txt文件可编辑提交
This commit is contained in:
parent
e7b9a1d7a9
commit
62cf72359a
@ -166,4 +166,23 @@ export function startSimpleNavi(params:any){
|
||||
method:'post',
|
||||
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 -->
|
||||
<template>
|
||||
<div class="editor-wrapper">
|
||||
<!-- 工具栏 -->
|
||||
<div v-if="editor" class="toolbar">
|
||||
<button @click="editor.chain().focus().toggleBold().run()"
|
||||
:class="{ 'is-active': editor.isActive('bold') }">
|
||||
<strong>B</strong>
|
||||
</button>
|
||||
<button @click="editor.chain().focus().toggleItalic().run()"
|
||||
:class="{ 'is-active': editor.isActive('italic') }">
|
||||
<em>I</em>
|
||||
</button>
|
||||
<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" />
|
||||
<div class="editor-wrapper" v-loading="txtloading" :class="{ 'fullscreen-editor': fullscreen }">
|
||||
<el-button @click="toggleFullscreen" circle class="fullscreen-btn">
|
||||
<el-icon v-if="!fullscreen">
|
||||
<FullScreen />
|
||||
</el-icon>
|
||||
<el-icon v-else>
|
||||
<Close />
|
||||
</el-icon>
|
||||
</el-button>
|
||||
<el-scrollbar :height="scrollHeight">
|
||||
<editor-content :editor="editor" class="editor-content" />
|
||||
</el-scrollbar>
|
||||
|
||||
|
||||
<!-- 操作按钮 -->
|
||||
<div class="actions">
|
||||
<button @click="loadContent" class="btn-load">加载文件</button>
|
||||
<button @click="saveContent" class="btn-save">保存文件</button>
|
||||
</div>
|
||||
|
||||
<!-- 状态提示 -->
|
||||
<div v-if="statusMessage" class="status">
|
||||
{{ statusMessage }}
|
||||
<el-button type="success" @click="saveCcontent">保存文件</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@ -38,11 +22,20 @@
|
||||
<script setup>
|
||||
import { EditorContent, useEditor } from '@tiptap/vue-3'
|
||||
import StarterKit from '@tiptap/starter-kit'
|
||||
import axios from 'axios'
|
||||
import { ref } from 'vue'
|
||||
|
||||
import { ref, onMounted, computed } 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('')
|
||||
|
||||
onMounted(() => {
|
||||
loadContent()
|
||||
});
|
||||
// 初始化编辑器
|
||||
const editor = useEditor({
|
||||
content: '',
|
||||
@ -54,35 +47,55 @@ const editor = useEditor({
|
||||
}),
|
||||
],
|
||||
})
|
||||
|
||||
const txtloading = ref(false)
|
||||
// 加载文件内容
|
||||
const loadContent = async () => {
|
||||
try {
|
||||
// const response = await axios.get('/api/files', {
|
||||
// params: { filePath: 'demo.txt' }
|
||||
// })
|
||||
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)
|
||||
const loadContent = () => {
|
||||
txtloading.value = true
|
||||
apicontent({ id: props.rowId }).then((res) => {
|
||||
editor.value.commands.setContent(convertNewlinesToParagraphs(res.data))
|
||||
txtloading.value = false
|
||||
// statusMessage.value = '内容加载成功'
|
||||
// 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 () => {
|
||||
try {
|
||||
const content = editor.value.getHTML()
|
||||
await axios.post('/api/files', {
|
||||
filePath: 'demo.txt',
|
||||
content: content
|
||||
})
|
||||
statusMessage.value = '保存成功'
|
||||
setTimeout(() => statusMessage.value = '', 2000)
|
||||
} catch (error) {
|
||||
statusMessage.value = `保存失败: ${error.response?.data || error.message}`
|
||||
}
|
||||
const saveCcontent = () => {
|
||||
const content = convertParagraphsToNewlines(editor.value.getHTML())
|
||||
saveContent({ id: props.rowId, content: content }).then((res) => {
|
||||
loadContent()
|
||||
ElMessage.success('保存成功')
|
||||
})
|
||||
}
|
||||
// 新增全屏状态
|
||||
const fullscreen = ref(false)
|
||||
const scrollHeight = computed(() => fullscreen.value ? 'calc(100vh - 60px)' : '600px')
|
||||
|
||||
// 全屏切换方法
|
||||
const toggleFullscreen = () => {
|
||||
fullscreen.value = !fullscreen.value
|
||||
nextTick(() => {
|
||||
if (fullscreen.value) {
|
||||
document.documentElement.style.overflow = 'hidden'
|
||||
} else {
|
||||
document.documentElement.style.overflow = ''
|
||||
}
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
@ -93,6 +106,7 @@ const saveContent = async () => {
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 8px;
|
||||
padding: 20px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.toolbar {
|
||||
@ -144,4 +158,36 @@ const saveContent = async () => {
|
||||
color: #666;
|
||||
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>
|
@ -146,7 +146,6 @@ const visibleChunks = computed(() => {
|
||||
console.log('No raw data available');
|
||||
return [];
|
||||
}
|
||||
|
||||
const start = hexContent.value.currentChunk * hexContent.value.chunkSize;
|
||||
const end = start + hexContent.value.chunkSize;
|
||||
const chunkData = hexContent.value.rawData.subarray(start, end);
|
||||
@ -678,7 +677,7 @@ html body {
|
||||
color: #333;
|
||||
|
||||
&::before {
|
||||
content: counter(line, decimal-leading-zero) ": ";
|
||||
// content: counter(line, decimal-leading-zero) ": ";
|
||||
color: #666;
|
||||
margin-right: 1em;
|
||||
}
|
||||
|
22
web/src/views/testdata/datamanagement/index.vue
vendored
22
web/src/views/testdata/datamanagement/index.vue
vendored
@ -591,12 +591,15 @@ const isViewfile = ref(false)
|
||||
const fileType = ref('')
|
||||
function openPreview(row: any) {
|
||||
// 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
|
||||
title1.value = row.fileName
|
||||
ViewfileUrl.value = row.url
|
||||
isViewfile.value = true
|
||||
fileType.value = getFileExtension(row.fileName)
|
||||
|
||||
}else if(getFileExtension(row.fileName) == 'txt'){
|
||||
testClick(row)
|
||||
} else {
|
||||
row.fileType = getFileType(row.fileName)
|
||||
filePreview.value = row
|
||||
@ -1196,8 +1199,8 @@ async function submitzip(formEl: any) {
|
||||
|
||||
})
|
||||
} else {
|
||||
// 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) => {
|
||||
// loading.value = true
|
||||
Decompression({ id: jiezip.value.id, parentId: zipParentid.value, decompressionPath:'/' + pathid.value + zipObj.value.compressedPath}).then((res: any) => {
|
||||
if (res.code == 0) {
|
||||
ElMessage.success('解压成功')
|
||||
// // gettreedata()
|
||||
@ -1230,7 +1233,7 @@ const jiepatharr: any = ref([])
|
||||
function gettsfiles() {
|
||||
filetsobj.value.nodeId = pathid.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) => {
|
||||
listFilesarr.value = res.data
|
||||
if (res.data[0]) {
|
||||
@ -1494,7 +1497,9 @@ function handleCustomEvent(row: any) {
|
||||
}
|
||||
//编辑文本设置
|
||||
const textedit = ref(false)
|
||||
const rowId = ref('')
|
||||
function testClick(row: any) {
|
||||
rowId.value = row.id
|
||||
textedit.value = true
|
||||
title.value = '编辑 - ' + row.workPath + row.fileName
|
||||
}
|
||||
@ -1605,8 +1610,8 @@ function textClose() {
|
||||
<template #default="scope">
|
||||
<span
|
||||
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)"
|
||||
style="cursor: pointer;">
|
||||
<!-- <img src="@/assets/project/chong.png" alt="" title="编辑文本" @click="testClick(scope.row)"
|
||||
style="cursor: pointer;"> -->
|
||||
<img src="@/assets/project/chong.png" alt="" title="重命名" @click="editfile(scope.row, false)"
|
||||
style="cursor: pointer;">
|
||||
<img v-if="scope.row.fileName.includes('ins_img')" src="@/assets/MenuIcon/guiji.png" alt=""
|
||||
@ -1932,10 +1937,9 @@ function textClose() {
|
||||
<AudioPlayer></AudioPlayer>
|
||||
<Viewfile v-if="isViewfile" :showTime="true" :title="title1" :url="ViewfileUrl" :type="fileType"
|
||||
@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>
|
||||
|
||||
<textEdit />
|
||||
<textEdit :rowId="rowId" />
|
||||
<!-- </el-scrollbar> -->
|
||||
</el-dialog>
|
||||
|
||||
|
@ -10,6 +10,8 @@ import { Search } from '@element-plus/icons-vue'
|
||||
import { ElMessageBox, ElMessage } from "element-plus";
|
||||
import { tstaskList, getTsNodesTree, tsFilesPage, deleteTsFilesByIds } from "@/api/datamanagement";
|
||||
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 useHeaderStorageList from "@/components/header/useHeaderStorageList";
|
||||
@ -576,11 +578,16 @@ const title1 = ref('')
|
||||
const isViewfile = ref(false)
|
||||
const fileType = ref('')
|
||||
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
|
||||
ViewfileUrl.value = row.url
|
||||
isViewfile.value = true
|
||||
fileType.value = getFileExtension(row.fileName)
|
||||
|
||||
} else if (getFileExtension(row.fileName) == 'txt') {
|
||||
testClick(row)
|
||||
} else {
|
||||
row.fileType = getFileType(row.fileName)
|
||||
filePreview.value = row
|
||||
@ -588,6 +595,17 @@ function openPreview(row: any) {
|
||||
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) {
|
||||
// 获取点号在文件名中的位置(从后往前查找)
|
||||
const lastIndex = filename.lastIndexOf('.');
|
||||
@ -891,6 +909,11 @@ function CloseView() {
|
||||
<AudioPlayer></AudioPlayer>
|
||||
<Viewfile v-if="isViewfile" :showTime="true" :title="title1" :url="ViewfileUrl" :type="fileType"
|
||||
@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>
|
||||
</section>
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user