From 3b801a270ee7542e4895be05a19d43e4badef6ea Mon Sep 17 00:00:00 2001 From: sheng <905537351@qq.com> Date: Wed, 24 Jun 2026 14:57:27 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E5=B7=A5=E5=8E=82=E6=A8=A1?= =?UTF-8?q?=E5=9E=8B=E4=BA=A7=E7=BA=BF=E5=92=8C=E5=8C=BA=E5=9F=9F=E5=8A=9F?= =?UTF-8?q?=E8=83=BD=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../production-master-data/factory-area.js | 8 + .../production-master-data/production-line.js | 8 + src/locales/en.json | 25 +- src/locales/zh-chs.json | 25 +- .../factory-model/factory-area/index.vue | 313 ++++++++++-------- .../factory-model/production-line/index.vue | 206 +++++------- 6 files changed, 322 insertions(+), 263 deletions(-) diff --git a/src/api/production-master-data/factory-area.js b/src/api/production-master-data/factory-area.js index 47f57eef..18fa5981 100644 --- a/src/api/production-master-data/factory-area.js +++ b/src/api/production-master-data/factory-area.js @@ -49,3 +49,11 @@ export function deleteFactoryArea (data) { data: apiParams('delete', data) }) } + +export function exportFactoryAreaTask (data) { + return request({ + url: BASE + 'export', + method: 'post', + data: apiParams('export', data) + }) +} diff --git a/src/api/production-master-data/production-line.js b/src/api/production-master-data/production-line.js index 251bba3b..2c7acd82 100644 --- a/src/api/production-master-data/production-line.js +++ b/src/api/production-master-data/production-line.js @@ -41,3 +41,11 @@ export function deleteProductionLine (data) { data: apiParams('delete', data) }) } + +export function exportProductionLineTask (data) { + return request({ + url: BASE + 'export', + method: 'post', + data: apiParams('export', data) + }) +} diff --git a/src/locales/en.json b/src/locales/en.json index 6c03947e..56309fc1 100644 --- a/src/locales/en.json +++ b/src/locales/en.json @@ -44,7 +44,20 @@ "tip": "Tip", "confirm_delete": "Are you sure to delete?", "validation_fail": "Validation failed", - "please_enter": "Please enter {name}" + "please_enter": "Please enter {name}", + "parent_area": "Parent Area", + "select_parent_area": "Please select parent area", + "status": "Status", + "select_status": "Please select status", + "enabled": "Enabled", + "disabled": "Disabled", + "add_child": "Add Subarea", + "add_child_title": "Add Subarea", + "export": "Export", + "confirm_export": "Create export task?", + "length_1_100": "Length should be 1 to 100 characters", + "remark_max_500": "Remark cannot exceed 500 characters", + "parent_cycle_error": "Parent area cannot be itself or a child area" }, "production_line": { "search": "Search", @@ -71,7 +84,15 @@ "confirm": "Confirm", "tip": "Tip", "confirm_delete": "Are you sure to delete?", - "validation_fail": "Validation failed" + "validation_fail": "Validation failed", + "status": "Status", + "select_status": "Please select status", + "enabled": "Enabled", + "disabled": "Disabled", + "export": "Export", + "confirm_export": "Create export task?", + "length_1_100": "Length should be 1 to 100 characters", + "remark_max_500": "Remark cannot exceed 500 characters" } }, "process_model": { diff --git a/src/locales/zh-chs.json b/src/locales/zh-chs.json index 479b1c04..4378aae9 100644 --- a/src/locales/zh-chs.json +++ b/src/locales/zh-chs.json @@ -44,7 +44,20 @@ "tip": "提示", "confirm_delete": "确定要执行该操作吗?", "validation_fail": "校验失败", - "please_enter": "请输入{name}" + "please_enter": "请输入{name}", + "parent_area": "上级区域", + "select_parent_area": "请选择上级区域", + "status": "状态", + "select_status": "请选择状态", + "enabled": "启用", + "disabled": "禁用", + "add_child": "新增子区域", + "add_child_title": "新增子区域", + "export": "导出", + "confirm_export": "确认创建导出任务?", + "length_1_100": "长度在 1 到 100 个字符", + "remark_max_500": "备注不能超过 500 个字符", + "parent_cycle_error": "上级区域不能选择自身或下级区域" }, "production_line": { "search": "查询", @@ -71,7 +84,15 @@ "confirm": "确定", "tip": "提示", "confirm_delete": "确定要执行该操作吗?", - "validation_fail": "校验失败" + "validation_fail": "校验失败", + "status": "状态", + "select_status": "请选择状态", + "enabled": "启用", + "disabled": "禁用", + "export": "导出", + "confirm_export": "确认创建导出任务?", + "length_1_100": "长度在 1 到 100 个字符", + "remark_max_500": "备注不能超过 500 个字符" } }, "process_model": { diff --git a/src/views/production-master-data/factory-model/factory-area/index.vue b/src/views/production-master-data/factory-model/factory-area/index.vue index ecd83472..b869181e 100644 --- a/src/views/production-master-data/factory-model/factory-area/index.vue +++ b/src/views/production-master-data/factory-model/factory-area/index.vue @@ -4,30 +4,20 @@ @@ -35,25 +25,31 @@ + > + + !disabledIds.has(String(this.getId(item)))) + .map(item => ({ value: this.getId(item), label: item._treeLabel || item.name })) + } + }, created () { this.columns = useTableColumns([ { prop: 'sort', label: this.key('sort'), width: 80 }, - { prop: 'code', label: this.key('code'), minWidth: 120 }, - { prop: 'name', label: this.key('name'), minWidth: 120 }, + { prop: 'code', label: this.key('code'), minWidth: 140 }, + { prop: 'name', label: this.key('name'), minWidth: 160 }, + { prop: 'status', label: this.key('status'), slot: 'status', width: 110 }, { prop: 'remark', label: this.key('remark') }, - { prop: '_actions', label: this.key('operation'), width: 160, fixed: 'right' } + { prop: '_actions', label: this.key('operation'), width: 230, fixed: 'right' } ]) const btns = useTableButtons({ toolbar: [ - { - key: 'add', - label: this.key('add'), - icon: 'el-icon-plus', - type: 'primary', - auth: '/production_configuration/factory_model/factory_area/create', - onClick: this.openAdd - } + { key: 'add', label: this.key('add'), icon: 'el-icon-plus', type: 'primary', auth: '/production_configuration/factory_model/factory_area/create', onClick: this.openAdd }, + { key: 'export', label: this.key('export'), icon: 'el-icon-download', auth: '/production_configuration/factory_model/factory_area/export', onClick: this.handleExport } ], row: [ - { - key: 'edit', - label: this.key('edit'), - icon: 'el-icon-edit', - auth: '/production_configuration/factory_model/factory_area/edit', - onClick: this.openEdit - }, - { - key: 'delete', - label: this.key('delete'), - icon: 'el-icon-delete', - color: 'danger', - auth: '/production_configuration/factory_model/factory_area/delete', - onClick: this.handleDelete - } + { key: 'addChild', label: this.key('add_child'), icon: 'el-icon-plus', auth: '/production_configuration/factory_model/factory_area/create', onClick: this.openAddChild }, + { key: 'edit', label: this.key('edit'), icon: 'el-icon-edit', auth: '/production_configuration/factory_model/factory_area/edit', onClick: this.openEdit }, + { key: 'delete', label: this.key('delete'), icon: 'el-icon-delete', color: 'danger', auth: '/production_configuration/factory_model/factory_area/delete', onClick: this.handleDelete } ] }, this.$permission) this.toolbarButtons = btns.toolbarButtons @@ -188,41 +161,89 @@ export default { this.fetchData() }, methods: { + getId (row) { + return row && (row.id !== undefined ? row.id : row.area_id) + }, + getParentId (row) { + if (!row) return '' + if (row.parent_id !== undefined) return row.parent_id || '' + if (row.pid !== undefined) return row.pid || '' + if (row.parentId !== undefined) return row.parentId || '' + return '' + }, + normalizeResponse (res) { + const data = res && res.data !== undefined ? res.data : res + if (Array.isArray(data)) return { list: data, total: data.length } + if (data && Array.isArray(data.list)) return { list: data.list, total: Number(data.count || data.total || data.list.length) } + if (data && Array.isArray(data.data)) return { list: data.data, total: Number(data.count || data.total || data.data.length) } + if (data && data.data && Array.isArray(data.data.data)) return { list: data.data.data, total: Number(data.data.count || data.data.total || data.data.data.length) } + return { list: [], total: 0 } + }, + normalizeNode (row, level = 0) { + const children = Array.isArray(row.children) ? row.children.map(item => this.normalizeNode(item, level + 1)) : [] + const node = { ...row, id: this.getId(row), parent_id: this.getParentId(row), children } + node._treeLabel = `${' '.repeat(level)}${node.name || ''}` + if (!node.children.length) delete node.children + return node + }, + buildTree (list) { + if (list.some(item => Array.isArray(item.children))) return list.map(item => this.normalizeNode(item)) + const map = new Map() + const roots = [] + list.forEach(item => { + const node = this.normalizeNode(item) + node.children = [] + map.set(String(node.id), node) + }) + map.forEach(node => { + const parentId = this.getParentId(node) + const parent = parentId !== '' ? map.get(String(parentId)) : null + if (parent && String(parent.id) !== String(node.id)) parent.children.push(node) + else roots.push(node) + }) + const mark = (nodes, level = 0) => nodes.map(node => { + node._treeLabel = `${' '.repeat(level)}${node.name || ''}` + if (node.children.length) node.children = mark(node.children, level + 1) + else delete node.children + return node + }) + return mark(roots) + }, + flattenTree (tree, result = []) { + tree.forEach(item => { + result.push(item) + if (Array.isArray(item.children)) this.flattenTree(item.children, result) + }) + return result + }, + collectDescendantIds (id) { + const current = this.flattenTree(this.tableData).find(item => String(this.getId(item)) === String(id)) + if (!current || !Array.isArray(current.children)) return [] + return this.flattenTree(current.children).map(item => String(this.getId(item))) + }, async fetchData () { this.loading = true try { - const res = await getFactoryAreaList({ - ...this.search, - page_no: this.pagination.current, - page_size: this.pagination.size - }) - const list = Array.isArray(res) ? res : (res.data || []) - const total = Array.isArray(res) ? res.length : (res.count || 0) - this.tableData = list - this.pagination.total = total + const res = await getFactoryAreaList({ ...this.search, page_no: 1, page_size: 10000 }) + const data = this.normalizeResponse(res) + this.rawAreaData = data.list + this.tableData = this.buildTree(data.list) } finally { this.loading = false } }, onSearch () { - this.pagination.current = 1 this.fetchData() }, onReset () { - this.search = { code: '', name: '' } - this.pagination.current = 1 - this.fetchData() - }, - onPageChange (page) { - this.pagination.current = page.current - this.pagination.size = page.size + this.search = { code: '', name: '', status: '' } this.fetchData() }, onSelect (rows) { this.selectedRows = rows }, resetForm () { - this.formData = { code: '', name: '', remark: '' } + this.formData = { code: '', name: '', parent_id: '', status: '1', remark: '' } this.editId = '' }, openAdd () { @@ -234,25 +255,38 @@ export default { this.dialogVisible = true }) }, + openAddChild (row) { + this.handleType = 'create' + this.dialogTitle = this.key('add_child_title') + this.$nextTick(() => { + this.$refs.dialogForm && this.$refs.dialogForm.reset() + this.resetForm() + this.formData.parent_id = this.getId(row) + this.dialogVisible = true + }) + }, openEdit (row) { this.handleType = 'edit' this.dialogTitle = this.key('edit_title') - this.editId = row.id - this.formData = { - code: row.code, - name: row.name, - remark: row.remark || '' - } + this.editId = this.getId(row) + this.formData = { code: row.code, name: row.name, parent_id: this.getParentId(row), status: row.status !== undefined ? String(row.status) : '1', remark: row.remark || '' } this.dialogVisible = true }, + validateHierarchy () { + if (this.handleType !== 'edit' || this.formData.parent_id === '') return true + const parentId = String(this.formData.parent_id) + if (parentId === String(this.editId) || this.collectDescendantIds(this.editId).includes(parentId)) { + this.$message.warning(this.$t(this.key('parent_cycle_error'))) + return false + } + return true + }, async onDialogSubmit () { + if (!this.validateHierarchy()) return this.submitting = true try { - if (this.handleType === 'create') { - await createFactoryArea(this.formData) - } else { - await editFactoryArea({ ...this.formData, id: this.editId }) - } + if (this.handleType === 'create') await createFactoryArea(this.formData) + else await editFactoryArea({ ...this.formData, id: this.editId }) this.$message.success(this.$t(this.key('operation_success'))) this.dialogVisible = false this.fetchData() @@ -263,31 +297,32 @@ export default { onDialogClose () { this.resetForm() }, + async confirmAction (message, action) { + try { + await this.$confirm(this.$t(message), this.$t(this.key('tip')), { type: 'warning' }) + } catch { + return false + } + await action() + return true + }, async handleDelete (row) { - const cancelled = await this.$confirmAction( - { - message: this.key('confirm_delete'), - title: this.key('tip') - }, - () => deleteFactoryArea({ id: [row.id] }) - ) - if (cancelled) return + const ok = await this.confirmAction(this.key('confirm_delete'), () => deleteFactoryArea({ id: [this.getId(row)] })) + if (!ok) return this.$message.success(this.$t(this.key('operation_success'))) - this.pagination.current = Math.min( - this.pagination.current, - Math.ceil((this.pagination.total - 1) / this.pagination.size) || 1 - ) this.fetchData() + }, + async handleExport () { + const ok = await this.confirmAction(this.key('confirm_export'), () => exportFactoryAreaTask({ ...this.search })) + if (ok) this.$message.success(this.$t(this.key('operation_success'))) } } } diff --git a/src/views/production-master-data/factory-model/production-line/index.vue b/src/views/production-master-data/factory-model/production-line/index.vue index 583d76af..3dbb1d7c 100644 --- a/src/views/production-master-data/factory-model/production-line/index.vue +++ b/src/views/production-master-data/factory-model/production-line/index.vue @@ -28,6 +28,7 @@ clearable filterable style="width:200px" + @change="onSearch" > + + + + + + {{ $t(key('search')) }} @@ -62,7 +75,12 @@ auto-height @page-change="onPageChange" @selection-change="onSelect" - /> + > + + ({ value: item.area_id || item.id, label: item.name })) } catch { /* 忽略加载失败 */ } }, async fetchData () { this.loading = true try { - const res = await getProductionLineList({ - ...this.search, - page_no: this.pagination.current, - page_size: this.pagination.size - }) - const list = Array.isArray(res) ? res : (res.data || []) - const total = Array.isArray(res) ? res.length : (res.count || 0) - this.tableData = list - this.pagination.total = total + const res = await getProductionLineList({ ...this.search, page_no: this.pagination.current, page_size: this.pagination.size }) + const data = this.normalizeResponse(res) + this.tableData = data.list + this.pagination.total = data.total } finally { this.loading = false } @@ -261,7 +233,7 @@ export default { this.fetchData() }, onReset () { - this.search = { code: '', name: '', area_id: '' } + this.search = { code: '', name: '', area_id: '', status: '' } this.pagination.current = 1 this.fetchData() }, @@ -274,7 +246,7 @@ export default { this.selectedRows = rows }, resetForm () { - this.formData = { code: '', name: '', area_id: '', remark: '' } + this.formData = { code: '', name: '', area_id: '', status: '1', remark: '' } this.editId = '' }, openAdd () { @@ -290,22 +262,14 @@ export default { this.handleType = 'edit' this.dialogTitle = this.key('edit_title') this.editId = row.id - this.formData = { - code: row.code, - name: row.name, - area_id: row.area_id, - remark: row.remark || '' - } + this.formData = { code: row.code, name: row.name, area_id: row.area_id, status: row.status !== undefined ? String(row.status) : '1', remark: row.remark || '' } this.dialogVisible = true }, async onDialogSubmit () { this.submitting = true try { - if (this.handleType === 'create') { - await createProductionLine(this.formData) - } else { - await editProductionLine({ ...this.formData, id: this.editId }) - } + if (this.handleType === 'create') await createProductionLine(this.formData) + else await editProductionLine({ ...this.formData, id: this.editId }) this.$message.success(this.$t(this.key('operation_success'))) this.dialogVisible = false this.fetchData() @@ -316,31 +280,33 @@ export default { onDialogClose () { this.resetForm() }, + async confirmAction (message, action) { + try { + await this.$confirm(this.$t(message), this.$t(this.key('tip')), { type: 'warning' }) + } catch { + return false + } + await action() + return true + }, async handleDelete (row) { - const cancelled = await this.$confirmAction( - { - message: this.key('confirm_delete'), - title: this.key('tip') - }, - () => deleteProductionLine({ id: [row.id] }) - ) - if (cancelled) return + const ok = await this.confirmAction(this.key('confirm_delete'), () => deleteProductionLine({ id: [row.id] })) + if (!ok) return this.$message.success(this.$t(this.key('operation_success'))) - this.pagination.current = Math.min( - this.pagination.current, - Math.ceil((this.pagination.total - 1) / this.pagination.size) || 1 - ) + this.pagination.current = Math.min(this.pagination.current, Math.ceil((this.pagination.total - 1) / this.pagination.size) || 1) this.fetchData() + }, + async handleExport () { + const ok = await this.confirmAction(this.key('confirm_export'), () => exportProductionLineTask({ ...this.search })) + if (ok) this.$message.success(this.$t(this.key('operation_success'))) } } }