<think>我们有两个主要任务:
1. 将VHDL和Verilog的复选框改为单选框,并且根据选择过滤规则类别(左侧)和表格数据(右侧)。
2. 修改规则类别多选框为单选效果(每次只能选一个),并且点击某个类别时,表格只显示该类别下的规则,同时给选中的类别项添加背景色,并更改选择框图标为单选框(使用Unocss图标)。
步骤分解:
任务1:VHDL和Verilog改为单选框
- 将原来的两个复选框(el-checkbox)改为单选框(el-radio)或者使用单选框组(el-radio-group)。
- 因为只能选一种语言,所以我们用一个变量(比如`selectedLanguage`)来存储当前选中的语言('VHDL'或'Verilog')。
- 当选择VHDL时,规则类别只显示VHDL相关的类别;选择Verilog时,只显示Verilog相关的类别。
任务2:规则类别改为单选且点击时表格只显示当前类别
- 将规则类别的多选框(el-checkbox)改为单选框(例如使用el-radio或者改变交互方式,但题目要求用多选框改图标,且要求单选效果,所以我们可以使用el-checkbox但通过代码控制每次只选一个,并改变样式)。
- 要求:点击一个类别时,其他类别取消选中,并且表格只显示该类别下的规则。
- 同时,给当前选中的规则类别项添加背景色,并将复选框图标改为单选框图标(使用Unocss图标)。
由于原代码中规则类别是使用el-checkbox循环生成的,并且每个类别有一个checked属性。现在我们要改为单选,那么:
- 我们需要一个变量(例如`selectedCategory`)来记录当前选中的类别名称(或索引)。
- 当点击一个类别时,将该类别的checked设为true,其他设为false。
但是,为了保持与之前的数据结构兼容,我们可以继续使用`ruleCategories`数组,但改变它的使用方式。
具体修改:
1. 将VHDL和Verilog的复选框改为单选框组:
```html
<el-radio-group v-model="selectedLanguage">
<el-radio label="VHDL">VHDL</el-radio>
<el-radio label="Verilog">Verilog</el-radio>
</el-radio-group>
```
并定义`selectedLanguage`,初始值设为'VHDL'。
2. 根据`selectedLanguage`来过滤规则类别(ruleCategories):
我们可以在`ruleCategories`的基础上,根据语言动态显示不同的类别数组。例如,我们可以将规则类别分为两组:
- VHDL类别数组:['VHDL编码规则','VHDL同步设计规则','VHDL标头规则']
- Verilog类别数组:['Verilog编码规则','Verilog同步设计规则', ...] (需要新增模拟数据)
因此,我们需要重新组织规则类别数据,可以定义两个数组,然后根据语言选择显示其中一个。
或者,我们在原始数据中给每个类别增加一个`language`字段,然后通过计算属性来过滤出当前语言对应的类别。
3. 修改规则类别的显示为单选,并改变样式:
- 我们将每个类别的`el-checkbox`改为点击事件,在点击时设置当前类别为选中,其他为未选中。
- 同时,我们给选中的类别添加一个背景色样式(例如`selected-category`),并修改前面的选择框为单选框图标(使用Unocss的图标,这里我们可以用i标签添加类名,比如`i-carbon-radio-button-checked`和`i-carbon-radio-button`)。
4. 修改表格数据的过滤(ruleTable):
- 之前是通过多个选中的类别来过滤,现在改为只通过当前选中的类别(一个)来过滤。
5. 增加模拟数据以满足Verilog的显示。
由于原代码中规则数据(ruleData)只有VHDL的规则,我们需要增加Verilog的规则数据。
具体修改步骤:
步骤1:将语言选择改为单选框组,并定义selectedLanguage。
步骤2:定义规则类别时,我们重构ruleCategories,为每个类别增加language属性,然后根据selectedLanguage过滤显示的类别列表(计算属性)。
步骤3:修改规则类别的显示方式,不再使用v-model绑定checked,而是使用一个变量(selectedCategory)来记录当前选中的类别。当点击某个类别时,设置selectedCategory为该类别,并更新ruleCategories中该类别的checked为true,其他为false(实际上我们不需要在ruleCategories中维护checked,而是根据selectedCategory来判断是否选中)。
步骤4:修改ruleTable的computed属性,使其只根据selectedCategory进行过滤(同时还要考虑语言、搜索关键词等)。
步骤5:为选中的规则类别项添加背景色和单选框图标。
步骤6:增加Verilog的模拟规则数据。
考虑到代码量较大,我们将逐步修改代码。
以下是修改后的完整代码:
</think>我将分析并修改代码以实现您的要求,以下是修改后的完整代码:
```vue
<template>
<div>
<div class="flex justify-between items-center py-4 h-14 px-5">
<PageHeader :title="pageTitle" @back="handlegoback" />
<div class="flex gap-2.5">
<el-button type="default" @click="handlegoback">返回</el-button>
<el-button type="primary" @click="handleSave">保存</el-button>
</div>
</div>
<el-form
:model="customForm"
:rules="customRuleSet"
ref="customFormRef"
label-width="120px"
class="flex gap-5 pt-5 border-t tlinter-border items-center pb-5"
>
<el-form-item label="规则集名称" prop="ruleSetName" class="m-0">
<el-input
v-model="customForm.ruleSetName"
placeholder="请输入1-20位规则集名称"
show-word-limit
class="w-60"
/>
</el-form-item>
<el-text
type="primary"
class="mx-1 text-[#409eff] self-center"
style="padding-bottom: 5px"
>
{{ usedRulesText }}
</el-text>
</el-form>
<div class="flex gap-0 p-5 border-t tlinter-border">
<div class="flex flex-col gap-1 w-1/4 border-r tlinter-border pr-5 h-full">
<div class="w-full h-full">
<el-input
v-model="searchQuery"
placeholder="输入规则编号/描述查询"
class="w-full"
suffix-icon="Search"
clearable
/>
</div>
<!-- 修改为单选框 -->
<div class="flex gap-4" label-width="0">
<el-radio-group v-model="selectedLanguage" @change="handleLanguageChange">
<el-radio label="VHDL" border size="small">VHDL</el-radio>
<el-radio label="Verilog" border size="small">Verilog</el-radio>
</el-radio-group>
</div>
<h1 class="font-inter text-base font-medium leading-[22px] tracking-0 tlinter-text-one pb-2">规则类别</h1>
<div class="flex flex-col gap-3" label-width="0">
<!-- 修改为单选模式 -->
<div
v-for="(category, index) in filteredCategories"
:key="index"
class="flex items-center p-2 rounded-md cursor-pointer transition-colors duration-200"
:class="{'bg-blue-50 border border-blue-200': category.name === selectedCategory}"
@click="selectCategory(category)"
>
<div class="mr-2">
<!-- 使用单选框图标 -->
<div v-if="category.name === selectedCategory" class="i-carbon-checkmark-circle-filled text-blue-500 w-5 h-5"></div>
<div v-else class="i-carbon-circle-dash text-gray-400 w-5 h-5"></div>
</div>
<span class="text-sm">{{ category.name }}</span>
</div>
</div>
</div>
<div class="flex-1 w-3/4 custom-form-item">
<el-table
ref="ruleTableRef"
:data="ruleTable"
style="width: 100%"
row-key="id"
@selection-change="handleSelectionChange"
>
<el-table-column
type="selection"
width="55"
reserve-selection
/>
<el-table-column
width="400"
prop="ruleNo"
label="规则编号"
>
<template #header>
<div class="flex items-center gap-2">
<span>规则编号</span>
<el-select
v-model="headerSelectValue"
:placeholder="selectPlaceholder"
style="width: 120px"
@change="handleHeaderSelectChange"
>
<el-option label="启用" value="enableAll"></el-option>
<el-option label="禁用" value="disableAll"></el-option>
</el-select>
</div>
</template>
<template #default="scope">
<el-text
@click="openDrawer(scope.row)"
class="hover:text-primary cursor-pointer"
:class="activeRowId === scope.row.id ? 'el-text--primary' : ''"
>
{{ scope.row.ruleNo }}
</el-text>
</template>
</el-table-column>
<el-table-column
prop="description"
label="描述"
width="420"
/>
<el-table-column
prop="alarmType"
label="告警类型(点击标签可切换)"
>
<template #default="scope">
<el-tag
:type="getTagType(scope.row.alarmType)"
@click="toggleAlarmType(scope.row)"
:class="scope.row.alarmType === '错误' ? 'tag-pink' : 'tag-yellow'"
>
● {{ scope.row.alarmType }}
</el-tag>
</template>
</el-table-column>
</el-table>
</div>
</div>
<el-drawer
v-model="drawerVisible"
:title="drawerTitle"
size="30%"
:before-close="closeDrawer"
>
<RuleDetails :current-row="currentRow" />
</el-drawer>
</div>
</template>
<script setup>
import { ref, computed, reactive, watch, onMounted, nextTick } from 'vue'
import { useRouter, useRoute } from 'vue-router'
import { Search } from '@element-plus/icons-vue'
import { ElMessage } from 'element-plus'
import RuleDetails from './components/ruleDetails.vue'
import PageHeader from "@/components/PageHeader.vue";
const router = useRouter()
const route = useRoute()
const ruleTableRef = ref(null)
const customFormRef = ref(null)
const headerSelectValue = ref('')
const searchQuery = ref('')
// 修改:使用单选框管理语言选择
const selectedLanguage = ref('VHDL')
// 修改:添加当前选中的类别
const selectedCategory = ref('')
// 抽屉相关
const drawerVisible = ref(false)
const currentRow = ref(null)
const drawerTitle = ref('')
const activeRowId = ref(null)
// 表格选中数据
const selectedRows = ref([])
// 页面标题
const pageTitle = computed(() => {
return route.query.ruleSetName || '自定义规则集'
})
// 表单数据(规则集名称)
const customForm = reactive({
ruleSetName: route.query.ruleSetName || ''
})
// 表单校验规则
const customRuleSet = reactive({
ruleSetName: [
{ required: true, message: '请输入规则集名称', trigger: 'blur' },
{ max: 20, message: '规则集名称不能超过20个字符', trigger: 'blur' }
]
})
// 规则类别(左侧筛选) - 修改:添加语言类型字段
const ruleCategories = ref([
{ name: 'VHDL编码规则', language: 'VHDL' },
{ name: 'VHDL同步设计规则', language: 'VHDL' },
{ name: 'VHDL标头规则', language: 'VHDL' },
{ name: 'Verilog编码规则', language: 'Verilog' },
{ name: 'Verilog时序规则', language: 'Verilog' },
{ name: 'Verilog模块结构规则', language: 'Verilog' },
{ name: 'Verilog命名规则', language: 'Verilog' }
])
// 修改:根据语言过滤类别
const filteredCategories = computed(() => {
return ruleCategories.value.filter(
cat => cat.language === selectedLanguage.value
)
})
// 表格原始数据 - 添加更多模拟数据
const ruleData = ref([
// VHDL规则
{
id: 1,
ruleNo: 'TLR-030001V',
description: 'VHDL源文件应包含头注释',
alarmType: '错误',
category: 'VHDL编码规则',
language: 'VHDL',
enable: true
},
{
id: 2,
ruleNo: 'TLR-030002V',
description: '同步设计应遵循时钟域交叉原则',
alarmType: '告警',
category: 'VHDL同步设计规则',
language: 'VHDL',
enable: true
},
{
id: 3,
ruleNo: 'TLR-030003V',
description: '标头应包含版本、作者等信息',
alarmType: '告警',
category: 'VHDL标头规则',
language: 'VHDL',
enable: false
},
{
id: 4,
ruleNo: 'TLR-030004V',
description: '模块端口声明需指定方向(IN/OUT)',
alarmType: '错误',
category: 'VHDL编码规则',
language: 'VHDL',
enable: true
},
// Verilog规则
{
id: 5,
ruleNo: 'TLR-040001R',
description: 'Verilog模块应有端口声明列表',
alarmType: '错误',
category: 'Verilog编码规则',
language: 'Verilog',
enable: true
},
{
id: 6,
ruleNo: 'TLR-040002R',
description: '时序逻辑必须使用非阻塞赋值',
alarmType: '警告',
category: 'Verilog时序规则',
language: 'Verilog',
enable: true
},
{
id: 7,
ruleNo: 'TLR-040003R',
description: '模块应包含module-endmodule结构',
alarmType: '错误',
category: 'Verilog模块结构规则',
language: 'Verilog',
enable: true
},
{
id: 8,
ruleNo: 'TLR-040004R',
description: '变量命名应使用小写字母加下划线',
alarmType: '警告',
category: 'Verilog命名规则',
language: 'Verilog',
enable: false
},
{
id: 9,
ruleNo: 'TLR-040005R',
description: '避免使用组合逻辑产生锁存器',
alarmType: '错误',
category: 'Verilog时序规则',
language: 'Verilog',
enable: true
}
])
// 过滤后的表格数据 - 修改:添加类别过滤
const ruleTable = computed(() => {
let filteredData = ruleData.value.filter(item =>
item.language === selectedLanguage.value
)
// 如果有选中的类别,则进一步过滤
if (selectedCategory.value) {
filteredData = filteredData.filter(item =>
item.category === selectedCategory.value
)
}
// 搜索过滤
if (searchQuery.value.trim()) {
const keyword = searchQuery.value.trim().toLowerCase()
filteredData = filteredData.filter(item =>
item.ruleNo.toLowerCase().includes(keyword) ||
item.description.toLowerCase().includes(keyword)
)
}
return filteredData
})
const isAllSelectedEnabled = computed(() => {
if (selectedRows.value.length === 0) return false
return selectedRows.value.every(row => row.enable === true)
})
const selectPlaceholder = computed(() => {
return isAllSelectedEnabled.value ? '已启用' : '启用状态'
})
const usedRulesText = computed(() => {
const enabledCount = ruleData.value.filter(rule => rule.enable === true).length
return `已启用${enabledCount}条规则`
})
const getTagType = computed(() => (alarmType) => {
const typeMap = {
'错误': 'danger',
'告警': 'warning'
}
return typeMap[alarmType] || 'info'
})
const handleTableSelection = (tableData) => {
if (!ruleTableRef.value || !tableData || tableData.length === 0) {
return
}
tableData.forEach(row => {
ruleTableRef.value.toggleRowSelection(row, false)
})
tableData.forEach(row => {
if (row.enable) {
ruleTableRef.value.toggleRowSelection(row, true)
}
})
}
// 表格选中事件
const handleSelectionChange = (selection) => {
selectedRows.value = selection
}
// 下拉框操作
const handleHeaderSelectChange = (value) => {
switch (value) {
case 'enableAll':
handleBatchEnable()
break
case 'disableAll':
handleBatchDisable()
break
}
headerSelectValue.value = ''
}
// 批量启用
const handleBatchEnable = () => {
if (selectedRows.value.length === 0) {
ElMessage.warning('请先选择要启用的规则')
return
}
ruleData.value.forEach(row => { row.enable = false })
selectedRows.value.forEach(selectedRow => {
const targetRow = ruleData.value.find(row => row.id === selectedRow.id)
if (targetRow) targetRow.enable = true
})
handleTableSelection(ruleTable.value)
}
// 批量禁用
const handleBatchDisable = () => {
if (selectedRows.value.length === 0) {
ElMessage.warning('请先选择要禁用的规则')
return
}
selectedRows.value.forEach(selectedRow => {
const targetRow = ruleData.value.find(row => row.id === selectedRow.id)
if (targetRow) targetRow.enable = false
})
handleTableSelection(ruleTable.value)
}
// 切换告警类型
const toggleAlarmType = (row) => {
const types = ['错误', '告警']
const currentIdx = types.indexOf(row.alarmType)
row.alarmType = types[(currentIdx + 1) % types.length]
}
// 打开规则详情抽屉
const openDrawer = (row) => {
currentRow.value = row
drawerTitle.value = row.ruleNo
activeRowId.value = row.id
drawerVisible.value = true
}
// 关闭抽屉
const closeDrawer = () => {
currentRow.value = null
drawerTitle.value = ''
activeRowId.value = null
drawerVisible.value = false
}
// 保存规则集
const handleSave = async () => {
const valid = await customFormRef.value.validate()
if (!valid) return
const savedData = {
name: customForm.ruleSetName,
enabledRules: ruleData.value.filter(rule => rule.enable),
totalEnabled: ruleData.value.filter(rule => rule.enable).length,
updateTime: new Date().toLocaleString()
}
console.log('保存规则集数据:', savedData)
ElMessage.success('规则集保存成功')
handlegoback()
}
// 返回上一页
const handlegoback = () => {
router.push("/rules")
}
// 新增:选择规则类别
const selectCategory = (category) => {
// 如果点击已选中的类别,则取消选择
if (selectedCategory.value === category.name) {
selectedCategory.value = ''
} else {
selectedCategory.value = category.name
}
}
// 新增:处理语言变更
const handleLanguageChange = () => {
// 切换语言时重置选中的类别
selectedCategory.value = ''
}
// 监听表格数据变化
watch(
() => ruleTable.value,
(newTableData) => {
handleTableSelection(newTableData)
},
{ immediate: true, deep: true }
)
// 监听选中数据变化
watch(
() => selectedRows.value,
(newSelected) => {
if (isAllSelectedEnabled.value) {
headerSelectValue.value = 'enableAll'
} else {
const validActions = ['enableAll', 'disableAll']
if (!validActions.includes(headerSelectValue.value)) {
headerSelectValue.value = ''
}
}
},
{ deep: true }
)
// 组件挂载完成后,确保表格选中状态初始化
onMounted(async () => {
await nextTick()
handleTableSelection(ruleTable.value)
})
</script>
<style scoped lang="scss">
:deep(.custom-form-item .el-form-item__content) {
margin-left: 20px !important;
}
// 抽屉样式调整
:deep(.el-drawer__header) {
margin-bottom: 0px !important;
padding: 16px 24px !important;
border-bottom: 1px solid #eee;
}
// 新增样式:语言选择组
.radio-group-container {
display: flex;
gap: 16px;
margin-bottom: 16px;
}
// 新增样式:类别项
.category-item {
display: flex;
align-items: center;
padding: 8px 12px;
border-radius: 6px;
margin-bottom: 8px;
cursor: pointer;
transition: background-color 0.2s;
&:hover {
background-color: #f5f7fa;
}
&.selected {
background-color: #ecf5ff;
border: 1px solid #d9ecff;
}
.radio-icon {
margin-right: 10px;
width: 20px;
height: 20px;
display: flex;
align-items: center;
justify-content: center;
}
}
</style>
```
### 修改内容详解:
1. **VHDL/Verilog改为单选框**:
- 将原来的两个复选框改为单选框组(`el-radio-group`)
- 添加 `selectedLanguage` 响应式变量(默认为'VHDL')
- 新增 `handleLanguageChange` 方法处理语言变更事件,切换语言时重置类别选择
2. **规则类别单选功能**:
- 移除原来的多选框,改为点击选择模式
- 添加 `selectedCategory` 响应式变量存储当前选中的类别
- 新增 `selectCategory` 方法处理类别选择逻辑