调整设备点检项目左右布局
Some checks failed
Release pipeline / Always run job (push) Has been cancelled
Release pipeline / publish (push) Has been cancelled

This commit is contained in:
sheng
2026-06-26 15:33:54 +08:00
parent 71a721989a
commit b52919aab4
3 changed files with 239 additions and 68 deletions

View File

@@ -1096,7 +1096,10 @@
"disabled": "Disabled", "disabled": "Disabled",
"please_select_status": "Please select status", "please_select_status": "Please select status",
"import_file": "Import File", "import_file": "Import File",
"duplicate_import_name": "Inspection item name {name} is duplicated. Remove duplicates and upload again." "duplicate_import_name": "Inspection item name {name} is duplicated. Remove duplicates and upload again.",
"enter_device_category_name": "Enter device category name",
"current_device_category": "Current Device Category",
"no_data": "No Data"
}, },
"inspection_records": { "inspection_records": {
"search": "Search", "search": "Search",

View File

@@ -1096,7 +1096,10 @@
"disabled": "禁用", "disabled": "禁用",
"please_select_status": "请选择状态", "please_select_status": "请选择状态",
"import_file": "数据导入表格", "import_file": "数据导入表格",
"duplicate_import_name": "【{name}】项目名称存在重复值,请去掉重复值并重新上传" "duplicate_import_name": "【{name}】项目名称存在重复值,请去掉重复值并重新上传",
"enter_device_category_name": "请输入设备类别名称",
"current_device_category": "当前设备类别",
"no_data": "无数据"
}, },
"inspection_records": { "inspection_records": {
"search": "查询", "search": "查询",

View File

@@ -1,13 +1,46 @@
<template> <template>
<d2-container> <d2-container>
<template #header> <div class="inspection-items-page">
<aside class="category-panel" v-loading="treeLoading">
<el-input
v-model.trim="categoryFilter"
size="mini"
:placeholder="$t(key('enter_device_category_name'))"
clearable
class="category-filter"
/>
<el-tree
v-if="deviceCategoryTree.length"
ref="categoryTree"
:data="deviceCategoryTree"
show-checkbox
highlight-current
default-expand-all
node-key="id"
:expand-on-click-node="false"
:default-checked-keys="currentCategoryId ? [currentCategoryId] : []"
:current-node-key="currentCategoryId"
:filter-node-method="filterCategoryNode"
@node-click="handleCategoryClick"
@check-change="handleCategoryCheckChange"
>
<template #default="{ node, data }">
<span class="category-node">
<span>{{ node.label }}</span>
<span class="category-code">({{ data.code || '-' }})</span>
</span>
</template>
</el-tree>
<el-result v-else icon="info" :title="$t(key('no_data'))" sub-title="" />
</aside>
<section class="items-panel">
<div class="items-context">
<span class="context-label">{{ $t(key('current_device_category')) }}</span>
<strong>{{ currentCategoryLabel || '-' }}</strong>
</div>
<div class="search-bar"> <div class="search-bar">
<el-form :inline="true" :model="search" size="mini"> <el-form :inline="true" :model="search" size="mini">
<el-form-item :label="$t(key('device_category'))">
<el-select v-model="search.device_category_id" :placeholder="$t(key('please_select_device_category'))" clearable filterable style="width:200px">
<el-option v-for="item in deviceCategoryOptions" :key="item.value" :label="item.label" :value="item.value" />
</el-select>
</el-form-item>
<el-form-item :label="$t(key('inspection_item_name'))"> <el-form-item :label="$t(key('inspection_item_name'))">
<el-input v-model.trim="search.name" :placeholder="$t(key('enter_inspection_item_name'))" clearable style="width:200px" @keyup.enter.native="onSearch" /> <el-input v-model.trim="search.name" :placeholder="$t(key('enter_inspection_item_name'))" clearable style="width:200px" @keyup.enter.native="onSearch" />
</el-form-item> </el-form-item>
@@ -29,7 +62,6 @@
</el-form-item> </el-form-item>
</el-form> </el-form>
</div> </div>
</template>
<page-table <page-table
ref="pageTable" ref="pageTable"
@@ -49,6 +81,8 @@
</el-tag> </el-tag>
</template> </template>
</page-table> </page-table>
</section>
</div>
<page-dialog-form <page-dialog-form
ref="dialogForm" ref="dialogForm"
@@ -70,7 +104,7 @@
<el-alert :title="$t(key('import_tip'))" type="warning" :closable="false" /> <el-alert :title="$t(key('import_tip'))" type="warning" :closable="false" />
<el-form size="mini" label-width="130px" class="import-form"> <el-form size="mini" label-width="130px" class="import-form">
<el-form-item :label="$t(key('device_category'))" required> <el-form-item :label="$t(key('device_category'))" required>
<el-select v-model="importDeviceCategoryId" :placeholder="$t(key('please_select_device_category'))" clearable filterable style="width:260px"> <el-select v-model="importDeviceCategoryId" :placeholder="$t(key('please_select_device_category'))" disabled style="width:260px">
<el-option v-for="item in deviceCategoryOptions" :key="item.value" :label="item.label" :value="item.value" /> <el-option v-for="item in deviceCategoryOptions" :key="item.value" :label="item.label" :value="item.value" />
</el-select> </el-select>
</el-form-item> </el-form-item>
@@ -118,8 +152,16 @@ function readPageData (res) {
return { list: [], total: 0 } return { list: [], total: 0 }
} }
function toOptions (list) { function normalizeCategories (list) {
return (Array.isArray(list) ? list : []).map(item => ({ label: item.name || item.label, value: item.id || item.value, raw: item })) return (Array.isArray(list) ? list : []).map((item, index) => ({
id: item.id || item.value,
value: item.id || item.value,
label: item.name || item.label,
name: item.name || item.label,
code: item.code || '',
index,
children: []
}))
} }
export default { export default {
@@ -129,11 +171,16 @@ export default {
data () { data () {
return { return {
loading: false, loading: false,
treeLoading: false,
submitting: false, submitting: false,
tableData: [], tableData: [],
selectedRows: [], selectedRows: [],
categoryFilter: '',
deviceCategoryTree: [],
deviceCategoryOptions: [], deviceCategoryOptions: [],
search: { device_category_id: '', name: '', check_method: '', standard: '', unit: '', create_time: [] }, currentCategoryId: '',
currentCategory: null,
search: { name: '', check_method: '', standard: '', unit: '', create_time: [] },
pagination: { current: 1, size: 10, total: 0 }, pagination: { current: 1, size: 10, total: 0 },
dialogVisible: false, dialogVisible: false,
dialogTitle: '', dialogTitle: '',
@@ -160,11 +207,15 @@ export default {
} }
}, },
computed: { computed: {
currentCategoryLabel () {
if (!this.currentCategory) return ''
return `${this.currentCategory.label}${this.currentCategory.code ? ` (${this.currentCategory.code})` : ''}`
},
formCols () { formCols () {
return [ return [
[ [
{ type: 'input', prop: 'name', label: this.key('inspection_item_name'), placeholder: this.key('enter_inspection_item_name'), style: { width: '100%' } }, { type: 'input', prop: 'name', label: this.key('inspection_item_name'), placeholder: this.key('enter_inspection_item_name'), style: { width: '100%' } },
{ type: 'select', prop: 'device_category_id', label: this.key('device_category'), placeholder: this.key('please_select_device_category'), options: this.deviceCategoryOptions, style: { width: '100%' } } { type: 'select', prop: 'device_category_id', label: this.key('device_category'), placeholder: this.key('please_select_device_category'), options: this.deviceCategoryOptions, disabled: true, style: { width: '100%' } }
], ],
[ [
{ type: 'select', prop: 'status', label: this.key('status'), placeholder: this.key('please_select_status'), options: [{ label: this.$t(this.key('enabled')), value: 1 }, { label: this.$t(this.key('disabled')), value: 0 }], style: { width: '100%' } }, { type: 'select', prop: 'status', label: this.key('status'), placeholder: this.key('please_select_status'), options: [{ label: this.$t(this.key('enabled')), value: 1 }, { label: this.$t(this.key('disabled')), value: 0 }], style: { width: '100%' } },
@@ -182,11 +233,15 @@ export default {
] ]
} }
}, },
watch: {
categoryFilter (val) {
if (this.$refs.categoryTree) this.$refs.categoryTree.filter(val)
}
},
created () { created () {
this.columns = useTableColumns([ this.columns = useTableColumns([
{ prop: 'sort', label: this.key('sort'), width: 80 }, { prop: 'sort', label: this.key('sort'), width: 80 },
{ prop: 'name', label: this.key('inspection_item_name'), minWidth: 150 }, { prop: 'name', label: this.key('inspection_item_name'), minWidth: 150 },
{ prop: 'device_category_name', label: this.key('device_category'), minWidth: 140 },
{ prop: 'status', label: this.key('status'), slot: 'status', width: 100 }, { prop: 'status', label: this.key('status'), slot: 'status', width: 100 },
{ prop: 'standard', label: this.key('standard'), minWidth: 140, showOverflowTooltip: true }, { prop: 'standard', label: this.key('standard'), minWidth: 140, showOverflowTooltip: true },
{ prop: 'check_method', label: this.key('check_method'), minWidth: 140, showOverflowTooltip: true }, { prop: 'check_method', label: this.key('check_method'), minWidth: 140, showOverflowTooltip: true },
@@ -212,22 +267,66 @@ export default {
this.toolbarButtons = btns.toolbarButtons this.toolbarButtons = btns.toolbarButtons
this.rowButtons = btns.rowButtons this.rowButtons = btns.rowButtons
this.loadDeviceCategories() this.loadDeviceCategories()
this.fetchData()
}, },
methods: { methods: {
emptyForm () { emptyForm () {
return { name: '', device_category_id: '', status: 1, standard: '', check_method: '', unit: '', frequentness: '', example: '', remark: '' } return { name: '', device_category_id: '', status: 1, standard: '', check_method: '', unit: '', frequentness: '', example: '', remark: '' }
}, },
async loadDeviceCategories () { async loadDeviceCategories () {
const res = await getEquipmentCategoryALL({}) this.treeLoading = true
this.deviceCategoryOptions = toOptions((res && res.data) || res) try {
const res = await getEquipmentCategoryALL({ no_denglu_sign: 'no' })
const list = normalizeCategories((res && res.data) || res)
this.deviceCategoryTree = list
this.deviceCategoryOptions = list.map(item => ({ label: item.label, value: item.id, raw: item }))
if (list.length) {
this.setCurrentCategory(list[0], false)
this.$nextTick(() => {
if (this.$refs.categoryTree) {
this.$refs.categoryTree.setCheckedKeys([this.currentCategoryId])
this.$refs.categoryTree.setCurrentKey(this.currentCategoryId)
}
})
this.fetchData()
}
} finally {
this.treeLoading = false
}
},
setCurrentCategory (category, shouldFetch = true) {
this.currentCategory = category
this.currentCategoryId = category ? category.id : ''
this.selectedRows = []
this.pagination.current = 1
if (shouldFetch) this.fetchData()
},
filterCategoryNode (value, data) {
if (!value) return true
const text = String(value).toLowerCase()
return String(data.label || '').toLowerCase().includes(text) || String(data.code || '').toLowerCase().includes(text)
},
handleCategoryClick (data) {
this.setCurrentCategory(data)
this.$nextTick(() => {
if (this.$refs.categoryTree) this.$refs.categoryTree.setCheckedKeys([data.id])
})
},
handleCategoryCheckChange (data, checked) {
if (!checked) return
if (this.$refs.categoryTree) this.$refs.categoryTree.setCheckedKeys([data.id])
if (String(data.id) !== String(this.currentCategoryId)) this.setCurrentCategory(data)
}, },
buildSearchParams () { buildSearchParams () {
const params = { ...this.search } const params = { ...this.search, device_category_id: this.currentCategoryId }
if (!Array.isArray(params.create_time) || !params.create_time.length) delete params.create_time if (!Array.isArray(params.create_time) || !params.create_time.length) delete params.create_time
return params return params
}, },
async fetchData () { async fetchData () {
if (!this.currentCategoryId) {
this.tableData = []
this.pagination.total = 0
return
}
this.loading = true this.loading = true
try { try {
const res = await getList({ ...this.buildSearchParams(), page_no: this.pagination.current, page_size: this.pagination.size }) const res = await getList({ ...this.buildSearchParams(), page_no: this.pagination.current, page_size: this.pagination.size })
@@ -243,7 +342,7 @@ export default {
this.fetchData() this.fetchData()
}, },
onReset () { onReset () {
this.search = { device_category_id: '', name: '', check_method: '', standard: '', unit: '', create_time: [] } this.search = { name: '', check_method: '', standard: '', unit: '', create_time: [] }
this.pagination.current = 1 this.pagination.current = 1
this.fetchData() this.fetchData()
}, },
@@ -256,10 +355,17 @@ export default {
this.formData = this.emptyForm() this.formData = this.emptyForm()
this.editId = '' this.editId = ''
}, },
ensureCategorySelected () {
if (this.currentCategoryId) return true
this.$message.warning(this.$t(this.key('please_select_device_category')))
return false
},
openAdd () { openAdd () {
if (!this.ensureCategorySelected()) return
this.handleType = 'create' this.handleType = 'create'
this.dialogTitle = this.key('add_title') this.dialogTitle = this.key('add_title')
this.resetForm() this.resetForm()
this.formData.device_category_id = this.currentCategoryId
this.dialogVisible = true this.dialogVisible = true
}, },
openEdit (row) { openEdit (row) {
@@ -268,7 +374,7 @@ export default {
this.editId = row.id this.editId = row.id
this.formData = { this.formData = {
name: row.name || '', name: row.name || '',
device_category_id: row.device_category_id || '', device_category_id: row.device_category_id || this.currentCategoryId,
status: Number(row.status), status: Number(row.status),
standard: row.standard || '', standard: row.standard || '',
check_method: row.check_method || '', check_method: row.check_method || '',
@@ -282,8 +388,9 @@ export default {
async onDialogSubmit () { async onDialogSubmit () {
this.submitting = true this.submitting = true
try { try {
if (this.handleType === 'create') await createItem(this.formData) const payload = { ...this.formData, device_category_id: this.currentCategoryId }
else await editItem({ ...this.formData, id: this.editId }) if (this.handleType === 'create') await createItem(payload)
else await editItem({ ...payload, id: this.editId })
this.$message.success(this.$t(this.key('operation_success'))) this.$message.success(this.$t(this.key('operation_success')))
this.dialogVisible = false this.dialogVisible = false
this.fetchData() this.fetchData()
@@ -317,7 +424,8 @@ export default {
} }
}, },
openImport () { openImport () {
this.importDeviceCategoryId = '' if (!this.ensureCategorySelected()) return
this.importDeviceCategoryId = this.currentCategoryId
this.importFileList = [] this.importFileList = []
this.importRows = [] this.importRows = []
this.importVisible = true this.importVisible = true
@@ -394,7 +502,64 @@ export default {
</script> </script>
<style scoped> <style scoped>
.search-bar { padding: 10px 0; } .inspection-items-page {
.import-form { margin-top: 14px; } display: flex;
/deep/ .el-form-item--mini.el-form-item { margin-bottom: 4px; } gap: 16px;
height: 100%;
min-height: 560px;
}
.category-panel {
flex: 0 0 260px;
min-width: 220px;
border-right: 1px solid #ebeef5;
padding: 10px 14px 10px 0;
overflow: auto;
}
.category-filter {
margin-bottom: 12px;
}
.category-node {
display: inline-flex;
align-items: center;
gap: 4px;
max-width: 190px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.category-code {
color: #909399;
font-size: 12px;
}
.items-panel {
flex: 1;
min-width: 0;
display: flex;
flex-direction: column;
}
.items-context {
display: flex;
align-items: center;
gap: 8px;
min-height: 30px;
margin-bottom: 8px;
color: #303133;
}
.context-label {
color: #909399;
}
.search-bar {
padding-bottom: 8px;
border-bottom: 1px solid #ebeef5;
margin-bottom: 10px;
}
.import-form {
margin-top: 14px;
}
/deep/ .el-form-item--mini.el-form-item {
margin-bottom: 4px;
}
/deep/ .d2-container-full__body {
overflow: hidden;
}
</style> </style>