Commit 83007dea authored by lijin's avatar lijin

增加素材组管理功能

parent 2b9434c0
import request from '@/utils/request'
// 获取所有素材组
export function getAllMaterialGroups() {
return request({
url: `${process.env.PUTIN_API}/material-groups`,
method: 'get'
})
}
// 根据ID获取素材组
export function getMaterialGroupById(id) {
return request({
url: `${process.env.PUTIN_API}/material-groups/${id}`,
method: 'get'
})
}
// 创建素材组
export function createMaterialGroup(data) {
return request({
url: `${process.env.PUTIN_API}/material-groups`,
method: 'post',
data
})
}
// 更新素材组
export function updateMaterialGroup(id, data) {
return request({
url: `${process.env.PUTIN_API}/material-groups/${id}`,
method: 'put',
data
})
}
// 删除素材组
export function deleteMaterialGroup(id) {
return request({
url: `${process.env.PUTIN_API}/material-groups/${id}`,
method: 'delete'
})
}
<template>
<div class="tag-transfer-container">
<el-row :gutter="20">
<!-- 左侧树形结构 -->
<el-col :span="10">
<el-card class="tree-card">
<div slot="header" class="card-header">
<span>可选标签</span>
<div class="search-input">
<el-input
v-model="searchQuery"
placeholder="搜索标签"
prefix-icon="el-icon-search"
clearable
@input="filterTree"
></el-input>
</div>
</div>
<!-- 使用v-if强制重新渲染树组件 -->
<el-tree
v-if="treeKey"
ref="tree"
:key="treeKey"
:data="treeData"
:props="defaultProps"
node-key="id"
show-checkbox
:filter-node-method="filterNode"
:default-checked-keys="selectedKeys"
@check="handleCheck"
>
</el-tree>
</el-card>
</el-col>
<!-- 右侧已选标签 -->
<el-col :span="10">
<el-card class="selected-card">
<div slot="header" class="card-header">
<span>已选标签</span>
<el-button type="text" @click="clearSelected">清空</el-button>
</div>
<div class="selected-tags" v-if="selectedTags.length > 0">
<el-tag
v-for="tag in selectedTags"
:key="tag.id"
closable
@close="removeTag(tag.id)"
class="tag-item"
>
{{ getTagPath(tag) }}
</el-tag>
</div>
<div v-else class="no-data">暂无选中标签</div>
</el-card>
</el-col>
</el-row>
</div>
</template>
<script>
import { getAllMaterialTags } from '@/api/materialTag'
export default {
name: 'TagTransfer',
props: {
value: {
type: Array,
default: () => []
}
},
// 强制组件重新渲染
beforeUpdate() {
console.log('TagTransfer beforeUpdate, value:', this.value)
},
// 添加updated钩子检测值变化
updated() {
console.log('TagTransfer updated, value:', this.value, 'selectedKeys:', this.selectedKeys)
},
data() {
return {
allTags: [],
searchQuery: '',
defaultProps: {
children: 'children',
label: 'name'
},
selectedKeys: [],
tagsMap: {},
treeKey: 1 // 树组件的key,用于强制重新渲染
}
},
computed: {
treeData() {
return this.buildTreeData()
},
selectedTags() {
return this.selectedKeys.map(id => this.tagsMap[id]).filter(Boolean)
}
},
watch: {
value: {
immediate: true,
deep: true,
handler(newVal) {
console.log('TagTransfer value changed:', newVal)
if (!Array.isArray(newVal)) {
console.warn('TagTransfer received non-array value:', newVal)
this.selectedKeys = []
} else {
// 使用JSON序列化确保引用断开
this.selectedKeys = JSON.parse(JSON.stringify(newVal))
}
// 增加treeKey强制树组件重新渲染
this.treeKey++
console.log('强制重新渲染树组件, treeKey:', this.treeKey)
// 等待树组件重新渲染后再设置选中状态
this.$nextTick(() => {
if (this.$refs.tree) {
console.log('Setting checked keys in watcher:', this.selectedKeys)
this.$refs.tree.setCheckedKeys(this.selectedKeys)
}
})
}
}
},
created() {
this.fetchTags()
},
// 组件更新时的生命周期钩子
updated() {
console.log('TagTransfer updated, selectedKeys:', this.selectedKeys)
},
methods: {
// 获取标签数据
fetchTags() {
getAllMaterialTags().then(response => {
if (response.status === 200 && response.result && response.result.data) {
this.allTags = response.result.data
// 创建标签映射关系
this.tagsMap = {}
this.allTags.forEach(tag => {
this.tagsMap[tag.id] = tag
})
// 增加treeKey强制树组件重新渲染
this.treeKey++
console.log('标签加载完成,强制重新渲染树组件, treeKey:', this.treeKey)
// 等待树组件重新渲染后再设置选中状态
this.$nextTick(() => {
if (this.$refs.tree) {
console.log('设置选中标签:', this.selectedKeys)
this.$refs.tree.setCheckedKeys(this.selectedKeys)
}
})
}
}).catch(error => {
console.error('获取标签失败:', error)
this.$message.error('获取标签失败')
})
},
// 构建树形数据
buildTreeData() {
// 根据父子关系构建树
const rootNodes = this.allTags.filter(tag => !tag.parentId)
return this.buildTree(rootNodes)
},
// 递归构建树
buildTree(nodes) {
return nodes.map(node => {
const children = this.allTags.filter(tag => tag.parentId === node.id)
const treeNode = {
id: node.id,
name: node.name,
parentId: node.parentId
}
if (children.length > 0) {
treeNode.children = this.buildTree(children)
}
return treeNode
})
},
// 过滤节点
filterNode(value, data) {
if (!value) return true
return data.name.toLowerCase().includes(value.toLowerCase())
},
// 过滤树
filterTree() {
this.$refs.tree.filter(this.searchQuery)
},
// 处理选中变化
handleCheck(data, checked) {
console.log('树选中变化:', checked)
// 使用JSON序列化确保断开引用
this.selectedKeys = JSON.parse(JSON.stringify(checked.checkedKeys))
// 使用setTimeout确保在当前事件循环结束后触发事件
setTimeout(() => {
this.$emit('input', this.selectedKeys)
this.$emit('change', this.selectedKeys)
}, 0)
},
// 移除标签
removeTag(tagId) {
this.selectedKeys = this.selectedKeys.filter(id => id !== tagId)
// 增加treeKey强制树组件重新渲染
this.treeKey++
// 等待树组件重新渲染后再设置选中状态
this.$nextTick(() => {
if (this.$refs.tree) {
this.$refs.tree.setCheckedKeys(this.selectedKeys)
}
// 使用setTimeout确保在当前事件循环结束后触发事件
setTimeout(() => {
const selectedKeysToEmit = JSON.parse(JSON.stringify(this.selectedKeys))
this.$emit('input', selectedKeysToEmit)
this.$emit('change', selectedKeysToEmit)
}, 0)
})
},
// 清空选中
clearSelected() {
this.selectedKeys = []
// 增加treeKey强制树组件重新渲染
this.treeKey++
// 等待树组件重新渲染后再设置选中状态
this.$nextTick(() => {
if (this.$refs.tree) {
this.$refs.tree.setCheckedKeys([])
}
// 使用setTimeout确保在当前事件循环结束后触发事件
setTimeout(() => {
this.$emit('input', [])
this.$emit('change', [])
}, 0)
})
},
// 获取标签路径
getTagPath(tag) {
if (!tag) return ''
const path = []
let currentTag = tag
while (currentTag) {
path.unshift(currentTag.name)
if (currentTag.parentId) {
currentTag = this.tagsMap[currentTag.parentId]
} else {
break
}
}
return path.join(' / ')
}
}
}
</script>
<style scoped>
.tag-transfer-container {
margin-bottom: 20px;
}
.card-header {
display: flex;
justify-content: space-between;
align-items: center;
}
.search-input {
width: 150px;
}
.tree-card, .selected-card {
height: 400px;
overflow-y: auto;
}
.selected-tags {
display: flex;
flex-wrap: wrap;
gap: 8px;
}
.tag-item {
margin-right: 8px;
margin-bottom: 8px;
}
.no-data {
color: #909399;
text-align: center;
margin-top: 20px;
}
</style>
......@@ -156,6 +156,12 @@ export const constantRouterMap = [
component: () => import('@/views/materialTag'),
meta: { title: '标签管理' }
},
{
path: '/assetManagement/material-group',
name: 'assetManagement.material-group',
component: () => import('@/views/materialGroup'),
meta: { title: '素材组管理' }
},
]
},
......
......@@ -26,10 +26,10 @@
<!-- 带子菜单的导航项 -->
<el-submenu index="4">
<template slot="title">资产管理</template>
<el-menu-item index="/assetManagement/material-group">素材组管理</el-menu-item>
<el-menu-item index="/assetManagement/copywritingLibrary">文案管理</el-menu-item>
<el-menu-item index="/assetManagement/app-group">产品组管理</el-menu-item>
<el-menu-item index="/assetManagement/location-group">地域组管理</el-menu-item>
<el-menu-item index="/assetManagement/createDelivery">素材组</el-menu-item>
<el-menu-item index="/assetManagement/title-group">标题组管理</el-menu-item>
<el-menu-item index="/assetManagement/description-group">描述组管理</el-menu-item>
<el-menu-item index="/assetManagement/material-tag">标签管理</el-menu-item>
......
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment