|
|
@@ -1,127 +1,246 @@
|
|
|
<template>
|
|
|
<el-row :gutter="20">
|
|
|
<!-- 左侧树形结构 -->
|
|
|
- <el-col :span="6">
|
|
|
+ <el-col :span="3">
|
|
|
<el-card shadow="never">
|
|
|
<div class="header">
|
|
|
<span>分类树</span>
|
|
|
- <el-button type="primary" size="small" class="add-btn">添加根分类</el-button>
|
|
|
+ <el-button class="add-btn" size="small" type="primary" @click="addcategory">添加根分类</el-button>
|
|
|
</div>
|
|
|
- <el-tree :data="treeData" :props="treeProps" node-key="id" highlight-current @node-click="handleNodeClick" />
|
|
|
+ <el-divider></el-divider>
|
|
|
+ <el-tree ref="treeRef" :data="treeData" :props="treeProps" :render-content="renderTreeContent"
|
|
|
+ :row-style="{height:'100px'}"
|
|
|
+ highlight-current node-key="id" @node-click="handleNodeClick"/>
|
|
|
</el-card>
|
|
|
+ <!-- 树形结构下方按钮 -->
|
|
|
+ <div style="margin-top: 10px; display: flex; justify-content: space-between;">
|
|
|
+ <el-button size="default" @click="expandAll">展开所有</el-button>
|
|
|
+ <el-button size="default" @click="collapseAll">折叠所有</el-button>
|
|
|
+ </div>
|
|
|
</el-col>
|
|
|
|
|
|
<!-- 中间表单区域 -->
|
|
|
- <el-col :span="18">
|
|
|
+ <el-col :span="21">
|
|
|
<el-card shadow="never">
|
|
|
- <h3>编辑分类</h3>
|
|
|
- <el-form :model="form" label-width="120px">
|
|
|
- <el-form-item label="分类名称">
|
|
|
- <el-input v-model="form.name" />
|
|
|
- </el-form-item>
|
|
|
- <el-form-item label="分类编码">
|
|
|
- <el-input v-model="form.code" />
|
|
|
- </el-form-item>
|
|
|
- <el-form-item label="父级分类">
|
|
|
- <el-select v-model="form.parentId" placeholder="请选择父级分类">
|
|
|
- <el-option label="无(根分类)" value="1" />
|
|
|
- </el-select>
|
|
|
+ <div style="display: flex;justify-content: space-between">
|
|
|
+ <h3>{{ addOrEdit }}分类</h3>
|
|
|
+ <el-tag round effect="light">ID:{{form.id}}</el-tag>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <el-form ref="formvalidate" :model="form" :rules="rules" label-position="top" label-width="120px">
|
|
|
+ <el-form-item label="分类名称" prop="name">
|
|
|
+ <el-input v-model="form.name"/>
|
|
|
</el-form-item>
|
|
|
- <el-form-item label="排序顺序">
|
|
|
- <el-input-number v-model="form.sort" :min="1" />
|
|
|
+ <el-form-item label="分类编码" prop="code">
|
|
|
+ <el-input v-model="form.code"/>
|
|
|
+ <div>
|
|
|
+ <span style="color: #777777">分类编码 用于系统标识,只能包含字母,数字和连字符</span>
|
|
|
+ </div>
|
|
|
</el-form-item>
|
|
|
- <el-form-item label="分类描述">
|
|
|
- <el-input v-model="form.description" type="textarea" />
|
|
|
+ <el-row :gutter="20">
|
|
|
+ <el-col :span="12">
|
|
|
+ <el-form-item label="父级分类" prop="parentId">
|
|
|
+ <el-select v-model="form.parentId" placeholder="请选择父级分类">
|
|
|
+ <el-option label="无(根分类)" :value="1"/>
|
|
|
+ </el-select>
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ <el-col :span="12">
|
|
|
+ <el-form-item label="排序顺序" prop="sort">
|
|
|
+ <el-input v-model="form.sort" :min="1" style="width: 100%;"/>
|
|
|
+ <div style="color: #999; font-size: 14px; margin-top: 5px;">数值越小排序越靠前</div>
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ </el-row>
|
|
|
+ <el-form-item label="分类描述" prop="description">
|
|
|
+ <el-input v-model="form.description" type="textarea"/>
|
|
|
</el-form-item>
|
|
|
</el-form>
|
|
|
<!-- 关键词提示模块 -->
|
|
|
<div style="color: #777777">关键词提示词</div>
|
|
|
<div class="keyword-box" style="display: flex">
|
|
|
<div class="keyword-content" style="margin-top: 20px;margin-bottom: 20px;margin-left: 20px">
|
|
|
- <span >该分类下共有 {{ templateCount }} 个提示词模板</span><br>
|
|
|
- <el-button type="plain" size="small" @click="viewKeywords" style="margin-top: 10px ">查看关联提示词</el-button>
|
|
|
+ <span>该分类下共有 {{ templateCount }} 个提示词模板</span><br>
|
|
|
+ <el-button plain size="small" style="margin-top: 10px " @click="viewKeywords">查看关联提示词</el-button>
|
|
|
</div>
|
|
|
</div>
|
|
|
<div class="form-footer">
|
|
|
- <el-button type="danger">删除分类</el-button>
|
|
|
+ <el-button v-show="showdeletebutton" type="danger" @click="deletecategory">删除分类</el-button>
|
|
|
<div class="right-btns">
|
|
|
<el-button>取消</el-button>
|
|
|
- <el-button type="primary">保存</el-button>
|
|
|
+ <el-button type="primary" @click="saveform(formvalidate)">{{ saveoradd }}</el-button>
|
|
|
</div>
|
|
|
</div>
|
|
|
</el-card>
|
|
|
</el-col>
|
|
|
</el-row>
|
|
|
+
|
|
|
</template>
|
|
|
|
|
|
-<script setup>
|
|
|
-import { ref } from 'vue';
|
|
|
-// import {PromptModel} from '/src/api/promptwordManagement/types.js'
|
|
|
-import {getPromptById} from '/src/api/promptwordManagement/promptpage.js'
|
|
|
-import {onMounted} from "vue";
|
|
|
+<script lang="ts" setup>
|
|
|
+import {ref} from 'vue';
|
|
|
+import {PromptModel} from '@/api/promptwordManagement/types'
|
|
|
+import {getPromptById, addPromptCategory, putPromptCategory,deletePromptCategory} from '@/api/promptwordManagement/promptpage.js'
|
|
|
+import {onMounted} from "vue";
|
|
|
+import {ElMessage} from "element-plus/es";
|
|
|
+import type {FormInstance, FormRules} from 'element-plus'
|
|
|
+import {Document, Folder} from '@element-plus/icons-vue';
|
|
|
|
|
|
-const templateCount=ref(5)
|
|
|
+const showaddpromptcategory = ref(false)
|
|
|
+const templateCount = ref(5)
|
|
|
+const saveoradd = ref('保存')
|
|
|
+const showdeletebutton = ref(false)
|
|
|
+const addOrEdit = ref('新增')
|
|
|
+let form_add = reactive<PromptModel>({
|
|
|
+ id: 0,
|
|
|
+ name: '',
|
|
|
+ code: '',
|
|
|
+ description: '',
|
|
|
+ parentId: 0,
|
|
|
+ sortOrder: 0,
|
|
|
+ createdAt: ''
|
|
|
+})
|
|
|
const treeData = ref([
|
|
|
{
|
|
|
id: 1,
|
|
|
- label: '内容创作',
|
|
|
+ name: '内容创作',
|
|
|
+ code: '123',
|
|
|
+ description: '简单介绍',
|
|
|
+ parentid: '0',
|
|
|
+ sortOrder: '1',
|
|
|
children: [
|
|
|
- { id: 2, label: '文案撰写' },
|
|
|
- { id: 3, label: '文章生成' }
|
|
|
+ {
|
|
|
+ id: 2,
|
|
|
+ name: '内容创作',
|
|
|
+ code: '123',
|
|
|
+ description: '简单介绍',
|
|
|
+ parentid: '0',
|
|
|
+ sortOrder: '1',
|
|
|
+ },
|
|
|
+ {
|
|
|
+ id: 3,
|
|
|
+ name: '内容创作',
|
|
|
+ code: '123',
|
|
|
+ description: '简单介绍',
|
|
|
+ parentid: '0',
|
|
|
+ sortOrder: '1',
|
|
|
+ }
|
|
|
]
|
|
|
},
|
|
|
{
|
|
|
id: 4,
|
|
|
- label: '知识问答',
|
|
|
+ name: '通用回答',
|
|
|
+ code: '123',
|
|
|
+ description: '简单介绍',
|
|
|
+ parentid: '0',
|
|
|
+ sortOrder: '1',
|
|
|
children: [
|
|
|
- { id: 5, label: '通用回答' },
|
|
|
- { id: 6, label: '专业回答' }
|
|
|
+ {
|
|
|
+ id: 5,
|
|
|
+ name: '通用回答',
|
|
|
+ code: '123',
|
|
|
+ description: '简单介绍',
|
|
|
+ parentid: '0',
|
|
|
+ sortOrder: '1',
|
|
|
+ },
|
|
|
+ {
|
|
|
+ id: 6,
|
|
|
+ name: '专业回答',
|
|
|
+ code: '123',
|
|
|
+ description: '简单介绍',
|
|
|
+ parentid: '0',
|
|
|
+ sortOrder: '2',
|
|
|
+ }
|
|
|
]
|
|
|
},
|
|
|
- {
|
|
|
- id: 7,
|
|
|
- label: '代码助手',
|
|
|
- children: [
|
|
|
- { id: 7, label: '代码生成' },
|
|
|
- { id: 9, label: '代码解释' },
|
|
|
- { id:10, label: 'Bug修复'}
|
|
|
- ]
|
|
|
- },
|
|
|
- {
|
|
|
- id: 11,
|
|
|
- label: '聊天对话',
|
|
|
- children: [
|
|
|
|
|
|
- ]
|
|
|
- },
|
|
|
- {
|
|
|
- id: 12,
|
|
|
- label: '系统提示词',
|
|
|
- children: [
|
|
|
|
|
|
- ]
|
|
|
- }
|
|
|
])
|
|
|
|
|
|
const treeProps = {
|
|
|
children: 'children',
|
|
|
- label: 'label'
|
|
|
+ label: 'name'
|
|
|
}
|
|
|
-
|
|
|
+const addcategory = () => {
|
|
|
+ saveoradd.value = '添加'
|
|
|
+ addOrEdit.value = '新增'
|
|
|
+ showdeletebutton.value = false
|
|
|
+ formvalidate.value.resetFields()
|
|
|
+}
|
|
|
+const viewKeywords = ref()
|
|
|
const form = ref({
|
|
|
+ id:null,
|
|
|
name: '',
|
|
|
code: '',
|
|
|
parentId: '',
|
|
|
- sort: 1,
|
|
|
+ sort: null,
|
|
|
description: ''
|
|
|
})
|
|
|
+const rules = reactive<FormRules<PromptModel>>({
|
|
|
+ name: [
|
|
|
+ {required: true, message: '分类名称不能为空', trigger: 'blur'}
|
|
|
+ ],
|
|
|
+ code: [
|
|
|
+ {required: true, message: '分类编码不能为空', trigger: 'blur'}
|
|
|
+ ],
|
|
|
+ parentId: [
|
|
|
+ {required: true, message: '父分类不能为空', trigger: 'blur'}
|
|
|
+ ],
|
|
|
+ description: [
|
|
|
+ {required: true, message: '分类描述不能为空', trigger: 'blur'}
|
|
|
+ ],
|
|
|
+ sort: [
|
|
|
+ {required: true, message: '排序顺序不能为空', trigger: 'blur'}
|
|
|
+ ]
|
|
|
+})
|
|
|
+const formvalidate = ref<FormInstance>()
|
|
|
+const saveform = async (formvalidate: FormInstance | undefined) => {
|
|
|
+ // if (!formEl)return
|
|
|
+ const valid = await formvalidate.validate()
|
|
|
+ try {
|
|
|
+ if (valid) {
|
|
|
+ console.log('校验通过')
|
|
|
+ if (addOrEdit.value === '新增') {
|
|
|
+ await addPromptCategory(form.value)
|
|
|
+ } else {
|
|
|
+ await putPromptCategory(form.value)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } catch (error) {
|
|
|
+ ElMessage.error("出错了!")
|
|
|
+ console.log('出错:', error)
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+const renderTreeContent = (h, {node, data}) => {
|
|
|
+ const isFolder = !data.isLeaf;
|
|
|
+ return h(
|
|
|
+ 'span',
|
|
|
+ {
|
|
|
+ style: {
|
|
|
+ display: 'flex',
|
|
|
+ alignItems: 'center'
|
|
|
+ }
|
|
|
+ },
|
|
|
+ [
|
|
|
+ h(ElIcon, {style: {marginRight: '6px'}}, () => isFolder ? h(Folder) : h(Document)),
|
|
|
+ h('span', null, node.label)
|
|
|
+ ]
|
|
|
+ );
|
|
|
+}
|
|
|
+
|
|
|
function handleNodeClick(data, node) {
|
|
|
+ addOrEdit.value = '编辑'
|
|
|
+ saveoradd.value = '保存'
|
|
|
+ showdeletebutton.value = true
|
|
|
const parent = node.parent
|
|
|
|
|
|
- if (parent&&parent.level>0) {
|
|
|
+ if (parent && parent.level > 0) {
|
|
|
// ✅ 如果有父节点,把它的 id 设置为 form.parentId
|
|
|
form.value.parentId = parent.data.id
|
|
|
- console.log('父节点ID为:', parent.data.id)
|
|
|
} else {
|
|
|
// 如果没有父节点(顶级节点),parentId 设为 null 或 ''
|
|
|
form.value.parentId = '无(根分类)'
|
|
|
@@ -129,45 +248,125 @@ function handleNodeClick(data, node) {
|
|
|
}
|
|
|
|
|
|
// 其他表单字段可选填充
|
|
|
- form.value.name = data.label
|
|
|
+ form.value.id=data.id
|
|
|
+ form.value.name = data.name
|
|
|
+ form.value.code = data.code
|
|
|
+ form.value.description = data.description
|
|
|
+ form.value.sort=data.sortOrder
|
|
|
}
|
|
|
-const getData=async ()=>{
|
|
|
- const data=await getPromptById(1)
|
|
|
- const res=data.data
|
|
|
- console.log('获得返回数据',res)
|
|
|
|
|
|
+
|
|
|
+const treeRef = ref() // 用于获取 el-tree 实例
|
|
|
+
|
|
|
+// 展开所有节点
|
|
|
+const expandAll = () => {
|
|
|
+ const tree = treeRef.value
|
|
|
+ if (tree) {
|
|
|
+ // 设置所有节点为展开状态
|
|
|
+ treeData.value.forEach(node => {
|
|
|
+ tree.store.nodesMap[node.id].expanded = true
|
|
|
+ })
|
|
|
+ }
|
|
|
}
|
|
|
-console.log("组件被调用了")
|
|
|
-onMounted(()=>{
|
|
|
- getData();
|
|
|
+
|
|
|
+// 折叠所有节点(只显示根节点)
|
|
|
+const collapseAll = () => {
|
|
|
+ const tree = treeRef.value
|
|
|
+ if (tree) {
|
|
|
+ // 设置所有节点为折叠状态
|
|
|
+ treeData.value.forEach(node => {
|
|
|
+ tree.store.nodesMap[node.id].expanded = false
|
|
|
+ })
|
|
|
+ }
|
|
|
+}
|
|
|
+// 递归删除节点
|
|
|
+const removeNode = (nodes, id) => {
|
|
|
+ for (let i = 0; i < nodes.length; i++) {
|
|
|
+ if (nodes[i].id === id) {
|
|
|
+ // 找到节点,从数组中移除
|
|
|
+ nodes.splice(i, 1);
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ if (nodes[i].children && nodes[i].children.length) {
|
|
|
+ const found = removeNode(nodes[i].children, id);
|
|
|
+ if (found) return true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return false;
|
|
|
+};
|
|
|
+const deletecategory = async () => {
|
|
|
+ const nodeIdToDelete = form.value.id;
|
|
|
+
|
|
|
+ if (!nodeIdToDelete) {
|
|
|
+ ElMessage.warning('请选择一个分类进行删除');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ try {
|
|
|
+ await deletePromptCategory(nodeIdToDelete); // 调用接口删除
|
|
|
+ const deleted = removeNode(treeData.value, nodeIdToDelete);
|
|
|
+ if (deleted) {
|
|
|
+ ElMessage.success('删除成功');
|
|
|
+ form.value = {
|
|
|
+ id: null,
|
|
|
+ name: '',
|
|
|
+ code: '',
|
|
|
+ parentId: '',
|
|
|
+ sort: null,
|
|
|
+ description: ''
|
|
|
+ };
|
|
|
+ addOrEdit.value = '新增';
|
|
|
+ saveoradd.value = '添加';
|
|
|
+ showdeletebutton.value = false;
|
|
|
+ }
|
|
|
+ } catch (error) {
|
|
|
+ ElMessage.error('删除失败,请重试');
|
|
|
+ console.error('删除失败:', error);
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+
|
|
|
+onMounted(() => {
|
|
|
+ // getData();
|
|
|
})
|
|
|
|
|
|
</script>
|
|
|
|
|
|
<style scoped>
|
|
|
-.keyword-content{
|
|
|
+.keyword-content {
|
|
|
margin-top: 10px;
|
|
|
}
|
|
|
-.keyword-box{
|
|
|
+
|
|
|
+.keyword-box {
|
|
|
background-color: #F5F7FA;
|
|
|
}
|
|
|
+
|
|
|
.header {
|
|
|
display: flex;
|
|
|
justify-content: space-between;
|
|
|
align-items: center;
|
|
|
margin-bottom: 10px;
|
|
|
}
|
|
|
+
|
|
|
.add-btn {
|
|
|
font-size: 12px;
|
|
|
}
|
|
|
+
|
|
|
.form-footer {
|
|
|
display: flex;
|
|
|
justify-content: space-between;
|
|
|
align-items: center;
|
|
|
margin-top: 20px;
|
|
|
}
|
|
|
+
|
|
|
.right-btns {
|
|
|
display: flex;
|
|
|
gap: 10px;
|
|
|
+ margin-left: auto;
|
|
|
+}
|
|
|
+
|
|
|
+.custom-tree-node {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
}
|
|
|
</style>
|