txt文件可编辑提交
This commit is contained in:
parent
e7b9a1d7a9
commit
62cf72359a
@ -167,3 +167,22 @@ export function startSimpleNavi(params:any){
|
|||||||
params:params
|
params:params
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
//读取text文件
|
||||||
|
export function apicontent(params:any){
|
||||||
|
return request ({
|
||||||
|
url:'/experimentalData/ts-files/api/files/content',
|
||||||
|
method:'get',
|
||||||
|
params:params
|
||||||
|
})
|
||||||
|
}
|
||||||
|
//保存编辑的图片
|
||||||
|
export function saveContent(params:any){
|
||||||
|
return request ({
|
||||||
|
url:'/experimentalData/ts-files/save/files/content',
|
||||||
|
method:'post',
|
||||||
|
params:params,
|
||||||
|
// headers: {
|
||||||
|
// 'Content-Type': 'application/json' // 明确指定内容类型
|
||||||
|
// }
|
||||||
|
})
|
||||||
|
}
|
@ -1,36 +1,20 @@
|
|||||||
<!-- src/components/RichTextEditor.vue -->
|
<!-- src/components/RichTextEditor.vue -->
|
||||||
<template>
|
<template>
|
||||||
<div class="editor-wrapper">
|
<div class="editor-wrapper" v-loading="txtloading" :class="{ 'fullscreen-editor': fullscreen }">
|
||||||
<!-- 工具栏 -->
|
<el-button @click="toggleFullscreen" circle class="fullscreen-btn">
|
||||||
<div v-if="editor" class="toolbar">
|
<el-icon v-if="!fullscreen">
|
||||||
<button @click="editor.chain().focus().toggleBold().run()"
|
<FullScreen />
|
||||||
:class="{ 'is-active': editor.isActive('bold') }">
|
</el-icon>
|
||||||
<strong>B</strong>
|
<el-icon v-else>
|
||||||
</button>
|
<Close />
|
||||||
<button @click="editor.chain().focus().toggleItalic().run()"
|
</el-icon>
|
||||||
:class="{ 'is-active': editor.isActive('italic') }">
|
</el-button>
|
||||||
<em>I</em>
|
<el-scrollbar :height="scrollHeight">
|
||||||
</button>
|
<editor-content :editor="editor" class="editor-content" />
|
||||||
<button @click="editor.chain().focus().toggleHeading({ level: 2 }).run()"
|
|
||||||
:class="{ 'is-active': editor.isActive('heading') }">
|
|
||||||
H2
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<el-scrollbar height="600px">
|
|
||||||
<!-- 编辑器主体 -->
|
|
||||||
<editor-content :editor="editor" class="editor-content" />
|
|
||||||
</el-scrollbar>
|
</el-scrollbar>
|
||||||
|
|
||||||
|
|
||||||
<!-- 操作按钮 -->
|
|
||||||
<div class="actions">
|
<div class="actions">
|
||||||
<button @click="loadContent" class="btn-load">加载文件</button>
|
<el-button type="success" @click="saveCcontent">保存文件</el-button>
|
||||||
<button @click="saveContent" class="btn-save">保存文件</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 状态提示 -->
|
|
||||||
<div v-if="statusMessage" class="status">
|
|
||||||
{{ statusMessage }}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@ -38,11 +22,20 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { EditorContent, useEditor } from '@tiptap/vue-3'
|
import { EditorContent, useEditor } from '@tiptap/vue-3'
|
||||||
import StarterKit from '@tiptap/starter-kit'
|
import StarterKit from '@tiptap/starter-kit'
|
||||||
import axios from 'axios'
|
import { ref, onMounted, computed } from 'vue'
|
||||||
import { ref } from 'vue'
|
import { apicontent, saveContent } from "@/api/datamanagement";
|
||||||
|
import { ElMessage } from "element-plus";
|
||||||
|
import { FullScreen, Close } from '@element-plus/icons-vue'
|
||||||
|
const props = defineProps({
|
||||||
|
rowId: {
|
||||||
|
type: String,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
});
|
||||||
const statusMessage = ref('')
|
const statusMessage = ref('')
|
||||||
|
onMounted(() => {
|
||||||
|
loadContent()
|
||||||
|
});
|
||||||
// 初始化编辑器
|
// 初始化编辑器
|
||||||
const editor = useEditor({
|
const editor = useEditor({
|
||||||
content: '',
|
content: '',
|
||||||
@ -54,35 +47,55 @@ const editor = useEditor({
|
|||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
|
const txtloading = ref(false)
|
||||||
// 加载文件内容
|
// 加载文件内容
|
||||||
const loadContent = async () => {
|
const loadContent = () => {
|
||||||
try {
|
txtloading.value = true
|
||||||
// const response = await axios.get('/api/files', {
|
apicontent({ id: props.rowId }).then((res) => {
|
||||||
// params: { filePath: 'demo.txt' }
|
editor.value.commands.setContent(convertNewlinesToParagraphs(res.data))
|
||||||
// })
|
txtloading.value = false
|
||||||
const data = "<p>124535</p><p>4554</p><p>4545ljgljk</p><p><strong>lk'k;'k;'l;k'</strong></p><h2><strong><em>;l'kl;'kl;'</em></strong></h2><h2><strong><em>;'kl;';kl'kl;'l;k'k;l'k';lk';';k'l;'k;'kl;</em></strong></h2>"
|
|
||||||
editor.value.commands.setContent(data)
|
|
||||||
// statusMessage.value = '内容加载成功'
|
// statusMessage.value = '内容加载成功'
|
||||||
// setTimeout(() => statusMessage.value = '', 2000)
|
// setTimeout(() => statusMessage.value = '', 2000)
|
||||||
} catch (error) {
|
})
|
||||||
statusMessage.value = `加载失败: ${error.response?.data || error.message}`
|
}
|
||||||
}
|
function convertNewlinesToParagraphs(text) {
|
||||||
|
// 分割字符串并过滤空行
|
||||||
|
const paragraphs = text.split('\n').filter(line => line.trim() !== '');
|
||||||
|
|
||||||
|
// 用 <p> 标签包裹每行并拼接
|
||||||
|
return paragraphs.map(line => `<p>${line}</p>`).join('');
|
||||||
|
}
|
||||||
|
function convertParagraphsToNewlines(html) {
|
||||||
|
// 移除所有 <p> 标签并替换为换行符
|
||||||
|
return html.replace(/<\/?p>/g, '\n')
|
||||||
|
// 合并多个换行符为一个(可选)
|
||||||
|
.replace(/\n+/g, '\n')
|
||||||
|
// 移除首尾换行符(可选)
|
||||||
|
.trim();
|
||||||
}
|
}
|
||||||
|
|
||||||
// 保存文件内容
|
// 保存文件内容
|
||||||
const saveContent = async () => {
|
const saveCcontent = () => {
|
||||||
try {
|
const content = convertParagraphsToNewlines(editor.value.getHTML())
|
||||||
const content = editor.value.getHTML()
|
saveContent({ id: props.rowId, content: content }).then((res) => {
|
||||||
await axios.post('/api/files', {
|
loadContent()
|
||||||
filePath: 'demo.txt',
|
ElMessage.success('保存成功')
|
||||||
content: content
|
})
|
||||||
})
|
}
|
||||||
statusMessage.value = '保存成功'
|
// 新增全屏状态
|
||||||
setTimeout(() => statusMessage.value = '', 2000)
|
const fullscreen = ref(false)
|
||||||
} catch (error) {
|
const scrollHeight = computed(() => fullscreen.value ? 'calc(100vh - 60px)' : '600px')
|
||||||
statusMessage.value = `保存失败: ${error.response?.data || error.message}`
|
|
||||||
}
|
// 全屏切换方法
|
||||||
|
const toggleFullscreen = () => {
|
||||||
|
fullscreen.value = !fullscreen.value
|
||||||
|
nextTick(() => {
|
||||||
|
if (fullscreen.value) {
|
||||||
|
document.documentElement.style.overflow = 'hidden'
|
||||||
|
} else {
|
||||||
|
document.documentElement.style.overflow = ''
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@ -93,6 +106,7 @@ const saveContent = async () => {
|
|||||||
border: 1px solid #ddd;
|
border: 1px solid #ddd;
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
padding: 20px;
|
padding: 20px;
|
||||||
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|
||||||
.toolbar {
|
.toolbar {
|
||||||
@ -144,4 +158,36 @@ const saveContent = async () => {
|
|||||||
color: #666;
|
color: #666;
|
||||||
font-size: 0.9em;
|
font-size: 0.9em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.fullscreen-editor {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
z-index: 9999;
|
||||||
|
width: 100vw !important;
|
||||||
|
height: 100vh !important;
|
||||||
|
margin: 0 !important;
|
||||||
|
background: white;
|
||||||
|
border-radius: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fullscreen-editor .editor-content {
|
||||||
|
min-height: calc(100vh - 100px) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fullscreen-btn {
|
||||||
|
position: absolute;
|
||||||
|
right: 0px;
|
||||||
|
top: 0px;
|
||||||
|
z-index: 10000;
|
||||||
|
}
|
||||||
|
|
||||||
|
.actions {
|
||||||
|
position: sticky;
|
||||||
|
bottom: 0;
|
||||||
|
background: white;
|
||||||
|
padding: 10px;
|
||||||
|
border-top: 1px solid #eee;
|
||||||
|
z-index: 1000;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
@ -146,7 +146,6 @@ const visibleChunks = computed(() => {
|
|||||||
console.log('No raw data available');
|
console.log('No raw data available');
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
const start = hexContent.value.currentChunk * hexContent.value.chunkSize;
|
const start = hexContent.value.currentChunk * hexContent.value.chunkSize;
|
||||||
const end = start + hexContent.value.chunkSize;
|
const end = start + hexContent.value.chunkSize;
|
||||||
const chunkData = hexContent.value.rawData.subarray(start, end);
|
const chunkData = hexContent.value.rawData.subarray(start, end);
|
||||||
@ -678,7 +677,7 @@ html body {
|
|||||||
color: #333;
|
color: #333;
|
||||||
|
|
||||||
&::before {
|
&::before {
|
||||||
content: counter(line, decimal-leading-zero) ": ";
|
// content: counter(line, decimal-leading-zero) ": ";
|
||||||
color: #666;
|
color: #666;
|
||||||
margin-right: 1em;
|
margin-right: 1em;
|
||||||
}
|
}
|
||||||
|
18
web/src/views/testdata/datamanagement/index.vue
vendored
18
web/src/views/testdata/datamanagement/index.vue
vendored
@ -591,12 +591,15 @@ const isViewfile = ref(false)
|
|||||||
const fileType = ref('')
|
const fileType = ref('')
|
||||||
function openPreview(row: any) {
|
function openPreview(row: any) {
|
||||||
// debugger?
|
// debugger?
|
||||||
if (getFileExtension(row.fileName) == 'pdf' || getFileExtension(row.fileName) == 'pptx' || getFileExtension(row.fileName) == 'xlsx' || getFileExtension(row.fileName) == 'docx' || getFileExtension(row.fileName) == 'doc' || getFileExtension(row.fileName) == 'bin') {
|
if (getFileExtension(row.fileName) == 'pdf' || getFileExtension(row.fileName) == 'pptx' || getFileExtension(row.fileName) == 'xlsx' || getFileExtension(row.fileName) == 'xls' || getFileExtension(row.fileName) == 'docx' || getFileExtension(row.fileName) == 'doc' || getFileExtension(row.fileName) == 'bin') {
|
||||||
// debugger
|
// debugger
|
||||||
title1.value = row.fileName
|
title1.value = row.fileName
|
||||||
ViewfileUrl.value = row.url
|
ViewfileUrl.value = row.url
|
||||||
isViewfile.value = true
|
isViewfile.value = true
|
||||||
fileType.value = getFileExtension(row.fileName)
|
fileType.value = getFileExtension(row.fileName)
|
||||||
|
|
||||||
|
}else if(getFileExtension(row.fileName) == 'txt'){
|
||||||
|
testClick(row)
|
||||||
} else {
|
} else {
|
||||||
row.fileType = getFileType(row.fileName)
|
row.fileType = getFileType(row.fileName)
|
||||||
filePreview.value = row
|
filePreview.value = row
|
||||||
@ -1197,7 +1200,7 @@ async function submitzip(formEl: any) {
|
|||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
// loading.value = true
|
// loading.value = true
|
||||||
Decompression({ id: jiezip.value.id, parentId: zipParentid.value, decompressionPath: jieFilearr.value.workPath ? '/' + pathid.value + jieFilearr.value.workPath : '/' + pathid.value + filetsobj.value.path }).then((res: any) => {
|
Decompression({ id: jiezip.value.id, parentId: zipParentid.value, decompressionPath:'/' + pathid.value + zipObj.value.compressedPath}).then((res: any) => {
|
||||||
if (res.code == 0) {
|
if (res.code == 0) {
|
||||||
ElMessage.success('解压成功')
|
ElMessage.success('解压成功')
|
||||||
// // gettreedata()
|
// // gettreedata()
|
||||||
@ -1230,7 +1233,7 @@ const jiepatharr: any = ref([])
|
|||||||
function gettsfiles() {
|
function gettsfiles() {
|
||||||
filetsobj.value.nodeId = pathid.value
|
filetsobj.value.nodeId = pathid.value
|
||||||
filetsobj.value.taskId = projectId.value
|
filetsobj.value.taskId = projectId.value
|
||||||
// filetsobj.value.path ='/' + pathid.value + filetsobj.value.path
|
// filetsobj.value.path ='/' + pathid.value+filetsobj.value.path
|
||||||
listTsFiles(filetsobj.value).then((res: any) => {
|
listTsFiles(filetsobj.value).then((res: any) => {
|
||||||
listFilesarr.value = res.data
|
listFilesarr.value = res.data
|
||||||
if (res.data[0]) {
|
if (res.data[0]) {
|
||||||
@ -1494,7 +1497,9 @@ function handleCustomEvent(row: any) {
|
|||||||
}
|
}
|
||||||
//编辑文本设置
|
//编辑文本设置
|
||||||
const textedit = ref(false)
|
const textedit = ref(false)
|
||||||
|
const rowId = ref('')
|
||||||
function testClick(row: any) {
|
function testClick(row: any) {
|
||||||
|
rowId.value = row.id
|
||||||
textedit.value = true
|
textedit.value = true
|
||||||
title.value = '编辑 - ' + row.workPath + row.fileName
|
title.value = '编辑 - ' + row.workPath + row.fileName
|
||||||
}
|
}
|
||||||
@ -1605,8 +1610,8 @@ function textClose() {
|
|||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<span
|
<span
|
||||||
style="display: flex;display: -webkit-flex;justify-content: space-between;-webkit-justify-content: space-between; ">
|
style="display: flex;display: -webkit-flex;justify-content: space-between;-webkit-justify-content: space-between; ">
|
||||||
<img src="@/assets/project/chong.png" alt="" title="编辑文本" @click="testClick(scope.row)"
|
<!-- <img src="@/assets/project/chong.png" alt="" title="编辑文本" @click="testClick(scope.row)"
|
||||||
style="cursor: pointer;">
|
style="cursor: pointer;"> -->
|
||||||
<img src="@/assets/project/chong.png" alt="" title="重命名" @click="editfile(scope.row, false)"
|
<img src="@/assets/project/chong.png" alt="" title="重命名" @click="editfile(scope.row, false)"
|
||||||
style="cursor: pointer;">
|
style="cursor: pointer;">
|
||||||
<img v-if="scope.row.fileName.includes('ins_img')" src="@/assets/MenuIcon/guiji.png" alt=""
|
<img v-if="scope.row.fileName.includes('ins_img')" src="@/assets/MenuIcon/guiji.png" alt=""
|
||||||
@ -1934,8 +1939,7 @@ function textClose() {
|
|||||||
@update="CloseView" />
|
@update="CloseView" />
|
||||||
<el-dialog :title="title" v-model="textedit" :before-close="textClose" top="30px" draggable width="60%"
|
<el-dialog :title="title" v-model="textedit" :before-close="textClose" top="30px" draggable width="60%"
|
||||||
destroy-on-close>
|
destroy-on-close>
|
||||||
|
<textEdit :rowId="rowId" />
|
||||||
<textEdit />
|
|
||||||
<!-- </el-scrollbar> -->
|
<!-- </el-scrollbar> -->
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
|
|
||||||
|
@ -10,6 +10,8 @@ import { Search } from '@element-plus/icons-vue'
|
|||||||
import { ElMessageBox, ElMessage } from "element-plus";
|
import { ElMessageBox, ElMessage } from "element-plus";
|
||||||
import { tstaskList, getTsNodesTree, tsFilesPage, deleteTsFilesByIds } from "@/api/datamanagement";
|
import { tstaskList, getTsNodesTree, tsFilesPage, deleteTsFilesByIds } from "@/api/datamanagement";
|
||||||
import { listLocalAndBackup, compare, uploadToBackup, downloadToLocal, deleteTsFilesById } from "@/api/fileSynchronization";
|
import { listLocalAndBackup, compare, uploadToBackup, downloadToLocal, deleteTsFilesById } from "@/api/fileSynchronization";
|
||||||
|
//text文件编辑功能
|
||||||
|
import textEdit from '@/components/textEditing/index.vue'
|
||||||
// 文件预览相关
|
// 文件预览相关
|
||||||
import useFileUpload from "@/components/file/file/useFileUpload";
|
import useFileUpload from "@/components/file/file/useFileUpload";
|
||||||
import useHeaderStorageList from "@/components/header/useHeaderStorageList";
|
import useHeaderStorageList from "@/components/header/useHeaderStorageList";
|
||||||
@ -576,11 +578,16 @@ const title1 = ref('')
|
|||||||
const isViewfile = ref(false)
|
const isViewfile = ref(false)
|
||||||
const fileType = ref('')
|
const fileType = ref('')
|
||||||
function openPreview(row: any) {
|
function openPreview(row: any) {
|
||||||
if (getFileExtension(row.fileName) == 'pdf' || getFileExtension(row.fileName) == 'xlsx' || getFileExtension(row.fileName) == 'docx' || getFileExtension(row.fileName) == 'doc' || getFileExtension(row.fileName) == 'bin') {
|
// debugger
|
||||||
|
if (getFileExtension(row.fileName) == 'pdf' || getFileExtension(row.fileName) == 'pptx' || getFileExtension(row.fileName) == 'xlsx' || getFileExtension(row.fileName) == 'xls' || getFileExtension(row.fileName) == 'docx' || getFileExtension(row.fileName) == 'doc' || getFileExtension(row.fileName) == 'bin') {
|
||||||
|
// debugger
|
||||||
title1.value = row.fileName
|
title1.value = row.fileName
|
||||||
ViewfileUrl.value = row.url
|
ViewfileUrl.value = row.url
|
||||||
isViewfile.value = true
|
isViewfile.value = true
|
||||||
fileType.value = getFileExtension(row.fileName)
|
fileType.value = getFileExtension(row.fileName)
|
||||||
|
|
||||||
|
} else if (getFileExtension(row.fileName) == 'txt') {
|
||||||
|
testClick(row)
|
||||||
} else {
|
} else {
|
||||||
row.fileType = getFileType(row.fileName)
|
row.fileType = getFileType(row.fileName)
|
||||||
filePreview.value = row
|
filePreview.value = row
|
||||||
@ -588,6 +595,17 @@ function openPreview(row: any) {
|
|||||||
openRow(row)
|
openRow(row)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
const textedit = ref(false)
|
||||||
|
const rowId = ref('')
|
||||||
|
const title = ref('')
|
||||||
|
function testClick(row: any) {
|
||||||
|
rowId.value = row.id
|
||||||
|
textedit.value = true
|
||||||
|
title.value = '编辑 - ' + row.fileName
|
||||||
|
}
|
||||||
|
function textClose() {
|
||||||
|
textedit.value = false
|
||||||
|
}
|
||||||
function getFileExtension(filename: any) {
|
function getFileExtension(filename: any) {
|
||||||
// 获取点号在文件名中的位置(从后往前查找)
|
// 获取点号在文件名中的位置(从后往前查找)
|
||||||
const lastIndex = filename.lastIndexOf('.');
|
const lastIndex = filename.lastIndexOf('.');
|
||||||
@ -891,6 +909,11 @@ function CloseView() {
|
|||||||
<AudioPlayer></AudioPlayer>
|
<AudioPlayer></AudioPlayer>
|
||||||
<Viewfile v-if="isViewfile" :showTime="true" :title="title1" :url="ViewfileUrl" :type="fileType"
|
<Viewfile v-if="isViewfile" :showTime="true" :title="title1" :url="ViewfileUrl" :type="fileType"
|
||||||
@update="CloseView" />
|
@update="CloseView" />
|
||||||
|
<el-dialog :title="title" v-model="textedit" :before-close="textClose" top="30px" draggable width="60%"
|
||||||
|
destroy-on-close>
|
||||||
|
<textEdit :rowId="rowId" />
|
||||||
|
<!-- </el-scrollbar> -->
|
||||||
|
</el-dialog>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user