2025-03-25 09:58:19 +00:00
|
|
|
|
<template>
|
|
|
|
|
|
<div
|
|
|
|
|
|
class="sidebarTree"
|
|
|
|
|
|
:class="{
|
|
|
|
|
|
hidenLeft: !showFlag,
|
|
|
|
|
|
}"
|
|
|
|
|
|
>
|
|
|
|
|
|
<i
|
|
|
|
|
|
class="el-icon-arrow-right"
|
|
|
|
|
|
style="font-size: 24px; margin-top: 20px; cursor: pointer"
|
|
|
|
|
|
v-show="!showFlag"
|
|
|
|
|
|
@click.stop="changeShow()"
|
|
|
|
|
|
></i>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 树形菜单 -->
|
|
|
|
|
|
<div class="treeTitle">版本列表</div>
|
|
|
|
|
|
<div class="topBox" v-show="showFlag">
|
|
|
|
|
|
<div class="topText" @click.stop="changeOpen">
|
|
|
|
|
|
<i v-show="openFlag" class="el-icon-caret-bottom"></i>
|
|
|
|
|
|
<i v-show="!openFlag" class="el-icon-caret-right"></i>
|
|
|
|
|
|
<img src="@/assets/demand/list.png" />
|
|
|
|
|
|
<span>全部版本</span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="topBtn">
|
|
|
|
|
|
<i
|
|
|
|
|
|
class="el-icon-plus"
|
|
|
|
|
|
@click.stop="dialogVisible = true"
|
|
|
|
|
|
style="font-size: 20px"
|
|
|
|
|
|
></i>
|
|
|
|
|
|
<i
|
|
|
|
|
|
class="el-icon-arrow-left"
|
|
|
|
|
|
style="font-size: 20px"
|
|
|
|
|
|
@click.stop="changeShow()"
|
|
|
|
|
|
></i>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<el-tree
|
|
|
|
|
|
v-show="showFlag"
|
|
|
|
|
|
:data="treeData"
|
|
|
|
|
|
:props="defaultProps"
|
|
|
|
|
|
:default-expanded-keys="defaultExpend"
|
|
|
|
|
|
node-key="nodeId"
|
|
|
|
|
|
class="tree"
|
|
|
|
|
|
ref="treeRef"
|
|
|
|
|
|
@node-click="handleNodeClick"
|
|
|
|
|
|
:expand-on-click-node="false"
|
|
|
|
|
|
>
|
|
|
|
|
|
<template #default="{ node, data }">
|
|
|
|
|
|
<div
|
|
|
|
|
|
class="treeNode"
|
|
|
|
|
|
@mousemove="data.hover = true"
|
|
|
|
|
|
@mouseout="data.hover = false"
|
|
|
|
|
|
>
|
|
|
|
|
|
<!-- 展开/收起图标 -->
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 节点图标 -->
|
|
|
|
|
|
<img
|
2025-03-28 09:51:53 +00:00
|
|
|
|
v-if="data.type == 0 && data.nodeId === selectedId"
|
2025-03-25 09:58:19 +00:00
|
|
|
|
src="@/assets/demand/treeIcon.png"
|
|
|
|
|
|
class="nodeIcon"
|
|
|
|
|
|
/>
|
|
|
|
|
|
<img
|
2025-03-28 09:51:53 +00:00
|
|
|
|
v-if="data.type == 0 && data.nodeId !== selectedId"
|
2025-03-25 09:58:19 +00:00
|
|
|
|
src="@/assets/demand/treeIcon1.png"
|
|
|
|
|
|
class="nodeIcon"
|
|
|
|
|
|
/>
|
|
|
|
|
|
<!-- 节点文本 -->
|
2025-04-25 10:04:28 +00:00
|
|
|
|
<el-tooltip
|
|
|
|
|
|
class="item"
|
|
|
|
|
|
effect="light"
|
|
|
|
|
|
:content="data.title"
|
|
|
|
|
|
placement="top"
|
|
|
|
|
|
:disabled="data.title.length > 8 ? false : true"
|
2025-03-25 09:58:19 +00:00
|
|
|
|
>
|
2025-04-25 10:04:28 +00:00
|
|
|
|
<div
|
|
|
|
|
|
:class="[
|
|
|
|
|
|
'nodeLabel',
|
|
|
|
|
|
data.nodeId === selectedId ? 'selected' : '',
|
|
|
|
|
|
]"
|
|
|
|
|
|
>
|
|
|
|
|
|
{{ data.title }}
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</el-tooltip>
|
2025-03-25 09:58:19 +00:00
|
|
|
|
|
|
|
|
|
|
<!-- 右侧数字标记 -->
|
|
|
|
|
|
<span
|
|
|
|
|
|
v-if="data.type == 0 && !data.hover"
|
|
|
|
|
|
:class="[
|
|
|
|
|
|
'count',
|
|
|
|
|
|
data.nodeId === selectedId ? 'selectedCount' : '',
|
|
|
|
|
|
]"
|
|
|
|
|
|
>
|
|
|
|
|
|
{{ data.childrenList.length }}
|
|
|
|
|
|
</span>
|
|
|
|
|
|
<el-dropdown
|
|
|
|
|
|
v-show="data.type == 0 && data.hover"
|
|
|
|
|
|
trigger="click"
|
|
|
|
|
|
placement="bottom"
|
|
|
|
|
|
@command="
|
|
|
|
|
|
(val) => {
|
|
|
|
|
|
changeRow(val, data);
|
|
|
|
|
|
}
|
|
|
|
|
|
"
|
|
|
|
|
|
>
|
2025-03-26 09:58:58 +00:00
|
|
|
|
<i class="el-icon-more" style="font-size: 20px"></i>
|
2025-03-25 09:58:19 +00:00
|
|
|
|
<el-dropdown-menu slot="dropdown">
|
|
|
|
|
|
<el-dropdown-item command="add">新建需求</el-dropdown-item>
|
|
|
|
|
|
<el-dropdown-item command="edit">编辑</el-dropdown-item>
|
|
|
|
|
|
<el-dropdown-item command="del" style="color: #dd242a"
|
|
|
|
|
|
>删除</el-dropdown-item
|
|
|
|
|
|
>
|
|
|
|
|
|
</el-dropdown-menu>
|
|
|
|
|
|
</el-dropdown>
|
|
|
|
|
|
<!-- 右侧操作图标 -->
|
|
|
|
|
|
<img
|
|
|
|
|
|
v-if="data.actionIcon"
|
|
|
|
|
|
:src="data.actionIcon"
|
|
|
|
|
|
class="actionIcon"
|
|
|
|
|
|
/>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
</el-tree>
|
|
|
|
|
|
<el-dialog title="添加版本号" :visible.sync="dialogVisible" width="30%">
|
|
|
|
|
|
<el-form>
|
|
|
|
|
|
<el-form-item label="版本号">
|
|
|
|
|
|
<el-input v-model="demandData.name"></el-input>
|
|
|
|
|
|
</el-form-item>
|
|
|
|
|
|
</el-form>
|
|
|
|
|
|
<div slot="footer" class="dialog-footer">
|
|
|
|
|
|
<el-button @click="dialogVisible = false">取消</el-button>
|
|
|
|
|
|
<el-button type="primary" @click="confirmAddNode">确定</el-button>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</el-dialog>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
|
|
<script>
|
|
|
|
|
|
import { demandApi } from "@/utils/api";
|
|
|
|
|
|
export default {
|
|
|
|
|
|
name: "SidebarTree",
|
|
|
|
|
|
props: {
|
|
|
|
|
|
projectId: {
|
|
|
|
|
|
type: String,
|
|
|
|
|
|
default: "",
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
data() {
|
|
|
|
|
|
return {
|
|
|
|
|
|
selectedId: "",
|
|
|
|
|
|
treeData: [],
|
|
|
|
|
|
defaultProps: {
|
|
|
|
|
|
children: "childrenList",
|
|
|
|
|
|
label: "title",
|
|
|
|
|
|
},
|
|
|
|
|
|
dialogVisible: false,
|
|
|
|
|
|
demandData: {
|
|
|
|
|
|
name: "",
|
|
|
|
|
|
},
|
|
|
|
|
|
openFlag: false,
|
|
|
|
|
|
showFlag: true,
|
|
|
|
|
|
defaultExpend: [],
|
|
|
|
|
|
};
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
methods: {
|
|
|
|
|
|
handleNodeClick(data) {
|
|
|
|
|
|
this.selectedId = data.nodeId;
|
|
|
|
|
|
this.changeVersion(data);
|
|
|
|
|
|
},
|
|
|
|
|
|
getVersionTree(defaultId) {
|
|
|
|
|
|
demandApi
|
|
|
|
|
|
.getVersionTree({
|
|
|
|
|
|
projectId: this.projectId,
|
|
|
|
|
|
demandStatusList: [],
|
|
|
|
|
|
})
|
|
|
|
|
|
.then((res) => {
|
|
|
|
|
|
if (!res.data.length) {
|
2025-04-25 10:04:28 +00:00
|
|
|
|
this.treeData = [];
|
2025-03-25 09:58:19 +00:00
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
res.data = res.data.map((ele) => {
|
|
|
|
|
|
ele.nodeId = ele.id + "_" + ele.type;
|
2025-03-28 09:51:53 +00:00
|
|
|
|
ele.childrenList.map((item) => {
|
|
|
|
|
|
item.nodeId = item.id + "_" + item.type;
|
|
|
|
|
|
});
|
2025-03-25 09:58:19 +00:00
|
|
|
|
ele.hover = false;
|
|
|
|
|
|
return ele;
|
|
|
|
|
|
});
|
2025-04-21 09:54:57 +00:00
|
|
|
|
this.initTableData(defaultId, res.data);
|
2025-03-25 09:58:19 +00:00
|
|
|
|
this.treeData = res.data;
|
|
|
|
|
|
});
|
|
|
|
|
|
},
|
|
|
|
|
|
changeVersion(data) {
|
2025-04-21 09:54:57 +00:00
|
|
|
|
if (!data) {
|
|
|
|
|
|
data = {
|
|
|
|
|
|
id: this.projectId,
|
|
|
|
|
|
type: 2,
|
|
|
|
|
|
};
|
|
|
|
|
|
}
|
2025-03-25 09:58:19 +00:00
|
|
|
|
this.$emit("changeVersion", data);
|
|
|
|
|
|
},
|
2025-04-21 09:54:57 +00:00
|
|
|
|
initTableData(defaultId, tableList) {
|
|
|
|
|
|
if (defaultId && defaultId != "all") {
|
|
|
|
|
|
let searchNode = {};
|
|
|
|
|
|
this.defaultExpend = [defaultId];
|
|
|
|
|
|
searchNode = tableList.find((ele) => ele.nodeId == defaultId);
|
|
|
|
|
|
this.changeVersion(searchNode);
|
|
|
|
|
|
this.selectedId = this.defaultExpend[0];
|
|
|
|
|
|
} else if (defaultId == "all") {
|
|
|
|
|
|
this.selectedId = "";
|
|
|
|
|
|
this.changeVersion({
|
|
|
|
|
|
id: this.projectId,
|
|
|
|
|
|
type: 2,
|
|
|
|
|
|
});
|
|
|
|
|
|
} else {
|
|
|
|
|
|
this.defaultExpend = [tableList[0].nodeId];
|
|
|
|
|
|
this.selectedId = this.defaultExpend[0];
|
|
|
|
|
|
this.setVersionList(tableList.filter((ele) => ele.type == 0));
|
|
|
|
|
|
this.changeVersion(
|
|
|
|
|
|
tableList.find((ele) => ele.nodeId == this.defaultExpend[0])
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
2025-03-25 09:58:19 +00:00
|
|
|
|
setVersionList(data) {
|
|
|
|
|
|
this.$emit("setVersionList", data);
|
|
|
|
|
|
},
|
|
|
|
|
|
confirmAddNode() {
|
|
|
|
|
|
if (!this.demandData.name) {
|
|
|
|
|
|
this.$message({
|
|
|
|
|
|
message: "请填写版本号",
|
|
|
|
|
|
type: "warning",
|
|
|
|
|
|
});
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
2025-04-25 10:04:28 +00:00
|
|
|
|
if (this.demandData.name.length > 10) {
|
|
|
|
|
|
this.$message({
|
|
|
|
|
|
message: "版本号限制10个字符",
|
|
|
|
|
|
type: "warning",
|
|
|
|
|
|
});
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
2025-03-25 09:58:19 +00:00
|
|
|
|
let param = {
|
|
|
|
|
|
projectId: this.projectId,
|
|
|
|
|
|
versionNumber: this.demandData.name,
|
|
|
|
|
|
};
|
|
|
|
|
|
if (this.demandData.id) {
|
|
|
|
|
|
param.id = this.demandData.id;
|
|
|
|
|
|
demandApi.editVersion(param).then((res) => {
|
|
|
|
|
|
this.resetAdd(0);
|
|
|
|
|
|
});
|
|
|
|
|
|
} else {
|
|
|
|
|
|
demandApi.addVersion(param).then((res) => {
|
|
|
|
|
|
this.resetAdd(1);
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
resetAdd(add) {
|
|
|
|
|
|
this.$message({
|
|
|
|
|
|
message: add ? "添加成功" : "修改成功",
|
|
|
|
|
|
type: "success",
|
|
|
|
|
|
});
|
|
|
|
|
|
this.dialogVisible = false;
|
|
|
|
|
|
this.demandData.name = "";
|
|
|
|
|
|
this.demandData.id = "";
|
|
|
|
|
|
this.getVersionTree();
|
|
|
|
|
|
},
|
|
|
|
|
|
editDemand(data) {
|
|
|
|
|
|
this.demandData = {
|
|
|
|
|
|
name: data.title,
|
|
|
|
|
|
id: data.id,
|
|
|
|
|
|
};
|
|
|
|
|
|
this.dialogVisible = true;
|
|
|
|
|
|
},
|
|
|
|
|
|
delVersion(data) {
|
|
|
|
|
|
this.$confirm("此操作将永久删除该版本号, 是否继续?", "提示", {
|
|
|
|
|
|
confirmButtonText: "确定",
|
|
|
|
|
|
cancelButtonText: "取消",
|
|
|
|
|
|
type: "warning",
|
|
|
|
|
|
})
|
|
|
|
|
|
.then(() => {
|
|
|
|
|
|
demandApi.delVersion(data.id).then((res) => {
|
|
|
|
|
|
this.$message({
|
|
|
|
|
|
type: "success",
|
|
|
|
|
|
message: "删除成功!",
|
|
|
|
|
|
});
|
|
|
|
|
|
this.getVersionTree();
|
|
|
|
|
|
});
|
|
|
|
|
|
})
|
|
|
|
|
|
.catch(() => {});
|
|
|
|
|
|
},
|
|
|
|
|
|
changeOpen() {
|
|
|
|
|
|
this.openFlag = !this.openFlag;
|
|
|
|
|
|
if (this.openFlag) {
|
|
|
|
|
|
this.defaultExpend = this.treeData.map((ele) => ele.nodeId);
|
|
|
|
|
|
} else {
|
|
|
|
|
|
this.defaultExpend = [];
|
|
|
|
|
|
}
|
|
|
|
|
|
this.getVersionTree("all");
|
|
|
|
|
|
},
|
|
|
|
|
|
changeShow() {
|
|
|
|
|
|
this.showFlag = !this.showFlag;
|
|
|
|
|
|
},
|
|
|
|
|
|
changeRow(type, row) {
|
|
|
|
|
|
if (type == "add") {
|
|
|
|
|
|
this.$emit("addDemand");
|
|
|
|
|
|
} else if (type == "edit") {
|
|
|
|
|
|
this.editDemand(row);
|
|
|
|
|
|
} else if (type == "del") {
|
|
|
|
|
|
this.delVersion(row);
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
watch: {
|
|
|
|
|
|
projectId(newVal) {
|
|
|
|
|
|
this.$nextTick(() => {
|
|
|
|
|
|
this.getVersionTree();
|
|
|
|
|
|
});
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
};
|
|
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
|
|
<style scoped lang="scss">
|
|
|
|
|
|
.sidebarTree {
|
|
|
|
|
|
width: 100%;
|
|
|
|
|
|
max-width: 300px;
|
|
|
|
|
|
min-height: 100vh;
|
|
|
|
|
|
background-color: inherit;
|
|
|
|
|
|
padding-left: 20px;
|
|
|
|
|
|
}
|
|
|
|
|
|
.hidenLeft {
|
|
|
|
|
|
width: 40px;
|
|
|
|
|
|
}
|
|
|
|
|
|
.tree {
|
|
|
|
|
|
width: 100%;
|
|
|
|
|
|
height: 100%;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.treeNode {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
width: 100%;
|
|
|
|
|
|
height: 48px;
|
|
|
|
|
|
padding: 0 20px;
|
|
|
|
|
|
border-radius: 2px;
|
|
|
|
|
|
}
|
|
|
|
|
|
::v-deep .el-tree-node__children {
|
|
|
|
|
|
padding-left: 15px !important;
|
|
|
|
|
|
}
|
|
|
|
|
|
.expandIcon {
|
|
|
|
|
|
width: 10px;
|
|
|
|
|
|
height: 10px;
|
|
|
|
|
|
margin-right: 15px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.nodeIcon {
|
|
|
|
|
|
width: 18px;
|
|
|
|
|
|
height: 18px;
|
|
|
|
|
|
margin-right: 15px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.nodeLabel {
|
|
|
|
|
|
flex: 1;
|
|
|
|
|
|
font-family: "PingFang SC";
|
|
|
|
|
|
font-size: 16px;
|
|
|
|
|
|
font-weight: 600;
|
|
|
|
|
|
line-height: 36px;
|
|
|
|
|
|
color: #333;
|
2025-04-25 10:04:28 +00:00
|
|
|
|
max-width: 160px;
|
|
|
|
|
|
overflow: hidden;
|
|
|
|
|
|
text-overflow: ellipsis;
|
|
|
|
|
|
white-space: nowrap;
|
|
|
|
|
|
padding-right: 20px;
|
2025-03-25 09:58:19 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-03-28 09:51:53 +00:00
|
|
|
|
.nodeLabel.selected {
|
2025-03-25 09:58:19 +00:00
|
|
|
|
color: #4096ff;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.count {
|
|
|
|
|
|
font-family: "PingFang SC";
|
|
|
|
|
|
font-size: 16px;
|
|
|
|
|
|
font-weight: 600;
|
|
|
|
|
|
line-height: 26px;
|
|
|
|
|
|
color: #999;
|
|
|
|
|
|
margin-right: 15px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.selectedCount {
|
|
|
|
|
|
color: #4096ff;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.actionIcon {
|
|
|
|
|
|
width: 18px;
|
|
|
|
|
|
height: 18px;
|
|
|
|
|
|
}
|
|
|
|
|
|
.treeTitle {
|
|
|
|
|
|
padding: 20px;
|
|
|
|
|
|
font-size: 18px;
|
|
|
|
|
|
font-weight: 600;
|
|
|
|
|
|
color: #333;
|
|
|
|
|
|
}
|
|
|
|
|
|
/* 选中状态背景色 */
|
|
|
|
|
|
// .treeNode:has(.selected) {
|
|
|
|
|
|
// background-color: #f6faff;
|
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
|
|
::v-deep .el-tree-node {
|
|
|
|
|
|
min-height: 42px;
|
|
|
|
|
|
.el-tree-node__content {
|
|
|
|
|
|
height: 42px;
|
|
|
|
|
|
}
|
2025-03-28 09:51:53 +00:00
|
|
|
|
:not(.is-leaf.el-tree-node__expand-icon) {
|
2025-03-25 09:58:19 +00:00
|
|
|
|
font-size: 16px;
|
2025-03-28 09:51:53 +00:00
|
|
|
|
// color: #333;
|
2025-03-25 09:58:19 +00:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
.topBox {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
flex-direction: row;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
justify-content: space-between;
|
|
|
|
|
|
margin-bottom: 10px;
|
|
|
|
|
|
.topText {
|
|
|
|
|
|
gap: 15px;
|
|
|
|
|
|
font-size: 16px;
|
|
|
|
|
|
font-weight: 600;
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
cursor: pointer;
|
|
|
|
|
|
|
|
|
|
|
|
img {
|
|
|
|
|
|
width: 18px;
|
|
|
|
|
|
height: 18px;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
.topBtn {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
gap: 10px;
|
|
|
|
|
|
i {
|
|
|
|
|
|
cursor: pointer;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
// /* <20><>浮效果 */
|
|
|
|
|
|
// .treeNode:hover {
|
|
|
|
|
|
// background-color: #f5f5f5;
|
|
|
|
|
|
// }
|
|
|
|
|
|
</style>
|