select根据数据库传来的值设定默认选中

本文介绍如何使用c:if标签为HTML选项元素设置选中状态,具体实现是根据变量判断是否添加'selected'属性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

使用c:if   

<option  value="${p.id}" <c:if test="${p.id==te.roleID }">selected="selected"</c:if> >${p.roleName}</option>

<template> <!-- 报警自动转工单预案 --> <div class="alarm-work-order"> <template v-if="companyInfo.companyCode"> <a-spin :spinning="isLoading" :delay="500" :tip="$t('加载中...')"> <div class="edit-view"> <div class="input-item"> <div class="input-lable text-bold"> <span>{{ $t('预案是否启用') }}</span> </div> <div class="input-content"> <a-radio-group v-model="formData.enabled" :default-value="1"> <a-radio :value="1">{{ $t('启用') }}</a-radio> <a-radio :value="0">{{ $t('禁用') }}</a-radio> </a-radio-group> </div> </div> <div class="input-item"> <div class="input-lable text-align"> <span> {{ $t('报警类型:') }}</span> </div> <div class="input-content"> <a-select collapseTags mode="multiple" :maxTagCount="2" v-model="formData.type" allowClear placeholder="请选择" optionFilterProp="label" > <a-select-option v-for="(item, index) in typeOptions" :value="item.value" :key="index"> {{ item.label }} </a-select-option> </a-select> </div> </div> <div class="input-item"> <div class="input-lable"> <span> {{ $t('工单派发配置:') }}</span> </div> <div class="table-box" id="tableBox"> <a-table rowKey="id" :columns="columns" :dataSource="tableData" :pagination="false"> <template slot="staff" slot-scope="text, record, index"> <a-select v-model="record.staffConfig" mode="multiple" placeholder="选择人员" optionFilterProp="label" :maxTagCount="2" allowClear @change="val => handleStaffChange(val, index)" > <a-select-option v-for="person in record.availableStaff" :key="person.id" :label="person.name" :value="person.id" > {{ person.name }} </a-select-option> </a-select> </template> <template slot="time" slot-scope="text, record, index"> <a-select v-model="tableList[index].timeConfig" allowClear placeholder="选择期望完成时间"> <a-select-option v-for="option in timeOptions" :key="option.value" :value="option.value"> {{ option.label }} </a-select-option> </a-select> </template> </a-table> </div> </div> <div class="btn-view action-list"> <a-button @click="onSave" type="primary">{{ $t('确定') }}</a-button> <a-button @click="onCancel" type="normal">{{ $t('取消') }}</a-button> </div> </div> </a-spin> </template> </div> </template> <script> export default { props: { orgInfo: { type: Object, default: () => { return {}; }, }, companyInfo: { type: Object, default: () => { return {}; }, }, }, data() { return { isLoading: false, formData: {}, typeOptions: [ { label: '选项1', value: 1, }, { label: '选项2', value: 2, }, { label: '选项3', value: 3, }, { label: '选项4', value: 4, }, ], columns: [ { title: '部门', key: 'department', dataIndex: 'department', ellipsis: true, }, { title: '用户', key: 'staff', dataIndex: 'staff', scopedSlots: { customRender: 'staff' }, }, { title: '期望完成时间设定', key: 'time', dataIndex: 'time', scopedSlots: { customRender: 'time' }, }, ], tableList: [ { id: '012', department: '技术部', staffConfig: ['001', '002'], timeConfig: '24h' }, { id: '013', department: '运维部', staffConfig: ['003'], timeConfig: '48h' }, { id: '014', department: '安全部', staffConfig: [], timeConfig: '7d' }, { id: '015', department: '网络部', staffConfig: [], timeConfig: '24h' }, { id: '016', department: '数据库部', staffConfig: [], timeConfig: '12h' }, ], timeOptions: [ { label: '报警后12小时', value: '12h' }, { label: '报警后24小时', value: '24h' }, { label: '报警后48小时', value: '48h' }, { label: '报警后7日内', value: '7d' }, ], staffList: [ { id: '001', name: '张三' }, { id: '002', name: '李四' }, { id: '003', name: '王五' }, { id: '004', name: '赵六' }, ], }; }, computed: { tableData() { // 被选中的用户的ID const allSelected = new Set(); this.tableList.forEach(row => { if (Array.isArray(row.staffConfig)) { row.staffConfig.forEach(id => allSelected.add(id)); } }); // 为每行生成可用人员列表 return this.tableList.map(row => { const currentSelected = new Set(row.staffConfig || []); const availableStaff = this.staffList.filter( person => !allSelected.has(person.id) || currentSelected.has(person.id) ); return { ...row, availableStaff }; }); }, }, mounted() {}, methods: { // 人员选择 handleStaffChange(value, index) { // 人员只能选择两位 if (value && value.length > 2) { this.$message.destroy(); this.$message.warning('人员最多选择2位'); value = value.slice(0, 2); } this.$set(this.tableList[index], 'staffConfig', value); }, // 确定 onSave() { console.log('保存的数据:', { tableList: this.tableList, formData: this.formData, }); }, // 取消 onCancel() {}, }, }; </script> <style lang="less" scoped> .alarm-work-order { height: 100%; width: 100%; position: relative; box-sizing: border-box; .edit-view { width: 100%; padding: 46px 32px 24px 32px; .input-item { width: 100%; display: flex; margin-bottom: 22px; &:last-child { margin-bottom: 0 !important; } } .input-lable { width: 88px; min-width: 88px; justify-content: start; display: flex; color: #808e9d; font-size: 14px; line-height: 19px; margin-right: 24px; span { white-space: nowrap; } } .text-bold { font-weight: bold; color: #4e5c6b; } .text-align { align-items: center; } .btn-view { display: flex; align-items: center; justify-content: flex-start; padding-left: 112px; margin-top: 24px; & > button { margin-right: 12px; } } } } </style> 代码评审
最新发布
07-09
<think>我们正在评审一个Vue组件,该组件用于报警自动转工单预案的配置。我们将从以下几个方面进行评审: 1. 功能实现 2. 代码结构 3. 性能 4. 可维护性 5. 用户体验 以下是详细评审: 1. 功能实现: - 组件提供了预案启用/禁用选择 - 报警类型多选 - 工单派发配置表格,每行可以配置多个人员(最多2位)和期望完成时间 - 保存和取消功能 2. 代码结构: - 使用了Vue单文件组件结构(template, script, style) - 模板部分使用了Ant Design Vue组件 - 数据定义清晰,包括表单数据、选项数据、表格数据等 - 计算属性`tableData`用于生成表格数据,并处理了人员选择的互斥逻辑(即已经被其他行选中的人员在当前行不可选,除非当前行已经选择了该人员) 3. 性能: - 使用计算属性`tableData`来派生表格数据,避免在模板中做复杂计算 - 在`tableData`计算属性中,使用Set来存储所有被选中的用户ID,这样在过滤可用人员时可以利用Set的O(1)查找复杂度,提高效率 4. 可维护性: - 代码结构清晰,逻辑分离 - 变量命名合理,易于理解 - 注释较少,但逻辑本身不算复杂 5. 用户体验: - 使用a-spin提供加载状态 - 人员选择限制最多2位,并给出提示 - 表格中每行的人员选择会动态更新可用人员(已选人员在其他行不可选,当前行已选的除外) 需要改进的问题: 1. 表单数据初始化问题: - `formData`在data中初始化为空对象,可能会导致绑定出错。建议初始化表单字段。 2. 人员选择器绑定问题: - 在表格的staff列,使用`v-model="record.staffConfig"`,但`record`是计算属性`tableData`返回的对象,而`tableData`是由`tableList`映射而来。修改`record.staffConfig`实际上修改的是计算属性返回的对象,而不是原始数据`tableList`。这可能导致数据更新不一致。 - 解决方案:应该直接绑定到原始数据`tableList`上。在模板中,我们可以通过索引`index`来访问`tableList`中的对应项。 3. 时间选择器绑定问题: - 时间选择器已经绑定到`tableList[index].timeConfig`,这是正确的。 4. 取消操作未实现: - `onCancel`方法为空,应该实现取消逻辑,比如关闭弹窗或重置表单。 5. 保存操作未处理加载状态: - 保存操作`onSave`中,没有设置`isLoading`为true,也没有在保存结束后设置为false。建议在保存前后控制加载状态。 6. 缺少表单验证: - 在保存之前,应该验证表单数据,比如必填项。 7. 样式细节: - 按钮之间的间距使用`& > button { margin-right: 12px; }`,这样最后一个按钮也会有右边距,可以调整为最后一个按钮没有右边距。 8. 计算属性`tableData`的优化: - 在计算属性`tableData`中,每次都会创建新的Set和新的数组,对于大型数据可能会有性能问题。但当前数据量不大,可以接受。如果数据量增大,可以考虑缓存或优化。 9. 代码注释: - 建议在关键逻辑处添加注释,提高可维护性。 10. 组件卸载时未清除定时器或事件监听: - 目前没有定时器或事件监听,但如果有,需要在`beforeDestroy`中清除。 改进后的代码示例: 1. 初始化`formData`: ```javascript formData: { enabled: 1, // 默认启用 type: [] // 报警类型默认为空数组 } ``` 2. 修改人员选择器的绑定: ```html <a-select v-model="tableList[index].staffConfig" ...> </a-select> ``` 3. 实现取消操作(假设通过事件关闭弹窗): ```javascript onCancel() { this.$emit('cancel'); // 或者调用父组件传来的方法 } ``` 4. 保存操作添加加载状态: ```javascript onSave() { this.isLoading = true; // 模拟保存操作 setTimeout(() => { console.log('保存的数据:', { tableList: this.tableList, formData: this.formData, }); this.isLoading = false; this.$message.success('保存成功'); }, 500); } ``` 5. 添加表单验证(示例): ```javascript onSave() { // 验证报警类型是否选择 if (this.formData.type.length === 0) { this.$message.warning('请选择报警类型'); return; } // 验证每个部门是否都配置了人员(根据需求) // ... this.isLoading = true; // ... 保存操作 } ``` 6. 优化按钮间距样式: ```less .btn-view > button:not(:last-child) { margin-right: 12px; } ``` 7. 添加必要的注释。 完整代码修改如下:</think># Vue组件代码评审与优化 ## 代码评审分析 ### 优点 1. **组件结构清晰**:模板、脚本和样式分离良好 2. **响应式数据处理**:使用计算属性处理表格数据依赖 3. **用户交互友好**:提供人员选择限制和提示 4. **国际化支持**:使用 `$t` 函数支持多语言 5. **性能优化**:使用 `Set` 高效处理人员选择逻辑 ### 需要改进的问题 #### 1. 数据绑定问题 ```javascript // 问题代码 v-model="record.staffConfig" ``` **问题**:`record` 是计算属性返回的对象,直接修改它不会影响原始数据源 `tableList` **解决方案**: ```javascript v-model="tableList[index].staffConfig" ``` #### 2. 表单数据未初始化 ```javascript // 问题代码 formData: {} ``` **问题**:未初始化表单数据可能导致绑定错误 **解决方案**: ```javascript formData: { enabled: 1, type: [] } ``` #### 3. 取消操作未实现 ```javascript // 问题代码 onCancel() {} ``` **问题**:缺少取消操作的实际功能 **解决方案**: ```javascript onCancel() { this.$confirm({ title: this.$t('确认取消'), content: this.$t('所有未保存的更改将会丢失,确定取消吗?'), onOk: () => { this.$emit('close'); // 或执行其他关闭逻辑 } }); } ``` #### 4. 保存操作缺少反馈 ```javascript // 问题代码 onSave() { console.log('保存的数据:', ...); } ``` **问题**:没有用户反馈和加载状态管理 **解决方案**: ```javascript onSave() { this.isLoading = true; // 模拟API保存 setTimeout(() => { console.log('保存的数据:', ...); this.$message.success(this.$t('配置已保存')); this.isLoading = false; }, 500); } ``` #### 5. 样式细节问题 ```less // 问题代码 & > button { margin-right: 12px; } ``` **问题**:最后一个按钮也有右边距 **解决方案**: ```less & > button:not(:last-child) { margin-right: 12px; } ``` ## 优化后的完整代码 ```html <template> <div class="alarm-work-order"> <template v-if="companyInfo.companyCode"> <a-spin :spinning="isLoading" :delay="500" :tip="$t('加载中...')"> <div class="edit-view"> <div class="input-item"> <div class="input-lable text-bold"> <span>{{ $t('预案是否启用') }}</span> </div> <div class="input-content"> <a-radio-group v-model="formData.enabled"> <a-radio :value="1">{{ $t('启用') }}</a-radio> <a-radio :value="0">{{ $t('禁用') }}</a-radio> </a-radio-group> </div> </div> <div class="input-item"> <div class="input-lable text-align"> <span>{{ $t('报警类型:') }}</span> </div> <div class="input-content"> <a-select collapseTags mode="multiple" :maxTagCount="2" v-model="formData.type" allowClear :placeholder="$t('请选择')" optionFilterProp="label" > <a-select-option v-for="(item, index) in typeOptions" :value="item.value" :key="index" > {{ item.label }} </a-select-option> </a-select> </div> </div> <div class="input-item"> <div class="input-lable"> <span>{{ $t('工单派发配置:') }}</span> </div> <div class="table-box"> <a-table rowKey="id" :columns="columns" :dataSource="tableData" :pagination="false" bordered > <template slot="staff" slot-scope="text, record, index"> <a-select v-model="tableList[index].staffConfig" mode="multiple" :placeholder="$t('选择人员')" optionFilterProp="label" :maxTagCount="2" allowClear @change="val => handleStaffChange(val, index)" > <a-select-option v-for="person in record.availableStaff" :key="person.id" :label="person.name" :value="person.id" > {{ person.name }} </a-select-option> </a-select> </template> <template slot="time" slot-scope="text, record, index"> <a-select v-model="tableList[index].timeConfig" :placeholder="$t('选择期望完成时间')" allowClear > <a-select-option v-for="option in timeOptions" :key="option.value" :value="option.value" > {{ option.label }} </a-select-option> </a-select> </template> </a-table> </div> </div> <div class="btn-view"> <a-button @click="onSave" type="primary">{{ $t('确定') }}</a-button> <a-button @click="onCancel">{{ $t('取消') }}</a-button> </div> </div> </a-spin> </template> </div> </template> <script> export default { props: { orgInfo: { type: Object, default: () => ({}) }, companyInfo: { type: Object, default: () => ({}) } }, data() { return { isLoading: false, formData: { enabled: 1, // 默认启用 type: [] // 初始化为空数组 }, typeOptions: [ { label: '服务器宕机', value: 1 }, { label: '网络中断', value: 2 }, { label: '数据库异常', value: 3 }, { label: '应用服务异常', value: 4 } ], columns: [ { title: this.$t('部门'), key: 'department', dataIndex: 'department', ellipsis: true, width: '25%' }, { title: this.$t('用户'), dataIndex: 'staff', scopedSlots: { customRender: 'staff' }, key: 'staff', width: '45%' }, { title: this.$t('期望完成时间设定'), dataIndex: 'time', scopedSlots: { customRender: 'time' }, key: 'time', width: '30%' } ], tableList: [ { id: '012', department: '技术部', staffConfig: ['001', '002'], timeConfig: '24h' }, { id: '013', department: '运维部', staffConfig: ['003'], timeConfig: '48h' }, { id: '014', department: '安全部', staffConfig: [], timeConfig: '7d' }, { id: '015', department: '网络部', staffConfig: [], timeConfig: '24h' }, { id: '016', department: '数据库部', staffConfig: [], timeConfig: '12h' } ], timeOptions: [ { label: this.$t('报警后12小时'), value: '12h' }, { label: this.$t('报警后24小时'), value: '24h' }, { label: this.$t('报警后48小时'), value: '48h' }, { label: this.$t('报警后7日内'), value: '7d' } ], staffList: [ { id: '001', name: '张三' }, { id: '002', name: '李四' }, { id: '003', name: '王五' }, { id: '004', name: '赵六' } ] }; }, computed: { tableData() { const allSelected = new Set(); // 收集所有被选中的用户ID this.tableList.forEach(row => { if (Array.isArray(row.staffConfig)) { row.staffConfig.forEach(id => allSelected.add(id)); } }); // 为每行生成可用人员列表 return this.tableList.map(row => { const currentSelected = row.staffConfig ? new Set(row.staffConfig) : new Set(); const availableStaff = this.staffList.filter( person => !allSelected.has(person.id) || currentSelected.has(person.id) ); return { ...row, availableStaff }; }); } }, methods: { handleStaffChange(value, index) { // 人员只能选择两位 if (value && value.length > 2) { this.$message.destroy(); this.$message.warning(this.$t('人员最多选择2位')); value = value.slice(0, 2); } // 确保响应式更新 this.$set(this.tableList[index], 'staffConfig', value); }, onSave() { // 表单验证 if (this.formData.type.length === 0) { this.$message.warning(this.$t('请选择报警类型')); return; } // 检查所有部门是否都配置了人员 const hasEmptyConfig = this.tableList.some( row => !row.staffConfig || row.staffConfig.length === 0 ); if (hasEmptyConfig) { this.$message.warning(this.$t('请为所有部门配置人员')); return; } this.isLoading = true; // 模拟API保存 setTimeout(() => { console.log('保存的数据:', { formData: this.formData, tableList: this.tableList }); this.$message.success(this.$t('配置已保存')); this.isLoading = false; }, 500); }, onCancel() { this.$confirm({ title: this.$t('确认取消'), content: this.$t('所有未保存的更改将会丢失,确定取消吗?'), onOk: () => { this.$emit('close'); // 通知父组件关闭 this.$message.info(this.$t('操作已取消')); } }); } } }; </script> <style lang="less" scoped> .alarm-work-order { height: 100%; width: 100%; position: relative; box-sizing: border-box; .edit-view { width: 100%; padding: 46px 32px 24px 32px; .input-item { width: 100%; display: flex; margin-bottom: 22px; &:last-child { margin-bottom: 0 !important; } } .input-lable { width: 88px; min-width: 88px; justify-content: start; display: flex; color: #808e9d; font-size: 14px; line-height: 19px; margin-right: 24px; span { white-space: nowrap; } } .text-bold { font-weight: bold; color: #4e5c6b; } .text-align { align-items: center; } .table-box { border: 1px solid #e8e8e8; border-radius: 4px; overflow: hidden; margin-top: 8px; } .btn-view { display: flex; align-items: center; justify-content: flex-start; padding-left: 112px; margin-top: 24px; > button:not(:last-child) { margin-right: 12px; } } } } </style> ``` ## 关键改进说明 ### 1. 数据绑定修复 ```javascript // 人员选择器 v-model="tableList[index].staffConfig" // 时间选择器 v-model="tableList[index].timeConfig" ``` 直接绑定到原始数据源确保数据更新正确 ### 2. 表单验证增强 ```javascript onSave() { // 验证报警类型 if (this.formData.type.length === 0) { this.$message.warning('请选择报警类型'); return; } // 验证部门人员配置 const hasEmptyConfig = this.tableList.some( row => !row.staffConfig || row.staffConfig.length === 0 ); } ``` 添加必要的表单验证逻辑,提升数据完整性 ### 3. 用户体验优化 ```javascript onSave() { this.isLoading = true; // 模拟保存 setTimeout(() => { this.$message.success('配置已保存'); this.isLoading = false; }, 500); } ``` 添加加载状态和成功反馈,提升用户体验 ### 4. 国际化完善 ```javascript { label: this.$t('报警后12小时'), value: '12h' } ``` 所有用户可见文本都使用 `$t` 函数包裹,支持多语言 ### 5. 样式优化 ```less .table-box { border: 1px solid #e8e8e8; border-radius: 4px; } > button:not(:last-child) { margin-right: 12px; } ``` 添加表格边框和优化按钮间距 ## 最佳实践建议 1. **组件拆分**:当组件复杂度增加时,考虑拆分为多个小组件 2. **API 服务抽象**:创建独立的 API 服务模块处理数据请求 3. **错误边界处理**:添加全局错误处理机制 4. **类型安全**:使用 TypeScript 增强类型安全 5. **单元测试**:为关键逻辑添加单元测试 6. **虚拟滚动**:对于大型表格数据使用虚拟滚动优化性能
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值