Compare commits
2 Commits
d9dae754c8
...
9eaf0490db
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9eaf0490db | ||
|
|
8c2993cdbd |
638
src/components/FilePreview/index.vue
Normal file
638
src/components/FilePreview/index.vue
Normal file
@ -0,0 +1,638 @@
|
|||||||
|
<template>
|
||||||
|
<el-dialog
|
||||||
|
:title="dialogTitle"
|
||||||
|
:visible.sync="visible"
|
||||||
|
:width="dialogWidth"
|
||||||
|
:fullscreen="isFullscreen"
|
||||||
|
append-to-body
|
||||||
|
@close="handleClose"
|
||||||
|
class="file-preview-dialog"
|
||||||
|
>
|
||||||
|
<!-- 工具栏 -->
|
||||||
|
<div class="preview-toolbar">
|
||||||
|
<el-button-group>
|
||||||
|
<el-button
|
||||||
|
size="mini"
|
||||||
|
icon="el-icon-circle-close"
|
||||||
|
@click="closePreview"
|
||||||
|
>
|
||||||
|
关闭
|
||||||
|
</el-button>
|
||||||
|
<el-button
|
||||||
|
size="mini"
|
||||||
|
:icon="isFullscreen ? 'el-icon-close' : 'el-icon-full-screen'"
|
||||||
|
@click="toggleFullscreen"
|
||||||
|
>
|
||||||
|
{{ isFullscreen ? '退出全屏' : '全屏' }}
|
||||||
|
</el-button>
|
||||||
|
<el-button
|
||||||
|
size="mini"
|
||||||
|
icon="el-icon-download"
|
||||||
|
@click="handleDownload"
|
||||||
|
v-if="selectFile.downloadable !== false"
|
||||||
|
>
|
||||||
|
下载
|
||||||
|
</el-button>
|
||||||
|
<el-button
|
||||||
|
size="mini"
|
||||||
|
icon="el-icon-refresh-left"
|
||||||
|
@click="handleRefresh"
|
||||||
|
v-if="showRefresh"
|
||||||
|
>
|
||||||
|
刷新
|
||||||
|
</el-button>
|
||||||
|
<!-- 新增:文件列表切换按钮 -->
|
||||||
|
<el-button
|
||||||
|
size="mini"
|
||||||
|
icon="el-icon-tickets"
|
||||||
|
@click="toggleFileList"
|
||||||
|
v-if="hasMultipleFiles"
|
||||||
|
>
|
||||||
|
{{ showFileList ? '隐藏列表' : '显示列表' }}
|
||||||
|
</el-button>
|
||||||
|
</el-button-group>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="preview-container" ref="previewContainer">
|
||||||
|
<!-- 左侧预览区域 -->
|
||||||
|
<div class="preview-content" :class="{ 'has-sidebar': showFileList && hasMultipleFiles }">
|
||||||
|
<!-- 加载状态 -->
|
||||||
|
<div v-if="loading" class="preview-loading">
|
||||||
|
<i class="el-icon-loading loading-icon"></i>
|
||||||
|
<div>加载中...</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 不支持预览的提示 -->
|
||||||
|
<div v-else-if="!supportedType" class="preview-unsupported">
|
||||||
|
<i class="el-icon-document unsupported-icon"></i>
|
||||||
|
<div>暂不支持预览该文件类型</div>
|
||||||
|
<el-button type="primary" @click="handleDownload" v-if="selectFile.downloadable !== false">
|
||||||
|
下载文件
|
||||||
|
</el-button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 各种文件类型的预览 -->
|
||||||
|
<template v-else>
|
||||||
|
<!-- 图片预览 -->
|
||||||
|
<image-preview
|
||||||
|
v-if="fileType === 'image'"
|
||||||
|
:src="fileUrl"
|
||||||
|
:preview-src-list="imagePreviewList"
|
||||||
|
class="preview-item"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<!-- 音频预览 -->
|
||||||
|
<audio
|
||||||
|
v-else-if="fileType === 'audio'"
|
||||||
|
:src="fileUrl"
|
||||||
|
controls
|
||||||
|
class="preview-item audio-player"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<!-- 视频预览 -->
|
||||||
|
<video
|
||||||
|
v-else-if="fileType === 'video'"
|
||||||
|
:src="fileUrl"
|
||||||
|
controls
|
||||||
|
class="preview-item video-player"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<!-- PDF预览 -->
|
||||||
|
<iframe
|
||||||
|
v-else-if="fileType === 'pdf'"
|
||||||
|
:src="pdfViewerUrl"
|
||||||
|
frameborder="0"
|
||||||
|
class="preview-item"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<!-- Office文档预览 -->
|
||||||
|
<iframe
|
||||||
|
v-else-if="fileType === 'office'"
|
||||||
|
:src="officeViewerUrl"
|
||||||
|
frameborder="0"
|
||||||
|
class="preview-item"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<!-- 文本文件预览 -->
|
||||||
|
<div
|
||||||
|
v-else-if="fileType === 'text'"
|
||||||
|
class="preview-item text-preview"
|
||||||
|
>
|
||||||
|
<pre v-if="textContent">{{ textContent }}</pre>
|
||||||
|
<div v-else class="text-loading">加载文本内容...</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 代码文件预览 -->
|
||||||
|
<div
|
||||||
|
v-else-if="fileType === 'code'"
|
||||||
|
class="preview-item code-preview"
|
||||||
|
>
|
||||||
|
<pre><code v-html="highlightedCode"></code></pre>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 默认iframe预览 -->
|
||||||
|
<iframe
|
||||||
|
v-else
|
||||||
|
:src="fileUrl"
|
||||||
|
frameborder="0"
|
||||||
|
class="preview-item"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 右侧文件列表 -->
|
||||||
|
<div class="file-sidebar" v-if="showFileList && hasMultipleFiles">
|
||||||
|
<div class="sidebar-header">
|
||||||
|
<span>文件列表 ({{ fileList.length }})</span>
|
||||||
|
<el-button
|
||||||
|
type="text"
|
||||||
|
icon="el-icon-close"
|
||||||
|
@click="showFileList = false"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="file-list">
|
||||||
|
<div
|
||||||
|
v-for="file in fileList"
|
||||||
|
:key="file.id || file.name"
|
||||||
|
:class="['file-item', { active: isActiveFile(file) }]"
|
||||||
|
@click="handleFileSelect(file)"
|
||||||
|
>
|
||||||
|
<i class="file-icon" :class="getFileIcon(file)"></i>
|
||||||
|
<span class="file-name" :title="file.fileName || file.name">
|
||||||
|
{{ file.fileName || file.name }}
|
||||||
|
</span>
|
||||||
|
<!-- 新增:选中标记 -->
|
||||||
|
<i v-if="isActiveFile(file)" class="el-icon-check active-checkmark"></i>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</el-dialog>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
// 文件类型映射
|
||||||
|
const FILE_TYPES = {
|
||||||
|
image: ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp', 'svg'],
|
||||||
|
audio: ['mp3', 'wav', 'ogg', 'aac', 'm4a', 'flac', 'wma'],
|
||||||
|
video: ['mp4', 'avi', 'mov', 'wmv', 'flv', 'webm', 'm3u8'],
|
||||||
|
pdf: ['pdf'],
|
||||||
|
office: ['doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx'],
|
||||||
|
text: ['txt', 'log', 'ini', 'conf'],
|
||||||
|
code: ['js', 'jsx', 'ts', 'tsx', 'vue', 'html', 'css', 'scss', 'java', 'py', 'php', 'json', 'xml']
|
||||||
|
}
|
||||||
|
|
||||||
|
// 文件图标映射
|
||||||
|
const FILE_ICONS = {
|
||||||
|
image: 'el-icon-picture',
|
||||||
|
audio: 'el-icon-headset',
|
||||||
|
video: 'el-icon-video-play',
|
||||||
|
pdf: 'el-icon-document-checked',
|
||||||
|
office: 'el-icon-document-checked',
|
||||||
|
text: 'el-icon-document',
|
||||||
|
code: 'el-icon-document',
|
||||||
|
default: 'el-icon-document'
|
||||||
|
}
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'FilePreview',
|
||||||
|
props: {
|
||||||
|
// 文件列表
|
||||||
|
fileList: {
|
||||||
|
type: Array,
|
||||||
|
default: () => []
|
||||||
|
},
|
||||||
|
// 文件基础URL
|
||||||
|
baseUrl: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
// 预览服务URL
|
||||||
|
previewUrl: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
// 文件服务URL
|
||||||
|
fileServiceUrl: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
// Office预览服务
|
||||||
|
officeViewer: {
|
||||||
|
type: String,
|
||||||
|
default: 'https://view.officeapps.live.com/op/view.aspx?src='
|
||||||
|
},
|
||||||
|
// PDF预览服务
|
||||||
|
pdfViewer: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
// 对话框宽度
|
||||||
|
width: {
|
||||||
|
type: String,
|
||||||
|
default: '80%'
|
||||||
|
},
|
||||||
|
// 是否显示文件列表
|
||||||
|
showFileListByDefault: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
// 自定义文件类型检测函数
|
||||||
|
customFileTypeDetector: {
|
||||||
|
type: Function,
|
||||||
|
default: null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
visible: false,
|
||||||
|
isFullscreen: false,
|
||||||
|
showFileList: this.showFileListByDefault,
|
||||||
|
loading: false,
|
||||||
|
selectFile: {},
|
||||||
|
textContent: '',
|
||||||
|
highlightedCode: ''
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
dialogTitle() {
|
||||||
|
return `文件预览(${this.selectFile.fileName || this.selectFile.name || ''})`
|
||||||
|
},
|
||||||
|
dialogWidth() {
|
||||||
|
return this.isFullscreen ? '100%' : this.width
|
||||||
|
},
|
||||||
|
fileType() {
|
||||||
|
if (this.customFileTypeDetector) {
|
||||||
|
return this.customFileTypeDetector(this.selectFile)
|
||||||
|
}
|
||||||
|
return this.detectFileType(this.selectFile)
|
||||||
|
},
|
||||||
|
supportedType() {
|
||||||
|
return this.fileType && this.fileType !== 'unsupported'
|
||||||
|
},
|
||||||
|
fileUrl() {
|
||||||
|
return this.getFileUrl(this.selectFile.filePath || this.selectFile.url)
|
||||||
|
},
|
||||||
|
officeViewerUrl() {
|
||||||
|
return this.officeViewer + encodeURIComponent(this.fileUrl)
|
||||||
|
},
|
||||||
|
pdfViewerUrl() {
|
||||||
|
if (this.pdfViewer) {
|
||||||
|
return this.pdfViewer + encodeURIComponent(this.fileUrl)
|
||||||
|
}
|
||||||
|
return this.fileUrl
|
||||||
|
},
|
||||||
|
imagePreviewList() {
|
||||||
|
return this.filteredFileList
|
||||||
|
.filter(file => this.detectFileType(file) === 'image')
|
||||||
|
.map(file => this.getFileUrl(file.filePath || file.url))
|
||||||
|
},
|
||||||
|
showRefresh() {
|
||||||
|
return ['office', 'pdf'].includes(this.fileType)
|
||||||
|
},
|
||||||
|
// 新增:判断是否有多个文件
|
||||||
|
hasMultipleFiles() {
|
||||||
|
return this.fileList && this.fileList.length > 1
|
||||||
|
},
|
||||||
|
// 新增:过滤后的文件列表
|
||||||
|
filteredFileList() {
|
||||||
|
return this.fileList || []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
// 打开预览
|
||||||
|
async openPreview(file, fileList = null) {
|
||||||
|
this.selectFile = { ...file }
|
||||||
|
|
||||||
|
// 如果有传入文件列表,更新组件文件列表
|
||||||
|
if (fileList) {
|
||||||
|
this.$emit('update:fileList', fileList)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 只有在有多个文件时才显示文件列表
|
||||||
|
this.showFileList = this.showFileListByDefault && this.hasMultipleFiles
|
||||||
|
this.visible = true
|
||||||
|
this.loading = true
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 如果是文本或代码文件,预加载内容
|
||||||
|
if (this.fileType === 'text' || this.fileType === 'code') {
|
||||||
|
await this.loadTextContent()
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('文件加载失败:', error)
|
||||||
|
} finally {
|
||||||
|
this.loading = false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// 关闭预览
|
||||||
|
closePreview() {
|
||||||
|
this.visible = false
|
||||||
|
this.isFullscreen = false
|
||||||
|
this.selectFile = {}
|
||||||
|
this.textContent = ''
|
||||||
|
this.highlightedCode = ''
|
||||||
|
},
|
||||||
|
|
||||||
|
// 检测文件类型
|
||||||
|
detectFileType(file) {
|
||||||
|
const fileName = file.fileName || file.name || ''
|
||||||
|
const filePath = file.filePath || file.url || ''
|
||||||
|
const extension = this.getFileExtension(fileName || filePath).toLowerCase()
|
||||||
|
|
||||||
|
for (const [type, extensions] of Object.entries(FILE_TYPES)) {
|
||||||
|
if (extensions.includes(extension)) {
|
||||||
|
return type
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 特殊处理:通过MIME类型检测
|
||||||
|
if (file.fileType) {
|
||||||
|
if (file.fileType.startsWith('image/')) return 'image'
|
||||||
|
if (file.fileType.startsWith('audio/')) return 'audio'
|
||||||
|
if (file.fileType.startsWith('video/')) return 'video'
|
||||||
|
if (file.fileType === 'application/pdf') return 'pdf'
|
||||||
|
}
|
||||||
|
|
||||||
|
return 'unsupported'
|
||||||
|
},
|
||||||
|
|
||||||
|
// 获取文件扩展名
|
||||||
|
getFileExtension(filename) {
|
||||||
|
return filename.slice((filename.lastIndexOf('.') - 1 >>> 0) + 2)
|
||||||
|
},
|
||||||
|
|
||||||
|
// 获取文件URL
|
||||||
|
getFileUrl(filePath) {
|
||||||
|
if (!filePath) return ''
|
||||||
|
|
||||||
|
// 已经是完整URL
|
||||||
|
if (filePath.includes('://')) {
|
||||||
|
return filePath
|
||||||
|
}
|
||||||
|
|
||||||
|
// 相对路径,拼接基础URL
|
||||||
|
const baseUrl = this.fileServiceUrl || this.baseUrl
|
||||||
|
if (baseUrl) {
|
||||||
|
return baseUrl + (filePath.startsWith('/') ? filePath : '/' + filePath)
|
||||||
|
}
|
||||||
|
|
||||||
|
return filePath
|
||||||
|
},
|
||||||
|
|
||||||
|
// 获取文件图标
|
||||||
|
getFileIcon(file) {
|
||||||
|
const fileType = this.detectFileType(file)
|
||||||
|
return FILE_ICONS[fileType] || FILE_ICONS.default
|
||||||
|
},
|
||||||
|
|
||||||
|
// 加载文本内容
|
||||||
|
async loadTextContent() {
|
||||||
|
try {
|
||||||
|
const response = await fetch(this.fileUrl)
|
||||||
|
this.textContent = await response.text()
|
||||||
|
|
||||||
|
// 如果是代码文件,进行语法高亮
|
||||||
|
if (this.fileType === 'code') {
|
||||||
|
this.highlightCode()
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('加载文本内容失败:', error)
|
||||||
|
this.textContent = '无法加载文件内容'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// 代码高亮(简单实现,实际项目中可以使用highlight.js等库)
|
||||||
|
highlightCode() {
|
||||||
|
// 这里可以集成 highlight.js 或其他语法高亮库
|
||||||
|
this.highlightedCode = this.escapeHtml(this.textContent)
|
||||||
|
},
|
||||||
|
|
||||||
|
// HTML转义
|
||||||
|
escapeHtml(text) {
|
||||||
|
const div = document.createElement('div')
|
||||||
|
div.textContent = text
|
||||||
|
return div.innerHTML
|
||||||
|
},
|
||||||
|
|
||||||
|
// 切换全屏
|
||||||
|
toggleFullscreen() {
|
||||||
|
this.isFullscreen = !this.isFullscreen
|
||||||
|
},
|
||||||
|
|
||||||
|
// 下载文件
|
||||||
|
handleDownload() {
|
||||||
|
const link = document.createElement('a')
|
||||||
|
link.href = this.fileUrl
|
||||||
|
link.download = this.selectFile.fileName || this.selectFile.name || 'download'
|
||||||
|
link.target = '_blank'
|
||||||
|
document.body.appendChild(link)
|
||||||
|
link.click()
|
||||||
|
document.body.removeChild(link)
|
||||||
|
},
|
||||||
|
|
||||||
|
// 刷新预览
|
||||||
|
handleRefresh() {
|
||||||
|
// 重新加载当前文件
|
||||||
|
this.openPreview(this.selectFile)
|
||||||
|
},
|
||||||
|
|
||||||
|
// 文件选择
|
||||||
|
handleFileSelect(file) {
|
||||||
|
if (this.isActiveFile(file)) return // 如果已经是当前文件,不重复加载
|
||||||
|
this.openPreview(file)
|
||||||
|
},
|
||||||
|
|
||||||
|
// 检查是否为当前活动文件
|
||||||
|
isActiveFile(file) {
|
||||||
|
if (file.id && this.selectFile.id) {
|
||||||
|
return file.id === this.selectFile.id
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果没有id,使用文件名和路径组合判断
|
||||||
|
const fileKey = `${file.fileName || file.name}-${file.filePath || file.url}`
|
||||||
|
const selectFileKey = `${this.selectFile.fileName || this.selectFile.name}-${this.selectFile.filePath || this.selectFile.url}`
|
||||||
|
|
||||||
|
return fileKey === selectFileKey
|
||||||
|
},
|
||||||
|
|
||||||
|
// 处理对话框关闭
|
||||||
|
handleClose() {
|
||||||
|
this.closePreview()
|
||||||
|
this.$emit('close')
|
||||||
|
},
|
||||||
|
|
||||||
|
// 新增:切换文件列表显示
|
||||||
|
toggleFileList() {
|
||||||
|
this.showFileList = !this.showFileList
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.file-preview-dialog {
|
||||||
|
:deep(.el-dialog__body) {
|
||||||
|
padding: 0;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.preview-toolbar {
|
||||||
|
position: absolute;
|
||||||
|
top: 10px;
|
||||||
|
right: 20px;
|
||||||
|
z-index: 1000;
|
||||||
|
background: rgba(255, 255, 255, 0.9);
|
||||||
|
padding: 8px;
|
||||||
|
border-radius: 4px;
|
||||||
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.preview-container {
|
||||||
|
display: flex;
|
||||||
|
height: 80vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
.preview-content {
|
||||||
|
flex: 1;
|
||||||
|
position: relative;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
|
||||||
|
&.has-sidebar {
|
||||||
|
flex: 0 0 75%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.preview-loading,
|
||||||
|
.preview-unsupported {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
height: 100%;
|
||||||
|
color: #909399;
|
||||||
|
}
|
||||||
|
|
||||||
|
.loading-icon,
|
||||||
|
.unsupported-icon {
|
||||||
|
font-size: 48px;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.preview-item {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.audio-player,
|
||||||
|
.video-player {
|
||||||
|
background: #000;
|
||||||
|
}
|
||||||
|
|
||||||
|
.text-preview,
|
||||||
|
.code-preview {
|
||||||
|
padding: 20px;
|
||||||
|
overflow: auto;
|
||||||
|
background: #f8f9fa;
|
||||||
|
font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
|
||||||
|
font-size: 14px;
|
||||||
|
line-height: 1.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.code-preview {
|
||||||
|
background: #1e1e1e;
|
||||||
|
color: #d4d4d4;
|
||||||
|
}
|
||||||
|
|
||||||
|
.file-sidebar {
|
||||||
|
flex: 0 0 25%;
|
||||||
|
border-left: 1px solid #e4e7ed;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
background: #fff;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar-header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
padding: 12px 16px;
|
||||||
|
border-bottom: 1px solid #e4e7ed;
|
||||||
|
font-weight: 500;
|
||||||
|
background: #f8f9fa;
|
||||||
|
}
|
||||||
|
|
||||||
|
.file-list {
|
||||||
|
flex: 1;
|
||||||
|
overflow-y: auto;
|
||||||
|
padding: 8px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.file-item {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
padding: 10px 16px;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
position: relative;
|
||||||
|
border-left: 3px solid transparent;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: #f5f7fa;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.active {
|
||||||
|
background-color: #ecf5ff;
|
||||||
|
color: #409eff;
|
||||||
|
border-left-color: #409eff;
|
||||||
|
|
||||||
|
.file-icon {
|
||||||
|
color: #409eff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.file-icon {
|
||||||
|
margin-right: 8px;
|
||||||
|
font-size: 16px;
|
||||||
|
color: #909399;
|
||||||
|
}
|
||||||
|
|
||||||
|
.file-name {
|
||||||
|
flex: 1;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
display: block; /* 保证文字显示 */
|
||||||
|
width: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 新增:选中标记样式 */
|
||||||
|
.active-checkmark {
|
||||||
|
color: #67c23a;
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: bold;
|
||||||
|
margin-left: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 响应式设计 */
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.preview-container {
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.file-sidebar {
|
||||||
|
flex: 0 0 200px;
|
||||||
|
border-left: none;
|
||||||
|
border-top: 1px solid #e4e7ed;
|
||||||
|
}
|
||||||
|
|
||||||
|
.preview-content.has-sidebar {
|
||||||
|
flex: 0 0 calc(100% - 200px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -3,18 +3,15 @@
|
|||||||
<!-- 搜索工作栏 -->
|
<!-- 搜索工作栏 -->
|
||||||
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
|
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
|
||||||
<el-form-item label="汇报主题" prop="reportTopic">
|
<el-form-item label="汇报主题" prop="reportTopic">
|
||||||
<el-input v-model="queryParams.reportTopic" placeholder="请输入汇报主题" clearable
|
<el-input v-model="queryParams.reportTopic" placeholder="请输入汇报主题" clearable @keyup.enter.native="handleQuery" />
|
||||||
@keyup.enter.native="handleQuery"/>
|
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="汇报时间" prop="reportTime">
|
<el-form-item label="汇报时间" prop="reportTime">
|
||||||
<el-date-picker v-model="queryParams.reportTime" style="width: 240px" value-format="yyyy-MM-dd HH:mm:ss"
|
<el-date-picker v-model="queryParams.reportTime" style="width: 240px" value-format="yyyy-MM-dd HH:mm:ss"
|
||||||
type="daterange"
|
type="daterange" range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期"
|
||||||
range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期"
|
:default-time="['00:00:00', '23:59:59']" />
|
||||||
:default-time="['00:00:00', '23:59:59']"/>
|
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="汇报人" prop="userId">
|
<el-form-item label="汇报人" prop="userId">
|
||||||
<el-input v-model="queryParams.userName" placeholder="请输入汇报人" clearable
|
<el-input v-model="queryParams.userName" placeholder="请输入汇报人" clearable @keyup.enter.native="handleQuery" />
|
||||||
@keyup.enter.native="handleQuery"/>
|
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item>
|
<el-form-item>
|
||||||
<el-button type="primary" icon="el-icon-search" @click="handleQuery">搜索</el-button>
|
<el-button type="primary" icon="el-icon-search" @click="handleQuery">搜索</el-button>
|
||||||
@ -30,29 +27,24 @@
|
|||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="1.5">
|
<el-col :span="1.5">
|
||||||
<el-button type="warning" plain icon="el-icon-download" size="mini" @click="handleExport"
|
<el-button type="warning" plain icon="el-icon-download" size="mini" @click="handleExport"
|
||||||
:loading="exportLoading">导出
|
:loading="exportLoading">导出
|
||||||
</el-button>
|
</el-button>
|
||||||
</el-col>
|
</el-col>
|
||||||
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
|
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
|
||||||
</el-row>
|
</el-row>
|
||||||
|
|
||||||
<el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true">
|
<el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true">
|
||||||
<el-table-column label="汇报主题" align="center" prop="reportTopic"/>
|
<el-table-column label="汇报主题" align="center" prop="reportTopic" />
|
||||||
<el-table-column label="汇报时间" align="center" prop="reportTime" width="180">
|
<el-table-column label="汇报时间" align="center" prop="reportTime" width="180">
|
||||||
<template v-slot="scope">
|
<template v-slot="scope">
|
||||||
<span>{{ parseTime(scope.row.reportTime) }}</span>
|
<span>{{ parseTime(scope.row.reportTime) }}</span>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column label="汇报内容" align="center" prop="reportContent" show-overflow-tooltip/>
|
<el-table-column label="汇报内容" align="center" prop="reportContent" show-overflow-tooltip />
|
||||||
<el-table-column label="汇报人" align="center" prop="userName"/>
|
<el-table-column label="汇报人" align="center" prop="userName" />
|
||||||
<el-table-column label="附件" align="center" width="100">
|
<el-table-column label="附件" align="center" width="100">
|
||||||
<template v-slot="scope">
|
<template v-slot="scope">
|
||||||
<el-button
|
<el-button v-if="scope.row.filePath" size="mini" type="text" @click="handleViewFiles(scope.row.filePath)">
|
||||||
v-if="scope.row.filePath"
|
|
||||||
size="mini"
|
|
||||||
type="text"
|
|
||||||
@click="handleViewFiles(scope.row.filePath)"
|
|
||||||
>
|
|
||||||
查看附件
|
查看附件
|
||||||
</el-button>
|
</el-button>
|
||||||
<span v-else>无附件</span>
|
<span v-else>无附件</span>
|
||||||
@ -60,7 +52,8 @@
|
|||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
|
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
|
||||||
<template v-slot="scope">
|
<template v-slot="scope">
|
||||||
<el-button size="mini" type="text" icon="el-icon-edit" @click="workReportView(scope.row.id)">查看<span style="font-weight: bold;font-size: 16px">|</span>打印
|
<el-button size="mini" type="text" icon="el-icon-edit" @click="workReportView(scope.row.id)">查看<span
|
||||||
|
style="font-weight: bold;font-size: 16px">|</span>打印
|
||||||
</el-button>
|
</el-button>
|
||||||
<el-button size="mini" type="text" icon="el-icon-edit" @click="openForm(scope.row.id)">修改
|
<el-button size="mini" type="text" icon="el-icon-edit" @click="openForm(scope.row.id)">修改
|
||||||
</el-button>
|
</el-button>
|
||||||
@ -70,49 +63,32 @@
|
|||||||
</el-table-column>
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
|
|
||||||
<el-dialog :title="'文件预览(' + currentFileName + ')'" :visible.sync="fileDialogVisible" width="70%"
|
<file-preview ref="filePreview" :file-list="currentFileList"/>
|
||||||
append-to-body>
|
|
||||||
|
<el-dialog :title="'文件预览(' + currentFileName + ')'" :visible.sync="fileDialogVisible" width="70%" append-to-body>
|
||||||
<div class="preview-container">
|
<div class="preview-container">
|
||||||
<!-- 左侧预览区域 -->
|
<!-- 左侧预览区域 -->
|
||||||
<!-- 音频文件 -->
|
<!-- 音频文件 -->
|
||||||
<audio v-if="isAudioType" class="preview-iframe" controls>
|
<audio v-if="isAudioType" class="preview-iframe" controls>
|
||||||
<source :src="currentFileUrl"/>
|
<source :src="currentFileUrl" />
|
||||||
</audio>
|
</audio>
|
||||||
|
|
||||||
<!-- Office文档/文本/PDF -->
|
<!-- Office文档/文本/PDF -->
|
||||||
<iframe
|
<iframe v-else-if="!isImageType && currentFileType !== 'txt' && !isAudioType && currentFileType !== 'pdf'"
|
||||||
v-else-if="!isImageType && currentFileType !== 'txt' && !isAudioType && currentFileType !== 'pdf'"
|
:src="officePreviewUrl" frameborder="0" class="preview-iframe"></iframe>
|
||||||
:src="officePreviewUrl"
|
|
||||||
frameborder="0"
|
|
||||||
class="preview-iframe"
|
|
||||||
></iframe>
|
|
||||||
|
|
||||||
<!-- 图片预览 -->
|
<!-- 图片预览 -->
|
||||||
<image-preview
|
<image-preview v-else-if="isImageType" class="preview-iframe" :src="currentFileUrl"></image-preview>
|
||||||
v-else-if="isImageType"
|
|
||||||
class="preview-iframe"
|
|
||||||
:src="currentFileUrl"
|
|
||||||
></image-preview>
|
|
||||||
|
|
||||||
<!-- PDF/文本 -->
|
<!-- PDF/文本 -->
|
||||||
<iframe
|
<iframe v-else-if="currentFileType === 'txt' || currentFileType === 'pdf'" :src="currentFileUrl" frameborder="0"
|
||||||
v-else-if="currentFileType === 'txt' || currentFileType === 'pdf'"
|
class="preview-iframe"></iframe>
|
||||||
:src="currentFileUrl"
|
|
||||||
frameborder="0"
|
|
||||||
class="preview-iframe"
|
|
||||||
></iframe>
|
|
||||||
|
|
||||||
<!-- 右侧文件列表 -->
|
<!-- 右侧文件列表 -->
|
||||||
<div class="file-list" v-if="currentFileList.length > 1">
|
<div class="file-list" v-if="currentFileList.length > 1">
|
||||||
<el-table
|
<el-table :data="currentFileList" height="100%" @row-click="handleFileClick"
|
||||||
:data="currentFileList"
|
|
||||||
height="100%"
|
|
||||||
@row-click="handleFileClick"
|
|
||||||
:row-class-name="getRowClassName">
|
:row-class-name="getRowClassName">
|
||||||
<el-table-column
|
<el-table-column prop="fileName" label="文件列表" min-width="180">
|
||||||
prop="fileName"
|
|
||||||
label="文件列表"
|
|
||||||
min-width="180">
|
|
||||||
<template #default="{ row }">
|
<template #default="{ row }">
|
||||||
<div class="file-item">
|
<div class="file-item">
|
||||||
<i :class="getFileIcon(row)"></i>
|
<i :class="getFileIcon(row)"></i>
|
||||||
@ -134,10 +110,10 @@
|
|||||||
|
|
||||||
<!-- 分页组件 -->
|
<!-- 分页组件 -->
|
||||||
<pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNo" :limit.sync="queryParams.pageSize"
|
<pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNo" :limit.sync="queryParams.pageSize"
|
||||||
@pagination="getList"/>
|
@pagination="getList" />
|
||||||
<!-- 对话框(添加 / 修改) -->
|
<!-- 对话框(添加 / 修改) -->
|
||||||
<ReportForm ref="formRef" :servicePackageId="queryParams.servicePackageId" :dictType="reportToDictType"
|
<ReportForm ref="formRef" :servicePackageId="queryParams.servicePackageId" :dictType="reportToDictType"
|
||||||
@success="getList"/>
|
@success="getList" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@ -145,7 +121,9 @@
|
|||||||
import * as ReportApi from '@/views/drivingSchool/workReport/api/index';
|
import * as ReportApi from '@/views/drivingSchool/workReport/api/index';
|
||||||
import ReportForm from './ReportForm.vue';
|
import ReportForm from './ReportForm.vue';
|
||||||
import print from 'vue-print-nb'
|
import print from 'vue-print-nb'
|
||||||
import {getLastPathSegment} from "@/utils/ruoyi";
|
import { getLastPathSegment } from "@/utils/ruoyi";
|
||||||
|
import FilePreview from '@/components/FilePreview/index.vue';
|
||||||
|
import { file } from 'jszip';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "Report",
|
name: "Report",
|
||||||
@ -154,6 +132,7 @@ export default {
|
|||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
ReportForm,
|
ReportForm,
|
||||||
|
FilePreview
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
@ -250,16 +229,16 @@ export default {
|
|||||||
/** 搜索按钮操作 */
|
/** 搜索按钮操作 */
|
||||||
handleQuery() {
|
handleQuery() {
|
||||||
const reportTime = this.queryParams.reportTime;
|
const reportTime = this.queryParams.reportTime;
|
||||||
this.queryParams = {
|
this.queryParams = {
|
||||||
pageNo: 1,
|
pageNo: 1,
|
||||||
pageSize: 10,
|
pageSize: 10,
|
||||||
reportTopic: null,
|
reportTopic: null,
|
||||||
reportTime: reportTime,
|
reportTime: reportTime,
|
||||||
createTime: [],
|
createTime: [],
|
||||||
userId: null,
|
userId: null,
|
||||||
userName: null,
|
userName: null,
|
||||||
servicePackageId: this.$route.query.servicePackageId,
|
servicePackageId: this.$route.query.servicePackageId,
|
||||||
dictType: this.$route.query.dictType,
|
dictType: this.$route.query.dictType,
|
||||||
}
|
}
|
||||||
this.queryParams.pageNo = 1;
|
this.queryParams.pageNo = 1;
|
||||||
this.getList();
|
this.getList();
|
||||||
@ -311,13 +290,26 @@ export default {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 初始化数据
|
// 初始化数据
|
||||||
this.currentFileList = filePath.split(',').filter(item => item.trim());
|
this.currentFileList = filePath.split(',')
|
||||||
this.fileDialogVisible = true;
|
.filter(item => item.trim()) // 去掉空格
|
||||||
|
.map(item => {
|
||||||
|
const parts = item.trim().split('/'); // 分割路径
|
||||||
|
const name = parts[parts.length - 1]; // 获取文件名
|
||||||
|
return {
|
||||||
|
url: item.trim(),
|
||||||
|
name: name
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
// this.fileDialogVisible = true;
|
||||||
|
|
||||||
|
// this.$refs.filePreview.openPreview(this.currentFileList[0],this.currentFileList)
|
||||||
|
this.$refs.filePreview.openPreview(this.currentFileList[0], this.currentFileList)
|
||||||
|
|
||||||
// 默认显示第一个文件
|
// 默认显示第一个文件
|
||||||
if (this.currentFileList.length > 0) {
|
// if (this.currentFileList.length > 0) {
|
||||||
this.previewFile(this.currentFileList[0]);
|
// this.previewFile(this.currentFileList[0]);
|
||||||
}
|
// }
|
||||||
},
|
},
|
||||||
|
|
||||||
// 获取完整文件URL(拼接基础API地址)
|
// 获取完整文件URL(拼接基础API地址)
|
||||||
@ -369,7 +361,7 @@ export default {
|
|||||||
},
|
},
|
||||||
|
|
||||||
// 表格行类名
|
// 表格行类名
|
||||||
getRowClassName({row}) {
|
getRowClassName({ row }) {
|
||||||
return row === this.currentFileUrl ? 'highlight-row' : '';
|
return row === this.currentFileUrl ? 'highlight-row' : '';
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -422,5 +414,4 @@ export default {
|
|||||||
.highlight-row {
|
.highlight-row {
|
||||||
background-color: #f0f7ff;
|
background-color: #f0f7ff;
|
||||||
}
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
<div>
|
<div>
|
||||||
<div style="display: flex; align-items: center;">
|
<div style="display: flex; align-items: center;">
|
||||||
<el-select v-model="carSelected" clearable style="width: 200px;">
|
<el-select v-model="carSelected" clearable style="width: 200px;">
|
||||||
<el-option v-for="car in carList" :key="car.id" :label="car.licenseNumber" :value="car.id"/>
|
<el-option v-for="car in carList" :key="car.id" :label="car.licenseNumber" :value="car.id" />
|
||||||
</el-select>
|
</el-select>
|
||||||
<el-button type="primary" size="small" @click="addNewCar" style="margin-left: 8px;">
|
<el-button type="primary" size="small" @click="addNewCar" style="margin-left: 8px;">
|
||||||
新增车辆
|
新增车辆
|
||||||
@ -14,7 +14,7 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
|
||||||
import {remindCarMainPage} from "@/api/base/carmain";
|
import { remindCarMainPage } from "@/api/base/carmain";
|
||||||
import AddCarForm from "./AddCarForm.vue";
|
import AddCarForm from "./AddCarForm.vue";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
@ -33,7 +33,7 @@ export default {
|
|||||||
type: Object,
|
type: Object,
|
||||||
required: true
|
required: true
|
||||||
},
|
},
|
||||||
inList:{
|
inList: {
|
||||||
type: Object,
|
type: Object,
|
||||||
default: null,
|
default: null,
|
||||||
required: false
|
required: false
|
||||||
@ -53,16 +53,19 @@ export default {
|
|||||||
value(val) {
|
value(val) {
|
||||||
this.carSelected = val ? val.id : null;
|
this.carSelected = val ? val.id : null;
|
||||||
},
|
},
|
||||||
cusName(val, old) {
|
cusName: {
|
||||||
if (val !== old) {
|
handler(val, old) {
|
||||||
// this.carSelected = null
|
if (val !== old) {
|
||||||
this.getCarList()
|
// this.carSelected = null
|
||||||
}
|
this.getCarList()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
immediate: true
|
||||||
},
|
},
|
||||||
inList(val){
|
inList(val) {
|
||||||
if (val){
|
if (val) {
|
||||||
const flag = this.carList.findIndex(item => item.id === val.id)
|
const flag = this.carList.findIndex(item => item.id === val.id)
|
||||||
if (flag > 0){
|
if (flag > 0) {
|
||||||
this.carList.splice(flag, 1)
|
this.carList.splice(flag, 1)
|
||||||
}
|
}
|
||||||
this.carList.unshift(val)
|
this.carList.unshift(val)
|
||||||
@ -108,6 +111,4 @@ export default {
|
|||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss"></style>
|
||||||
|
|
||||||
</style>
|
|
||||||
|
|||||||
@ -483,7 +483,7 @@ export default {
|
|||||||
soiType: this.type ? '02' : "04",
|
soiType: this.type ? '02' : "04",
|
||||||
goodsId: item.waresId,
|
goodsId: item.waresId,
|
||||||
goodsCount: item.waresCount,
|
goodsCount: item.waresCount,
|
||||||
goodsPrice: item.salePrice
|
goodsPrice: item.salePrice,
|
||||||
}
|
}
|
||||||
})]
|
})]
|
||||||
this.formData.ids = this.allSelectRows.map(item => item.id)
|
this.formData.ids = this.allSelectRows.map(item => item.id)
|
||||||
|
|||||||
@ -413,7 +413,7 @@
|
|||||||
<!-- <th>单位</th> -->
|
<!-- <th>单位</th> -->
|
||||||
<th style="width: 9%">数量</th>
|
<th style="width: 9%">数量</th>
|
||||||
<th style="width: 9%">单价</th>
|
<th style="width: 9%">单价</th>
|
||||||
<th style="width: 9%">折扣</th>
|
<!-- <th style="width: 9%">折扣</th> -->
|
||||||
<!-- <th v-if="checkPermi(['repair:tick:profit'])">毛利</th>
|
<!-- <th v-if="checkPermi(['repair:tick:profit'])">毛利</th>
|
||||||
<th v-if="checkPermi(['repair:tick:profit'])">毛利率</th> -->
|
<th v-if="checkPermi(['repair:tick:profit'])">毛利率</th> -->
|
||||||
<th style="width: 8%">金额</th>
|
<th style="width: 8%">金额</th>
|
||||||
@ -438,7 +438,7 @@
|
|||||||
</td> -->
|
</td> -->
|
||||||
<td>{{ item.itemCount }}</td>
|
<td>{{ item.itemCount }}</td>
|
||||||
<td>{{ item.itemPrice }}</td>
|
<td>{{ item.itemPrice }}</td>
|
||||||
<td>{{ item.itemDiscount }}</td>
|
<!-- <td>{{ item.itemDiscount }}</td> -->
|
||||||
<!-- <td v-if="checkPermi(['repair:tick:profit'])">
|
<!-- <td v-if="checkPermi(['repair:tick:profit'])">
|
||||||
{{ item.itemProfit }}
|
{{ item.itemProfit }}
|
||||||
</td>
|
</td>
|
||||||
@ -479,13 +479,13 @@
|
|||||||
<th style="width: 12%">单位</th>
|
<th style="width: 12%">单位</th>
|
||||||
<th style="width: 12%">数量</th>
|
<th style="width: 12%">数量</th>
|
||||||
<th style="width: 12%">单价</th>
|
<th style="width: 12%">单价</th>
|
||||||
<th style="width: 12%">折扣</th>
|
<!-- <th style="width: 12%">折扣</th> -->
|
||||||
<th v-if="checkPermi(['repair:tick:profit'])">毛利</th>
|
<!-- <th v-if="checkPermi(['repair:tick:profit'])">毛利</th> -->
|
||||||
<th v-if="checkPermi(['repair:tick:profit'])">毛利率</th>
|
<!-- <th v-if="checkPermi(['repair:tick:profit'])">毛利率</th> -->
|
||||||
<th style="width: 12%">金额</th>
|
<th style="width: 12%">金额</th>
|
||||||
<th style="width: 12%">施工人员</th>
|
<th style="width: 12%">施工人员</th>
|
||||||
<th style="width: 12%">服务顾问</th>
|
<th style="width: 12%">服务顾问</th>
|
||||||
<th>备注</th>
|
<!-- <th>备注</th> -->
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
@ -501,8 +501,8 @@
|
|||||||
</td>
|
</td>
|
||||||
<td>{{ item.itemCount }}</td>
|
<td>{{ item.itemCount }}</td>
|
||||||
<td>{{ item.itemPrice }}</td>
|
<td>{{ item.itemPrice }}</td>
|
||||||
<td>{{ item.itemDiscount }}</td>
|
<!-- <td>{{ item.itemDiscount }}</td> -->
|
||||||
<td v-if="checkPermi(['repair:tick:profit'])">
|
<!-- <td v-if="checkPermi(['repair:tick:profit'])">
|
||||||
{{ item.itemProfit }}
|
{{ item.itemProfit }}
|
||||||
</td>
|
</td>
|
||||||
<td v-if="checkPermi(['repair:tick:profit'])">
|
<td v-if="checkPermi(['repair:tick:profit'])">
|
||||||
@ -511,11 +511,11 @@
|
|||||||
? (item.itemProfitRate * 100).toFixed(2) + "%"
|
? (item.itemProfitRate * 100).toFixed(2) + "%"
|
||||||
: ""
|
: ""
|
||||||
}}
|
}}
|
||||||
</td>
|
</td> -->
|
||||||
<td style="width: 12%">{{ item.itemMoney }}</td>
|
<td style="width: 12%">{{ item.itemMoney }}</td>
|
||||||
<td style="width: 12%">{{ item.repairNames }}</td>
|
<td style="width: 12%">{{ item.repairNames }}</td>
|
||||||
<td style="width: 12%">{{ item.saleName }}</td>
|
<td style="width: 12%">{{ item.saleName }}</td>
|
||||||
<td>{{ item.remark }}</td>
|
<!-- <td>{{ item.remark }}</td> -->
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
@ -542,13 +542,13 @@
|
|||||||
<th>单位</th>
|
<th>单位</th>
|
||||||
<th>数量</th>
|
<th>数量</th>
|
||||||
<th>单价</th>
|
<th>单价</th>
|
||||||
<th>折扣</th>
|
<!-- <th>折扣</th> -->
|
||||||
<th v-if="checkPermi(['repair:tick:profit'])">毛利</th>
|
<!-- <th v-if="checkPermi(['repair:tick:profit'])">毛利</th>
|
||||||
<th v-if="checkPermi(['repair:tick:profit'])">毛利率</th>
|
<th v-if="checkPermi(['repair:tick:profit'])">毛利率</th> -->
|
||||||
<th style="width: 12%">金额</th>
|
<th style="width: 12%">金额</th>
|
||||||
<th style="width: 12%">施工人员</th>
|
<th style="width: 12%">施工人员</th>
|
||||||
<th style="width: 12%">服务顾问</th>
|
<th style="width: 12%">服务顾问</th>
|
||||||
<th>备注</th>
|
<!-- <th>备注</th> -->
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
@ -564,8 +564,8 @@
|
|||||||
</td>
|
</td>
|
||||||
<td>{{ item.itemCount }}</td>
|
<td>{{ item.itemCount }}</td>
|
||||||
<td>{{ item.itemPrice }}</td>
|
<td>{{ item.itemPrice }}</td>
|
||||||
<td>{{ item.itemDiscount }}</td>
|
<!-- <td>{{ item.itemDiscount }}</td> -->
|
||||||
<td v-if="checkPermi(['repair:tick:profit'])">
|
<!-- <td v-if="checkPermi(['repair:tick:profit'])">
|
||||||
{{ item.itemProfit }}
|
{{ item.itemProfit }}
|
||||||
</td>
|
</td>
|
||||||
<td v-if="checkPermi(['repair:tick:profit'])">
|
<td v-if="checkPermi(['repair:tick:profit'])">
|
||||||
@ -574,11 +574,11 @@
|
|||||||
? (item.itemProfitRate * 100).toFixed(2) + "%"
|
? (item.itemProfitRate * 100).toFixed(2) + "%"
|
||||||
: ""
|
: ""
|
||||||
}}
|
}}
|
||||||
</td>
|
</td> -->
|
||||||
<td style="width: 12%">{{ item.itemMoney }}</td>
|
<td style="width: 12%">{{ item.itemMoney }}</td>
|
||||||
<td style="width: 12%">{{ item.repairNames }}</td>
|
<td style="width: 12%">{{ item.repairNames }}</td>
|
||||||
<td style="width: 12%">{{ item.saleName }}</td>
|
<td style="width: 12%">{{ item.saleName }}</td>
|
||||||
<td>{{ item.remark }}</td>
|
<!-- <td>{{ item.remark }}</td> -->
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
@ -599,14 +599,14 @@
|
|||||||
<tr>
|
<tr>
|
||||||
<td><strong>总数量</strong></td>
|
<td><strong>总数量</strong></td>
|
||||||
<td>{{ totalCount }}</td>
|
<td>{{ totalCount }}</td>
|
||||||
<td><strong>成本</strong></td>
|
<!-- <td><strong>成本</strong></td>
|
||||||
<td>{{ otherInfo.cost }}</td>
|
<td>{{ otherInfo.cost }}</td> -->
|
||||||
<td><strong>总金额</strong></td>
|
<td><strong>总金额</strong></td>
|
||||||
<td>{{ totalMoney }}</td>
|
<td>{{ totalMoney }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
<div v-if="checkPermi(['repair:tick:profit'])">
|
<!-- <div v-if="checkPermi(['repair:tick:profit'])">
|
||||||
<table
|
<table
|
||||||
class="print-table"
|
class="print-table"
|
||||||
border="1"
|
border="1"
|
||||||
@ -669,7 +669,7 @@
|
|||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div> -->
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</PrintButton>
|
</PrintButton>
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user