新增软件概述;新增全局loading插件
This commit is contained in:
16
cdTMP/package-lock.json
generated
16
cdTMP/package-lock.json
generated
@@ -32,7 +32,7 @@
|
|||||||
"vue": "^3.5.27",
|
"vue": "^3.5.27",
|
||||||
"vue-clipboard3": "^2.0.0",
|
"vue-clipboard3": "^2.0.0",
|
||||||
"vue-color-kit": "^1.0.6",
|
"vue-color-kit": "^1.0.6",
|
||||||
"vue-data-ui": "^3.13.7",
|
"vue-data-ui": "^3.14.1",
|
||||||
"vue-router": "^5.0.1",
|
"vue-router": "^5.0.1",
|
||||||
"vuedraggable": "^2.24.3"
|
"vuedraggable": "^2.24.3"
|
||||||
},
|
},
|
||||||
@@ -40,7 +40,7 @@
|
|||||||
"@tailwindcss/postcss": "^4.1.18",
|
"@tailwindcss/postcss": "^4.1.18",
|
||||||
"@tailwindcss/vite": "^4.1.18",
|
"@tailwindcss/vite": "^4.1.18",
|
||||||
"@types/lodash-es": "^4.17.12",
|
"@types/lodash-es": "^4.17.12",
|
||||||
"@types/node": "^25.1.0",
|
"@types/node": "^25.2.0",
|
||||||
"@types/nprogress": "^0.2.3",
|
"@types/nprogress": "^0.2.3",
|
||||||
"@types/qs": "^6.14.0",
|
"@types/qs": "^6.14.0",
|
||||||
"@vitejs/plugin-vue": "^6.0.3",
|
"@vitejs/plugin-vue": "^6.0.3",
|
||||||
@@ -1900,9 +1900,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@types/node": {
|
"node_modules/@types/node": {
|
||||||
"version": "25.1.0",
|
"version": "25.2.0",
|
||||||
"resolved": "https://registry.npmmirror.com/@types/node/-/node-25.1.0.tgz",
|
"resolved": "https://registry.npmmirror.com/@types/node/-/node-25.2.0.tgz",
|
||||||
"integrity": "sha512-t7frlewr6+cbx+9Ohpl0NOTKXZNV9xHRmNOvql47BFJKcEG1CxtxlPEEe+gR9uhVWM4DwhnvTF110mIL4yP9RA==",
|
"integrity": "sha512-DZ8VwRFUNzuqJ5khrvwMXHmvPe+zGayJhr2CDNiKB1WBE1ST8Djl00D0IC4vvNmHMdj6DlbYRIaFE7WHjlDl5w==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@@ -5707,9 +5707,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/vue-data-ui": {
|
"node_modules/vue-data-ui": {
|
||||||
"version": "3.13.7",
|
"version": "3.14.1",
|
||||||
"resolved": "https://registry.npmmirror.com/vue-data-ui/-/vue-data-ui-3.13.7.tgz",
|
"resolved": "https://registry.npmmirror.com/vue-data-ui/-/vue-data-ui-3.14.1.tgz",
|
||||||
"integrity": "sha512-tFz+sN5CaDUl1/VotE35lV3hvJPurkhE6j/e3DldOMDbDCunOYvwqGuMglmGxQ8n/w1N/iqnEWVTmhIJHYdd8Q==",
|
"integrity": "sha512-i7GNaNtw39Avy9VuDHGdLdDpH2sRsr2ZFRpiilOvQ0XA5887KCvd7J5IUQRpVNTQSaT7pFSSEMPwcQ7NfPHuVw==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"jspdf": ">=3.0.1",
|
"jspdf": ">=3.0.1",
|
||||||
|
|||||||
@@ -35,7 +35,7 @@
|
|||||||
"vue": "^3.5.27",
|
"vue": "^3.5.27",
|
||||||
"vue-clipboard3": "^2.0.0",
|
"vue-clipboard3": "^2.0.0",
|
||||||
"vue-color-kit": "^1.0.6",
|
"vue-color-kit": "^1.0.6",
|
||||||
"vue-data-ui": "^3.13.7",
|
"vue-data-ui": "^3.14.1",
|
||||||
"vue-router": "^5.0.1",
|
"vue-router": "^5.0.1",
|
||||||
"vuedraggable": "^2.24.3"
|
"vuedraggable": "^2.24.3"
|
||||||
},
|
},
|
||||||
@@ -43,7 +43,7 @@
|
|||||||
"@tailwindcss/postcss": "^4.1.18",
|
"@tailwindcss/postcss": "^4.1.18",
|
||||||
"@tailwindcss/vite": "^4.1.18",
|
"@tailwindcss/vite": "^4.1.18",
|
||||||
"@types/lodash-es": "^4.17.12",
|
"@types/lodash-es": "^4.17.12",
|
||||||
"@types/node": "^25.1.0",
|
"@types/node": "^25.2.0",
|
||||||
"@types/nprogress": "^0.2.3",
|
"@types/nprogress": "^0.2.3",
|
||||||
"@types/qs": "^6.14.0",
|
"@types/qs": "^6.14.0",
|
||||||
"@vitejs/plugin-vue": "^6.0.3",
|
"@vitejs/plugin-vue": "^6.0.3",
|
||||||
|
|||||||
@@ -110,5 +110,27 @@ export default {
|
|||||||
id: projectId
|
id: projectId
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* 新增或者修改软件概述
|
||||||
|
* @returns 返回新增或修改是否成功
|
||||||
|
*/
|
||||||
|
postSoftSummary(data) {
|
||||||
|
return request({
|
||||||
|
url: "/testmanage/project/soft_summary/",
|
||||||
|
method: "post",
|
||||||
|
data: data
|
||||||
|
})
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* 获取项目的软件概述
|
||||||
|
* @returns 返回软件概述数据
|
||||||
|
*/
|
||||||
|
getSoftSummary(id) {
|
||||||
|
return request({
|
||||||
|
url: "/testmanage/project/get_soft_summary/",
|
||||||
|
method: "get",
|
||||||
|
params: { id: id }
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
64
cdTMP/src/components/GlobalLoading/index.vue
Normal file
64
cdTMP/src/components/GlobalLoading/index.vue
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
<template>
|
||||||
|
<div v-if="visible" class="global-loading">
|
||||||
|
<div class="spinner"></div>
|
||||||
|
<div v-if="text" class="loading-text">{{ text }}</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref } from "vue"
|
||||||
|
|
||||||
|
const visible = ref(false)
|
||||||
|
const text = ref("加载中...")
|
||||||
|
const show = (loadingText = "加载中...") => {
|
||||||
|
text.value = loadingText
|
||||||
|
visible.value = true
|
||||||
|
}
|
||||||
|
|
||||||
|
const hide = () => {
|
||||||
|
visible.value = false
|
||||||
|
}
|
||||||
|
|
||||||
|
// 暴露方法供外部调用
|
||||||
|
defineExpose({ show, hide })
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.global-loading {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
background: rgba(255, 255, 255, 0.8);
|
||||||
|
z-index: 9999;
|
||||||
|
}
|
||||||
|
|
||||||
|
.spinner {
|
||||||
|
border: 4px solid rgba(0, 0, 0, 0.1);
|
||||||
|
border-left-color: rgb(var(--blue-6));
|
||||||
|
border-radius: 50%;
|
||||||
|
width: 40px;
|
||||||
|
height: 40px;
|
||||||
|
animation: spin 1s linear infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
.loading-text {
|
||||||
|
margin-top: 10px;
|
||||||
|
color: rgb(var(--blue-6));
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes spin {
|
||||||
|
0% {
|
||||||
|
transform: rotate(0deg);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
transform: rotate(360deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
import { TableColumnData } from "@arco-design/web-vue"
|
import { TableColumnData } from "@arco-design/web-vue"
|
||||||
import { ref, reactive } from "vue"
|
import { ref, reactive, onUnmounted } from "vue"
|
||||||
// 粘贴图片组件
|
// 粘贴图片组件
|
||||||
import ImageInput from "../ImageInput/index.vue"
|
import ImageInput from "../ImageInput/index.vue"
|
||||||
// wordlike组件
|
// wordlike组件
|
||||||
@@ -44,7 +44,7 @@ export default function useTable() {
|
|||||||
case "image":
|
case "image":
|
||||||
return <ImageInput v-model={data.value[rowIndex].content} v-model:fontnote={data.value[rowIndex].fontnote}></ImageInput>
|
return <ImageInput v-model={data.value[rowIndex].content} v-model:fontnote={data.value[rowIndex].fontnote}></ImageInput>
|
||||||
case "table":
|
case "table":
|
||||||
return <WordLikeTable></WordLikeTable>
|
return <WordLikeTable v-model={data.value[rowIndex].content} v-model:fontnote={data.value[rowIndex].fontnote}></WordLikeTable>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -66,14 +66,19 @@ export default function useTable() {
|
|||||||
}
|
}
|
||||||
])
|
])
|
||||||
|
|
||||||
|
// 卸载时清空数据
|
||||||
|
const handleOnClose = () => {
|
||||||
|
data.value = [{ ...initalRowData }]
|
||||||
|
}
|
||||||
|
|
||||||
// 数据定义 - 测试
|
// 数据定义 - 测试
|
||||||
const data = ref([
|
const data = ref<
|
||||||
{
|
{
|
||||||
type: "text",
|
type: string
|
||||||
content: "这是数据内容",
|
content: string | string[][]
|
||||||
fontnote: ""
|
fontnote: string
|
||||||
}
|
}[]
|
||||||
])
|
>([])
|
||||||
|
|
||||||
// 单行初始内容-并设置数据类型
|
// 单行初始内容-并设置数据类型
|
||||||
const initalRowData = {
|
const initalRowData = {
|
||||||
@@ -104,8 +109,16 @@ export default function useTable() {
|
|||||||
|
|
||||||
// 新增表格
|
// 新增表格
|
||||||
const addTableRow = () => {
|
const addTableRow = () => {
|
||||||
data.value.push({ type: "table", content: "", fontnote: "" })
|
data.value.push({
|
||||||
|
type: "table",
|
||||||
|
content: [
|
||||||
|
["", "", ""],
|
||||||
|
["", "", ""],
|
||||||
|
["", "", ""]
|
||||||
|
],
|
||||||
|
fontnote: ""
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
return { columns, data, handleChange, addTextRow, addPicRow, addTableRow }
|
return { columns, data, handleChange, addTextRow, addPicRow, addTableRow, handleOnClose }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,17 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="project-modal-container">
|
<div class="project-modal-container">
|
||||||
<a-modal v-model:visible="visible" width="70%" draggable :on-before-ok="handleSyncOk">
|
<a-modal
|
||||||
<template #title>{{ "软件概述" }}</template>
|
v-model:visible="visible"
|
||||||
|
width="80%"
|
||||||
|
draggable
|
||||||
|
:on-before-ok="handleSyncOk"
|
||||||
|
unmount-on-close
|
||||||
|
ok-text="确认保存"
|
||||||
|
cancel-text="关闭不保存"
|
||||||
|
:maskClosable="false"
|
||||||
|
@close="handleOnClose"
|
||||||
|
>
|
||||||
|
<template #title>{{ title }}</template>
|
||||||
<div class="mb-2">
|
<div class="mb-2">
|
||||||
<a-space>
|
<a-space>
|
||||||
<a-dropdown>
|
<a-dropdown>
|
||||||
@@ -23,17 +33,44 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref } from "vue"
|
import { ref } from "vue"
|
||||||
import useTable from "./hooks/useTable"
|
import useTable from "./hooks/useTable"
|
||||||
|
import projectApi from "@/api/project/project"
|
||||||
|
import { useRoute } from "vue-router"
|
||||||
|
import { Message } from "@arco-design/web-vue"
|
||||||
|
import { getCurrentInstance } from "vue"
|
||||||
|
|
||||||
|
const { proxy } = getCurrentInstance() as any
|
||||||
|
|
||||||
|
const route = useRoute()
|
||||||
|
|
||||||
const visible = ref(false)
|
const visible = ref(false)
|
||||||
|
const title = ref("软件概述-新增")
|
||||||
|
|
||||||
const { columns, data, handleChange, addTextRow, addPicRow, addTableRow } = useTable()
|
const { columns, data, handleChange, addTextRow, addPicRow, addTableRow, handleOnClose } = useTable()
|
||||||
|
|
||||||
const handleSyncOk = async () => {
|
const handleSyncOk = async () => {
|
||||||
|
try {
|
||||||
|
await projectApi.postSoftSummary({ id: route.query.id, data: data.value })
|
||||||
|
visible.value = false
|
||||||
|
Message.success("保存成功")
|
||||||
|
} catch (e) {
|
||||||
|
Message.error("提交时发送错误,请联系管理员")
|
||||||
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
const open = async () => {
|
const open = async () => {
|
||||||
visible.value = true
|
proxy?.$loading?.show("数据加载中...")
|
||||||
|
try {
|
||||||
|
const res = await projectApi.getSoftSummary(route.query.id)
|
||||||
|
const code = res.code // 25001表示有数据,25002表示没有数据
|
||||||
|
title.value = code === 25001 ? "软件概述-修改" : "软件概述-新增"
|
||||||
|
data.value = res.data
|
||||||
|
visible.value = true
|
||||||
|
} catch (e) {
|
||||||
|
Message.error("获取软件概述信息失败")
|
||||||
|
} finally {
|
||||||
|
proxy?.$loading?.hide()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
defineExpose({ open })
|
defineExpose({ open })
|
||||||
|
|||||||
@@ -1,14 +1,122 @@
|
|||||||
<template>
|
<template>
|
||||||
<!-- 完成自定义表格 -->
|
<!-- 完成自定义表格 -->
|
||||||
<div class="word-like-container">
|
<div class="fontnote">
|
||||||
111
|
<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>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<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>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="less">
|
<style scoped lang="less">
|
||||||
|
.fontnote {
|
||||||
|
margin: 10px 0;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.arco-textarea {
|
||||||
|
min-width: 120px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.arco-table-cell {
|
||||||
|
padding: 5px;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
@@ -25,6 +25,10 @@ app.use(router)
|
|||||||
app.use(pinia)
|
app.use(pinia)
|
||||||
app.use(globalComponents)
|
app.use(globalComponents)
|
||||||
|
|
||||||
|
// 全局loading插件
|
||||||
|
import loadingPlugin from "./plugins/loading"
|
||||||
|
app.use(loadingPlugin)
|
||||||
|
|
||||||
// 使用服务端请求数据管理库
|
// 使用服务端请求数据管理库
|
||||||
import { VueQueryPlugin } from "@tanstack/vue-query"
|
import { VueQueryPlugin } from "@tanstack/vue-query"
|
||||||
app.use(VueQueryPlugin)
|
app.use(VueQueryPlugin)
|
||||||
|
|||||||
16
cdTMP/src/plugins/loading.js
Normal file
16
cdTMP/src/plugins/loading.js
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
import { createVNode, render } from "vue"
|
||||||
|
import LoadingComponent from "@/components/GlobalLoading/index.vue"
|
||||||
|
|
||||||
|
export default {
|
||||||
|
install(app) {
|
||||||
|
// 创建虚拟节点并渲染
|
||||||
|
const vnode = createVNode(LoadingComponent)
|
||||||
|
render(vnode, document.body)
|
||||||
|
|
||||||
|
// 挂载到全局属性
|
||||||
|
app.config.globalProperties.$loading = {
|
||||||
|
show: (text) => vnode.component?.exposed?.show(text),
|
||||||
|
hide: () => vnode.component?.exposed?.hide()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user