日常修复内容
This commit is contained in:
@@ -1,80 +1,80 @@
|
||||
<template>
|
||||
<div class="interface-image-container">
|
||||
<a-modal
|
||||
v-model:visible="visible"
|
||||
width="50%"
|
||||
draggable
|
||||
:on-before-ok="handleSyncOk"
|
||||
unmount-on-close
|
||||
ok-text="确认保存"
|
||||
cancel-text="关闭不保存"
|
||||
:maskClosable="false"
|
||||
@close="handleOnClose"
|
||||
>
|
||||
<template #title>软件接口图</template>
|
||||
<div class="flex justify-center items-center">
|
||||
<ImageInput v-model="imageUrl" v-model:fontnote="fontnote" />
|
||||
</div>
|
||||
</a-modal>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, getCurrentInstance } from "vue"
|
||||
import ImageInput from "./projectModal/ImageInput/index.vue"
|
||||
import { Message } from "@arco-design/web-vue"
|
||||
import projectApi from "@/api/project/project"
|
||||
import { useRoute } from "vue-router"
|
||||
|
||||
const { proxy } = getCurrentInstance() as any
|
||||
const route = useRoute()
|
||||
const visible = ref(false)
|
||||
|
||||
// props
|
||||
const { reset } = defineProps<{
|
||||
reset: () => void
|
||||
}>()
|
||||
|
||||
// 题注和图片数据
|
||||
const fontnote = ref("")
|
||||
const imageUrl = ref("")
|
||||
|
||||
const handleSyncOk = async () => {
|
||||
// 验证题注是否为空
|
||||
if (fontnote.value.trim().length <= 0 || !imageUrl.value.trim()) {
|
||||
Message.error("请输入题注和粘贴图片")
|
||||
return false
|
||||
}
|
||||
// 提交数据
|
||||
try {
|
||||
await projectApi.postInterfaceImage(route.query.id, { fontnote: fontnote.value, content: imageUrl.value, type: "image" })
|
||||
Message.success("保存成功")
|
||||
} catch (e) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
const handleOnClose = () => {
|
||||
// 用来清空数据
|
||||
fontnote.value = ""
|
||||
imageUrl.value = ""
|
||||
reset()
|
||||
}
|
||||
|
||||
const open = async () => {
|
||||
proxy?.$loading?.show("数据加载中...")
|
||||
try {
|
||||
const { data } = await projectApi.getInterfaceImage(route.query.id)
|
||||
fontnote.value = data.fontnote
|
||||
imageUrl.value = data.content
|
||||
visible.value = true
|
||||
} catch (e) {
|
||||
} finally {
|
||||
proxy?.$loading?.hide()
|
||||
}
|
||||
}
|
||||
|
||||
defineExpose({ open })
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
<template>
|
||||
<div class="interface-image-container">
|
||||
<a-modal
|
||||
v-model:visible="visible"
|
||||
width="50%"
|
||||
draggable
|
||||
:on-before-ok="handleSyncOk"
|
||||
unmount-on-close
|
||||
ok-text="确认保存"
|
||||
cancel-text="关闭不保存"
|
||||
:maskClosable="false"
|
||||
@close="handleOnClose"
|
||||
>
|
||||
<template #title>软件接口图</template>
|
||||
<div class="flex justify-center items-center">
|
||||
<ImageInput v-model="imageUrl" v-model:fontnote="fontnote" />
|
||||
</div>
|
||||
</a-modal>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, getCurrentInstance } from "vue"
|
||||
import ImageInput from "./projectModal/ImageInput/index.vue"
|
||||
import { Message } from "@arco-design/web-vue"
|
||||
import projectApi from "@/api/project/project"
|
||||
import { useRoute } from "vue-router"
|
||||
|
||||
const { proxy } = getCurrentInstance() as any
|
||||
const route = useRoute()
|
||||
const visible = ref(false)
|
||||
|
||||
// props
|
||||
const { reset } = defineProps<{
|
||||
reset: () => void
|
||||
}>()
|
||||
|
||||
// 题注和图片数据
|
||||
const fontnote = ref("")
|
||||
const imageUrl = ref("")
|
||||
|
||||
const handleSyncOk = async () => {
|
||||
// 验证题注是否为空
|
||||
if (fontnote.value?.trim().length <= 0 || !imageUrl.value?.trim()) {
|
||||
Message.error("请输入题注和粘贴图片")
|
||||
return false
|
||||
}
|
||||
// 提交数据
|
||||
try {
|
||||
await projectApi.postInterfaceImage(route.query.id, { fontnote: fontnote.value, content: imageUrl.value, type: "image" })
|
||||
Message.success("保存成功")
|
||||
} catch (e) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
const handleOnClose = () => {
|
||||
// 用来清空数据
|
||||
fontnote.value = ""
|
||||
imageUrl.value = ""
|
||||
reset()
|
||||
}
|
||||
|
||||
const open = async () => {
|
||||
proxy?.$loading?.show("数据加载中...")
|
||||
try {
|
||||
const { data } = await projectApi.getInterfaceImage(route.query.id)
|
||||
fontnote.value = data.fontnote || ""
|
||||
imageUrl.value = data.content || ""
|
||||
visible.value = true
|
||||
} catch (e) {
|
||||
} finally {
|
||||
proxy?.$loading?.hide()
|
||||
}
|
||||
}
|
||||
|
||||
defineExpose({ open })
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
|
||||
@@ -1,95 +1,95 @@
|
||||
<template>
|
||||
<div class="static-dynamic-table-container">
|
||||
<a-modal
|
||||
v-model:visible="visible"
|
||||
width="50%"
|
||||
draggable
|
||||
:on-before-ok="handleSyncOk"
|
||||
unmount-on-close
|
||||
ok-text="确认保存"
|
||||
cancel-text="关闭不保存"
|
||||
:maskClosable="false"
|
||||
@close="handleOnClose"
|
||||
>
|
||||
<template #title>{{ theTitle }}</template>
|
||||
<WordLikeTable v-model="tableData" v-model:fontnote="fontnote" />
|
||||
</a-modal>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { Message } from "@arco-design/web-vue"
|
||||
import { getCurrentInstance, ref } from "vue"
|
||||
import WordLikeTable from "./projectModal/wordLikeTable/index.vue"
|
||||
import { useRoute } from "vue-router"
|
||||
import { cloneDeep } from "lodash-es"
|
||||
import projectApi from "@/api/project/project"
|
||||
|
||||
const { proxy } = getCurrentInstance() as any
|
||||
const route = useRoute()
|
||||
|
||||
// props
|
||||
const { reset } = defineProps<{
|
||||
reset: () => void
|
||||
}>()
|
||||
|
||||
const visible = ref(false)
|
||||
const theTitle = ref("")
|
||||
|
||||
const tableInitValue = [
|
||||
["", "", ""],
|
||||
["", "", ""],
|
||||
["", "", ""]
|
||||
]
|
||||
const tableData = ref(tableInitValue)
|
||||
const fontnote = ref("")
|
||||
|
||||
const handleSyncOk = async () => {
|
||||
// 验证题注是否为空
|
||||
if (tableData.value.length <= 0) {
|
||||
Message.error("请输入表格内容再提交")
|
||||
return false
|
||||
}
|
||||
try {
|
||||
// 请求接口
|
||||
await projectApi.postStaticDynamicItems({
|
||||
id: route.query.id,
|
||||
category: theTitle.value,
|
||||
table: tableData.value,
|
||||
fontnote: fontnote.value
|
||||
})
|
||||
Message.success("保存成功")
|
||||
} catch (e) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
const handleOnClose = () => {
|
||||
// 用来清空数据
|
||||
tableData.value = cloneDeep(tableInitValue)
|
||||
fontnote.value = ""
|
||||
reset()
|
||||
}
|
||||
|
||||
const open = async (title: string) => {
|
||||
proxy?.$loading?.show("数据加载中...")
|
||||
theTitle.value = title
|
||||
try {
|
||||
// 获取数据并赋值给tableData
|
||||
const res = await projectApi.getStaticDynamicItems(route.query.id, title)
|
||||
if (res.code === 25001) {
|
||||
const data = res.data
|
||||
tableData.value = data.table
|
||||
fontnote.value = data.fontnote
|
||||
}
|
||||
visible.value = true
|
||||
} catch (e) {
|
||||
} finally {
|
||||
proxy?.$loading?.hide()
|
||||
}
|
||||
}
|
||||
|
||||
defineExpose({ open })
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
<template>
|
||||
<div class="static-dynamic-table-container">
|
||||
<a-modal
|
||||
v-model:visible="visible"
|
||||
width="50%"
|
||||
draggable
|
||||
:on-before-ok="handleSyncOk"
|
||||
unmount-on-close
|
||||
ok-text="确认保存"
|
||||
cancel-text="关闭不保存"
|
||||
:maskClosable="false"
|
||||
@close="handleOnClose"
|
||||
>
|
||||
<template #title>{{ theTitle }}</template>
|
||||
<WordLikeTable v-model="tableData" v-model:fontnote="fontnote" />
|
||||
</a-modal>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { Message } from "@arco-design/web-vue"
|
||||
import { getCurrentInstance, ref } from "vue"
|
||||
import WordLikeTable from "./projectModal/wordLikeTable/index.vue"
|
||||
import { useRoute } from "vue-router"
|
||||
import { cloneDeep } from "lodash-es"
|
||||
import projectApi from "@/api/project/project"
|
||||
|
||||
const { proxy } = getCurrentInstance() as any
|
||||
const route = useRoute()
|
||||
|
||||
// props
|
||||
const { reset } = defineProps<{
|
||||
reset: () => void
|
||||
}>()
|
||||
|
||||
const visible = ref(false)
|
||||
const theTitle = ref("")
|
||||
|
||||
const tableInitValue = [
|
||||
["", "", ""],
|
||||
["", "", ""],
|
||||
["", "", ""]
|
||||
]
|
||||
const tableData = ref(tableInitValue)
|
||||
const fontnote = ref("")
|
||||
|
||||
const handleSyncOk = async () => {
|
||||
// 验证题注是否为空
|
||||
if (tableData.value?.length <= 0) {
|
||||
Message.error("请输入表格内容再提交")
|
||||
return false
|
||||
}
|
||||
try {
|
||||
// 请求接口
|
||||
await projectApi.postStaticDynamicItems({
|
||||
id: route.query.id,
|
||||
category: theTitle.value,
|
||||
table: tableData.value,
|
||||
fontnote: fontnote.value
|
||||
})
|
||||
Message.success("保存成功")
|
||||
} catch (e) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
const handleOnClose = () => {
|
||||
// 用来清空数据
|
||||
tableData.value = cloneDeep(tableInitValue)
|
||||
fontnote.value = ""
|
||||
reset()
|
||||
}
|
||||
|
||||
const open = async (title: string) => {
|
||||
proxy?.$loading?.show("数据加载中...")
|
||||
theTitle.value = title
|
||||
try {
|
||||
// 获取数据并赋值给tableData
|
||||
const res = await projectApi.getStaticDynamicItems(route.query.id, title)
|
||||
if (res.code === 25001) {
|
||||
const data = res.data
|
||||
tableData.value = data.table
|
||||
fontnote.value = data.fontnote || ""
|
||||
}
|
||||
visible.value = true
|
||||
} catch (e) {
|
||||
} finally {
|
||||
proxy?.$loading?.hide()
|
||||
}
|
||||
}
|
||||
|
||||
defineExpose({ open })
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
|
||||
@@ -1,107 +1,107 @@
|
||||
<template>
|
||||
<div class="text-table-container">
|
||||
<a-modal
|
||||
v-model:visible="visible"
|
||||
width="50%"
|
||||
draggable
|
||||
:on-before-ok="handleSyncOk"
|
||||
unmount-on-close
|
||||
ok-text="确认保存"
|
||||
cancel-text="关闭不保存"
|
||||
:maskClosable="false"
|
||||
@close="handleOnClose"
|
||||
>
|
||||
<template #title>{{ theTitle }}</template>
|
||||
<a-space direction="vertical" fill>
|
||||
<a-card title="差异性段落描述" hoverable>
|
||||
<a-textarea auto-size placeholder="请填写差异性分析和'见下表所示'" v-model="description"></a-textarea>
|
||||
</a-card>
|
||||
<a-card title="表格" hoverable>
|
||||
<WordLikeTable v-model="tableDatas" v-model:fontnote="fontnote" />
|
||||
</a-card>
|
||||
</a-space>
|
||||
</a-modal>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { Message } from "@arco-design/web-vue"
|
||||
import { getCurrentInstance, ref } from "vue"
|
||||
import { useRoute } from "vue-router"
|
||||
import WordLikeTable from "./projectModal/wordLikeTable/index.vue"
|
||||
import { cloneDeep } from "lodash-es"
|
||||
import projectApi from "@/api/project/project"
|
||||
|
||||
const { proxy } = getCurrentInstance() as any
|
||||
const route = useRoute()
|
||||
|
||||
// datas
|
||||
const description = ref("")
|
||||
const initialTableData = [
|
||||
["", "", ""],
|
||||
["", "", ""],
|
||||
["", "", ""]
|
||||
]
|
||||
const fontnote = ref("")
|
||||
const tableDatas = ref(initialTableData)
|
||||
|
||||
// props
|
||||
const { reset } = defineProps<{
|
||||
reset: () => void
|
||||
}>()
|
||||
|
||||
const visible = ref(false)
|
||||
const theTitle = ref("")
|
||||
|
||||
const handleSyncOk = async () => {
|
||||
// 验证输入文字是否为空
|
||||
if (description.value.trim().length <= 0) {
|
||||
Message.error("请输入分析内容再提交")
|
||||
return false
|
||||
}
|
||||
try {
|
||||
// 请求接口
|
||||
await projectApi.postEnvAnalysis({
|
||||
id: route.query.id,
|
||||
table: tableDatas.value,
|
||||
fontnote: fontnote.value,
|
||||
description: description.value
|
||||
})
|
||||
Message.success("保存成功")
|
||||
} catch (e) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
const handleOnClose = () => {
|
||||
// 用来清空数据
|
||||
fontnote.value = ""
|
||||
description.value = ""
|
||||
tableDatas.value = cloneDeep(initialTableData)
|
||||
reset()
|
||||
}
|
||||
|
||||
const open = async (category_str: string) => {
|
||||
proxy?.$loading?.show("数据加载中...")
|
||||
theTitle.value = category_str
|
||||
try {
|
||||
// 获取数据并赋值给tableData
|
||||
const res = await projectApi.getEnvAnalysis(route.query.id)
|
||||
if (res.code === 25001) {
|
||||
tableDatas.value = res.data.table
|
||||
fontnote.value = res.data.fontnote
|
||||
description.value = res.data.description
|
||||
}
|
||||
visible.value = true
|
||||
} catch (e) {
|
||||
} finally {
|
||||
proxy?.$loading?.hide()
|
||||
}
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
open
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
<template>
|
||||
<div class="text-table-container">
|
||||
<a-modal
|
||||
v-model:visible="visible"
|
||||
width="50%"
|
||||
draggable
|
||||
:on-before-ok="handleSyncOk"
|
||||
unmount-on-close
|
||||
ok-text="确认保存"
|
||||
cancel-text="关闭不保存"
|
||||
:maskClosable="false"
|
||||
@close="handleOnClose"
|
||||
>
|
||||
<template #title>{{ theTitle }}</template>
|
||||
<a-space direction="vertical" fill>
|
||||
<a-card title="差异性段落描述" hoverable>
|
||||
<a-textarea auto-size placeholder="请填写差异性分析和'见下表所示'" v-model="description"></a-textarea>
|
||||
</a-card>
|
||||
<a-card title="表格" hoverable>
|
||||
<WordLikeTable v-model="tableDatas" v-model:fontnote="fontnote" />
|
||||
</a-card>
|
||||
</a-space>
|
||||
</a-modal>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { Message } from "@arco-design/web-vue"
|
||||
import { getCurrentInstance, ref } from "vue"
|
||||
import { useRoute } from "vue-router"
|
||||
import WordLikeTable from "./projectModal/wordLikeTable/index.vue"
|
||||
import { cloneDeep } from "lodash-es"
|
||||
import projectApi from "@/api/project/project"
|
||||
|
||||
const { proxy } = getCurrentInstance() as any
|
||||
const route = useRoute()
|
||||
|
||||
// datas
|
||||
const description = ref("")
|
||||
const initialTableData = [
|
||||
["", "", ""],
|
||||
["", "", ""],
|
||||
["", "", ""]
|
||||
]
|
||||
const fontnote = ref("")
|
||||
const tableDatas = ref(initialTableData)
|
||||
|
||||
// props
|
||||
const { reset } = defineProps<{
|
||||
reset: () => void
|
||||
}>()
|
||||
|
||||
const visible = ref(false)
|
||||
const theTitle = ref("")
|
||||
|
||||
const handleSyncOk = async () => {
|
||||
// 验证输入文字是否为空
|
||||
if (description.value.trim().length <= 0) {
|
||||
Message.error("请输入分析内容再提交")
|
||||
return false
|
||||
}
|
||||
try {
|
||||
// 请求接口
|
||||
await projectApi.postEnvAnalysis({
|
||||
id: route.query.id,
|
||||
table: tableDatas.value,
|
||||
fontnote: fontnote.value,
|
||||
description: description.value
|
||||
})
|
||||
Message.success("保存成功")
|
||||
} catch (e) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
const handleOnClose = () => {
|
||||
// 用来清空数据
|
||||
fontnote.value = ""
|
||||
description.value = ""
|
||||
tableDatas.value = cloneDeep(initialTableData)
|
||||
reset()
|
||||
}
|
||||
|
||||
const open = async (category_str: string) => {
|
||||
proxy?.$loading?.show("数据加载中...")
|
||||
theTitle.value = category_str
|
||||
try {
|
||||
// 获取数据并赋值给tableData
|
||||
const res = await projectApi.getEnvAnalysis(route.query.id)
|
||||
if (res.code === 25001) {
|
||||
tableDatas.value = res.data.table
|
||||
fontnote.value = res.data.fontnote || ""
|
||||
description.value = res.data.description || ""
|
||||
}
|
||||
visible.value = true
|
||||
} catch (e) {
|
||||
} finally {
|
||||
proxy?.$loading?.hide()
|
||||
}
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
open
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
|
||||
@@ -1,95 +1,114 @@
|
||||
<template>
|
||||
<!-- 组件:该组件显示一个正方体,可粘贴图片内容进去并展示,并生成base64到数据里面 -->
|
||||
<div class="image-input-container flex flex-col gap-1">
|
||||
<div class="image-input-handle flex items-center justify-center" @paste="handlePaste">
|
||||
<!-- 加载状态 -->
|
||||
<div v-if="isLoading">
|
||||
<a-spin :size="32" />
|
||||
</div>
|
||||
<!-- 正常显示状态 -->
|
||||
<template v-else-if="imgData">
|
||||
<img :src="imgData" alt="粘贴的图片" class="preview-image img-container" />
|
||||
</template>
|
||||
|
||||
<template v-else>
|
||||
<div class="placeholder">此处Ctrl+V粘贴图片</div>
|
||||
</template>
|
||||
</div>
|
||||
<!-- 题注:fontnote -->
|
||||
<a-input v-model="fontnote" class="max-w-100" placeholder="请输入题注"></a-input>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { Message } from "@arco-design/web-vue"
|
||||
import { nextTick, ref } from "vue"
|
||||
|
||||
// 储存图片base64
|
||||
const imgData = defineModel<string>()
|
||||
// 储存题注
|
||||
const fontnote = defineModel<string>("fontnote")
|
||||
// 加载状态
|
||||
const isLoading = ref(false)
|
||||
|
||||
// 处理粘贴事件
|
||||
const handlePaste = async (e: ClipboardEvent) => {
|
||||
e.preventDefault()
|
||||
// 处理没有粘贴内容
|
||||
if (!e.clipboardData) return
|
||||
const items = e.clipboardData!.items
|
||||
// 遍历粘贴板内容
|
||||
for (let i = 0; i < items.length; i++) {
|
||||
const item = items[i]
|
||||
// 判断是否是粘贴的图片
|
||||
if (item.kind === "file" && item.type.startsWith("image/")) {
|
||||
const file = item.getAsFile()
|
||||
if (!file) {
|
||||
Message.error("读取图片失败,请重新粘贴")
|
||||
break
|
||||
}
|
||||
// 判断大小不超过50M
|
||||
if (file.size > 50 * 1024 * 1024) {
|
||||
Message.error("要求图片不超过50M")
|
||||
break
|
||||
}
|
||||
isLoading.value = true
|
||||
const reader = new FileReader()
|
||||
reader.onload = async (e: ProgressEvent<FileReader>) => {
|
||||
imgData.value = e.target!.result as string
|
||||
await nextTick() // 保证图片展示
|
||||
isLoading.value = false
|
||||
}
|
||||
// 加载失败处理
|
||||
reader.onerror = () => {
|
||||
Message.error("图片加载失败,请重试")
|
||||
isLoading.value = false
|
||||
}
|
||||
reader.readAsDataURL(file) // 可直接转为base64的url给img元素使用
|
||||
break
|
||||
} else {
|
||||
Message.error("请粘贴图片,无法粘贴文字或其他内容")
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
.image-input-handle {
|
||||
width: 200px;
|
||||
height: 180px;
|
||||
border: 1px solid #eee;
|
||||
cursor: alias;
|
||||
|
||||
.img-container{
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.preview-image {
|
||||
max-width: 100%;
|
||||
max-height: 100%;
|
||||
object-fit: contain;
|
||||
}
|
||||
</style>
|
||||
<template>
|
||||
<!-- 组件:该组件显示一个正方体,可粘贴图片内容进去并展示,并生成base64到数据里面 -->
|
||||
<div class="image-input-container flex flex-col gap-1">
|
||||
<div class="image-input-handle flex items-center justify-center" @paste="handlePaste">
|
||||
<!-- 加载状态 -->
|
||||
<div v-if="isLoading">
|
||||
<a-spin :size="32" />
|
||||
</div>
|
||||
<!-- 正常显示状态 -->
|
||||
<template v-else-if="imgData">
|
||||
<img :src="imgData" alt="粘贴的图片" class="preview-image img-container" />
|
||||
</template>
|
||||
|
||||
<template v-else>
|
||||
<div class="placeholder">此处Ctrl+V粘贴图片</div>
|
||||
</template>
|
||||
</div>
|
||||
<!-- 题注:fontnote -->
|
||||
<a-input v-model="fontnote" class="max-w-100" placeholder="请输入题注"></a-input>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { Message } from "@arco-design/web-vue"
|
||||
import { nextTick, ref, onMounted, onBeforeUnmount } from "vue"
|
||||
|
||||
const imgData = defineModel<string>()
|
||||
const fontnote = defineModel<string>("fontnote")
|
||||
const isLoading = ref(false)
|
||||
|
||||
// 全局粘贴处理函数
|
||||
const onGlobalPaste = (e: ClipboardEvent) => {
|
||||
// 可以增加判断:只有当前组件所在的 modal 打开时才处理(通过 props 传入 visible 状态或使用 provide/inject)
|
||||
// 简单起见,这里假设始终需要处理(父组件控制显示隐藏)
|
||||
handlePaste(e)
|
||||
}
|
||||
|
||||
// 处理粘贴逻辑(复用之前的修复版)
|
||||
const handlePaste = (e: ClipboardEvent) => {
|
||||
e.preventDefault()
|
||||
const clipboardData = e.clipboardData
|
||||
if (!clipboardData) return
|
||||
|
||||
const items = clipboardData.items
|
||||
let imageItem: DataTransferItem | null = null
|
||||
|
||||
for (let i = 0; i < items.length; i++) {
|
||||
const item = items[i]
|
||||
if (item.kind === "file" && item.type.startsWith("image/")) {
|
||||
imageItem = item
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if (!imageItem) {
|
||||
Message.error("请粘贴图片,无法粘贴文字或其他内容")
|
||||
return
|
||||
}
|
||||
|
||||
const file = imageItem.getAsFile()
|
||||
if (!file) {
|
||||
Message.error("读取图片失败,请重新粘贴")
|
||||
return
|
||||
}
|
||||
|
||||
if (file.size > 50 * 1024 * 1024) {
|
||||
Message.error("要求图片不超过50M")
|
||||
return
|
||||
}
|
||||
|
||||
isLoading.value = true
|
||||
const reader = new FileReader()
|
||||
reader.onload = (e) => {
|
||||
imgData.value = e.target!.result as string
|
||||
nextTick(() => {
|
||||
isLoading.value = false
|
||||
})
|
||||
}
|
||||
reader.onerror = () => {
|
||||
Message.error("图片加载失败,请重试")
|
||||
isLoading.value = false
|
||||
}
|
||||
reader.readAsDataURL(file)
|
||||
}
|
||||
|
||||
// 挂载全局监听
|
||||
onMounted(() => {
|
||||
document.addEventListener("paste", onGlobalPaste)
|
||||
})
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
document.removeEventListener("paste", onGlobalPaste)
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
.image-input-handle {
|
||||
width: 200px;
|
||||
height: 180px;
|
||||
border: 1px solid #eee;
|
||||
cursor: alias;
|
||||
|
||||
.img-container {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.preview-image {
|
||||
max-width: 100%;
|
||||
max-height: 100%;
|
||||
object-fit: contain;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,122 +1,123 @@
|
||||
<template>
|
||||
<!-- 完成自定义表格 -->
|
||||
<div class="fontnote">
|
||||
<a-space class="w-full">
|
||||
<span>题注:</span>
|
||||
<a-input v-model="fontnote" :style="{ width: '500px' }"></a-input>
|
||||
</a-space>
|
||||
</div>
|
||||
<div class="arco-table arco-table-size-large arco-table-border arco-table-stripe arco-table-hover">
|
||||
<div class="arco-table-container">
|
||||
<table class="arco-table-element" cellpadding="0" cellspacing="0">
|
||||
<thead>
|
||||
<tr class="arco-table-tr">
|
||||
<th class="arco-table-th" v-for="(_, colIndex) in datas![0]" :key="colIndex">
|
||||
<span class="arco-table-cell items-center justify-center">
|
||||
<a-tooltip content="此列后新增列">
|
||||
<a-button type="text" size="mini" @click="addColumn(colIndex)" class="delete-col-btn">
|
||||
<template #icon>
|
||||
<icon-plus />
|
||||
</template>
|
||||
</a-button>
|
||||
</a-tooltip>
|
||||
<a-tooltip content="删除该列">
|
||||
<a-button
|
||||
type="text"
|
||||
size="mini"
|
||||
status="danger"
|
||||
@click="deleteColumn(colIndex)"
|
||||
:disabled="datas![0].length <= 1"
|
||||
class="delete-col-btn"
|
||||
>
|
||||
<template #icon>
|
||||
<icon-close />
|
||||
</template>
|
||||
</a-button>
|
||||
</a-tooltip>
|
||||
</span>
|
||||
</th>
|
||||
<th class="arco-table-th" :style="{ textAlign: 'center' }">
|
||||
<span>操作</span>
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr class="arco-table-tr" v-for="(row, rowIndex) in datas" :key="rowIndex">
|
||||
<td class="arco-table-td" v-for="(col, colIndex) in row" :key="colIndex">
|
||||
<span class="arco-table-cell">
|
||||
<a-textarea auto-size v-model="datas![rowIndex][colIndex]" />
|
||||
</span>
|
||||
</td>
|
||||
<td class="arco-table-td">
|
||||
<span class="arco-table-cell items-center justify-center">
|
||||
<a-tooltip content="此行后新增行">
|
||||
<a-button type="text" size="mini" @click="addRow(rowIndex)" class="delete-col-btn">
|
||||
<template #icon>
|
||||
<icon-plus />
|
||||
</template>
|
||||
</a-button>
|
||||
</a-tooltip>
|
||||
<a-tooltip content="删除该行">
|
||||
<a-button size="mini" type="text" status="danger" @click="deleteRow(rowIndex)" :disabled="datas!.length <= 1">
|
||||
<template #icon>
|
||||
<icon-delete />
|
||||
</template>
|
||||
</a-button>
|
||||
</a-tooltip>
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
// 该组件储存数据
|
||||
const fontnote = defineModel<string>("fontnote")
|
||||
|
||||
const datas = defineModel<string[][]>()
|
||||
|
||||
// 行列操作
|
||||
const deleteRow = (rowIndex: number) => {
|
||||
datas.value!.splice(rowIndex, 1)
|
||||
}
|
||||
const deleteColumn = (colIndex: number) => {
|
||||
datas.value!.forEach((row) => {
|
||||
row.splice(colIndex, 1)
|
||||
})
|
||||
}
|
||||
const addRow = (rowIndex: number) => {
|
||||
const newRow = new Array(datas.value![0].length).fill("")
|
||||
datas.value!.splice(rowIndex + 1, 0, newRow)
|
||||
}
|
||||
const addColumn = (colIndex: number) => {
|
||||
// 处理空表格的特殊情况
|
||||
if (datas.value!.length === 0) {
|
||||
datas.value!.push([""])
|
||||
return
|
||||
}
|
||||
// 新增后续列
|
||||
datas.value!.forEach((row) => {
|
||||
const insertPosition = colIndex === -1 ? row.length : colIndex + 1
|
||||
row.splice(insertPosition, 0, "")
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
.fontnote {
|
||||
margin: 10px 0;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.arco-textarea {
|
||||
min-width: 120px;
|
||||
}
|
||||
|
||||
.arco-table-cell {
|
||||
padding: 5px;
|
||||
}
|
||||
</style>
|
||||
<template>
|
||||
<!-- 完成自定义表格 -->
|
||||
<div class="fontnote">
|
||||
<a-space class="w-full">
|
||||
<span>题注:</span>
|
||||
<a-input v-model="fontnote" :style="{ width: '500px' }"></a-input>
|
||||
</a-space>
|
||||
<a-alert type="warning" class="mt-2">表格第一行为[表头],测评数据、软/硬件项表格会自动添加序号列,而其他纯自定义表格(动态环境描述、软件概述)不会添加序号列</a-alert>
|
||||
</div>
|
||||
<div class="arco-table arco-table-size-large arco-table-border arco-table-stripe arco-table-hover">
|
||||
<div class="arco-table-container">
|
||||
<table class="arco-table-element" cellpadding="0" cellspacing="0">
|
||||
<thead>
|
||||
<tr class="arco-table-tr">
|
||||
<th class="arco-table-th" v-for="(_, colIndex) in datas![0]" :key="colIndex">
|
||||
<span class="arco-table-cell items-center justify-center">
|
||||
<a-tooltip content="此列后新增列">
|
||||
<a-button type="text" size="mini" @click="addColumn(colIndex)" class="delete-col-btn">
|
||||
<template #icon>
|
||||
<icon-plus />
|
||||
</template>
|
||||
</a-button>
|
||||
</a-tooltip>
|
||||
<a-tooltip content="删除该列">
|
||||
<a-button
|
||||
type="text"
|
||||
size="mini"
|
||||
status="danger"
|
||||
@click="deleteColumn(colIndex)"
|
||||
:disabled="datas![0].length <= 1"
|
||||
class="delete-col-btn"
|
||||
>
|
||||
<template #icon>
|
||||
<icon-close />
|
||||
</template>
|
||||
</a-button>
|
||||
</a-tooltip>
|
||||
</span>
|
||||
</th>
|
||||
<th class="arco-table-th" :style="{ textAlign: 'center' }">
|
||||
<span>操作</span>
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr class="arco-table-tr" v-for="(row, rowIndex) in datas" :key="rowIndex">
|
||||
<td class="arco-table-td" v-for="(col, colIndex) in row" :key="colIndex">
|
||||
<span class="arco-table-cell">
|
||||
<a-textarea auto-size v-model="datas![rowIndex][colIndex]" />
|
||||
</span>
|
||||
</td>
|
||||
<td class="arco-table-td">
|
||||
<span class="arco-table-cell items-center justify-center">
|
||||
<a-tooltip content="此行后新增行">
|
||||
<a-button type="text" size="mini" @click="addRow(rowIndex)" class="delete-col-btn">
|
||||
<template #icon>
|
||||
<icon-plus />
|
||||
</template>
|
||||
</a-button>
|
||||
</a-tooltip>
|
||||
<a-tooltip content="删除该行">
|
||||
<a-button size="mini" type="text" status="danger" @click="deleteRow(rowIndex)" :disabled="datas!.length <= 1">
|
||||
<template #icon>
|
||||
<icon-delete />
|
||||
</template>
|
||||
</a-button>
|
||||
</a-tooltip>
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
// 该组件储存数据
|
||||
const fontnote = defineModel<string>("fontnote")
|
||||
|
||||
const datas = defineModel<string[][]>()
|
||||
|
||||
// 行列操作
|
||||
const deleteRow = (rowIndex: number) => {
|
||||
datas.value!.splice(rowIndex, 1)
|
||||
}
|
||||
const deleteColumn = (colIndex: number) => {
|
||||
datas.value!.forEach((row) => {
|
||||
row.splice(colIndex, 1)
|
||||
})
|
||||
}
|
||||
const addRow = (rowIndex: number) => {
|
||||
const newRow = new Array(datas.value![0].length).fill("")
|
||||
datas.value!.splice(rowIndex + 1, 0, newRow)
|
||||
}
|
||||
const addColumn = (colIndex: number) => {
|
||||
// 处理空表格的特殊情况
|
||||
if (datas.value!.length === 0) {
|
||||
datas.value!.push([""])
|
||||
return
|
||||
}
|
||||
// 新增后续列
|
||||
datas.value!.forEach((row) => {
|
||||
const insertPosition = colIndex === -1 ? row.length : colIndex + 1
|
||||
row.splice(insertPosition, 0, "")
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
.fontnote {
|
||||
margin: 10px 0;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.arco-textarea {
|
||||
min-width: 120px;
|
||||
}
|
||||
|
||||
.arco-table-cell {
|
||||
padding: 5px;
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user