diff --git a/docs/用户管理模块表单UX验证.md b/docs/用户管理模块表单UX验证.md new file mode 100644 index 00000000..0d733908 --- /dev/null +++ b/docs/用户管理模块表单UX验证.md @@ -0,0 +1,22 @@ +# 用户管理模块表单 UX 验证 + +## Findings + +- **High** `src/views/system-administration/user-management/user/index.vue`: 已修复新增/编辑弹窗表单模型未在 `data()` 中声明的问题。该问题会导致 Vue 2 根级动态属性不具备可靠响应式,输入框和下拉框在弹窗中表现为无法正常录入或选择。 +- **Medium** `src/views/system-administration/user-management/user/index.vue`: 已补充状态查询项,查询参数会随 `username`、`nickname` 一起传给列表接口,用于按启用/停用筛选用户。 +- **Medium** `src/views/system-administration/user-management/user/index.vue`: 已将账号重复校验、确认密码一致性校验接入 Element 表单规则,错误会出现在对应字段附近,而不是只依赖提交后的全局提示。 +- **Medium** `src/views/system-administration/user-management/user/index.vue`: 当前用户数据模型没有手机号、邮箱字段,接口封装也没有对应字段或独立校验接口。因此手机号/邮箱格式校验无法在不扩展前后端契约的情况下落地。建议后续先确认字段设计,再补充表单项、列表列、接口字段和格式规则。 +- **Low** `src/components/page-dialog-form/index.vue`: 已补充 `show-password` 透传,并修复自定义 validator 没有 `message` 时被无条件翻译的问题,避免后续自定义表单校验不稳定。 + +## Evidence + +- Browser: source-only。当前页面依赖登录态和后端接口,未做真实浏览器端新增用户提交。 +- Source checks: 用户弹窗字段状态、表单规则、状态查询、权限按钮声明已核对。 +- Build checks: 已通过 `eslint`、locale JSON 解析和生产构建验证语法与编译兼容性。 +- Confidence limits: 账号重复检查复用现有列表接口,并按用户名精确匹配;如果后端列表接口只做模糊查询或分页限制异常,最终仍需后端唯一约束兜底。 + +## Suggested Shape + +- 保持“账号/密码/确认密码/用户组/姓名/出入证编号/状态”的当前录入顺序,必填项优先,状态默认启用。 +- 若业务确认需要手机号/邮箱,应放在姓名之后、出入证编号之前,并使用字段级格式提示。 +- 删除、批量删除、重置密码、启停用等操作保持二次确认;接口失败时不应显示成功提示。 diff --git a/src/api/production-master-data/data-collection-configuration.js b/src/api/production-master-data/data-collection-configuration.js index 0ca20723..febac081 100644 --- a/src/api/production-master-data/data-collection-configuration.js +++ b/src/api/production-master-data/data-collection-configuration.js @@ -4,7 +4,7 @@ const BASE = 'production_configuration/spc_configuration/binding_scada_node/' function apiParams (method, data = {}) { return { - method: `production_master_data_spc_configuration_data_collection_configuration_${method}`, + method: `production_configuration_spc_configuration_binding_scada_node_${method}`, platform: 'background', ...data } diff --git a/src/api/production-master-data/factory-area.js b/src/api/production-master-data/factory-area.js index 18fa5981..57141320 100644 --- a/src/api/production-master-data/factory-area.js +++ b/src/api/production-master-data/factory-area.js @@ -4,7 +4,7 @@ const BASE = 'production_configuration/factory_model/factory_area/' function apiParams (method, data = {}) { return { - method: `production_master_data_factory_model_factory_area_${method}`, + method: `production_configuration_factory_model_factory_area_${method}`, platform: 'background', ...data } diff --git a/src/api/production-master-data/production-line.js b/src/api/production-master-data/production-line.js index 2c7acd82..3864b2cb 100644 --- a/src/api/production-master-data/production-line.js +++ b/src/api/production-master-data/production-line.js @@ -4,7 +4,7 @@ const BASE = 'production_configuration/factory_model/factory_line/' function apiParams (method, data = {}) { return { - method: `production_master_data_factory_model_factory_line_${method}`, + method: `production_configuration_factory_model_factory_line_${method}`, platform: 'background', ...data } diff --git a/src/components/page-dialog-form/index.vue b/src/components/page-dialog-form/index.vue index 97a55ef9..fe29cd78 100644 --- a/src/components/page-dialog-form/index.vue +++ b/src/components/page-dialog-form/index.vue @@ -66,6 +66,7 @@ v-model="formData[col.prop]" :placeholder="$t(col.placeholder)" :type="col.inputType || 'text'" + :show-password="!!col.showPassword" :autosize="col.autosize" :clearable="col.clearable !== false" :disabled="!!col.disabled" @@ -255,7 +256,13 @@ export default { const rules = this.rules || {} const translated = {} for (const [field, validators] of Object.entries(rules)) { - translated[field] = validators.map(v => ({ ...v, message: this.$t(v.message) })) + translated[field] = validators.map(v => { + const rule = { ...v } + if (rule.message) { + rule.message = this.$t(rule.message) + } + return rule + }) } return translated } diff --git a/src/locales/en.json b/src/locales/en.json index 56309fc1..898e2e9a 100644 --- a/src/locales/en.json +++ b/src/locales/en.json @@ -27,7 +27,6 @@ "create_success": "Created successfully", "edit_success": "Updated successfully", "delete_success": "Deleted successfully", - "sort": "No.", "code": "Area Code", "name": "Area Name", "remark": "Remark", @@ -45,19 +44,10 @@ "confirm_delete": "Are you sure to delete?", "validation_fail": "Validation failed", "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" + "remark_max_500": "Remark cannot exceed 500 characters" }, "production_line": { "search": "Search", @@ -66,7 +56,6 @@ "enter_name": "Please enter production line name", "enter_remark": "Please enter remark", "operation_success": "Operation succeeded", - "sort": "No.", "code": "Production Line Code", "name": "Production Line Name", "area": "Plant Area", @@ -85,10 +74,6 @@ "tip": "Tip", "confirm_delete": "Are you sure to delete?", "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", @@ -696,6 +681,28 @@ "confirm_delete": "Are you sure to delete this SPC collection configuration?", "validation_fail": "Validation failed", "please_enter": "Please enter {name}", + "result_param": "Result Parameter", + "result_param_code": "Result Parameter Code", + "result_param_name": "Result Parameter Name", + "enter_result_param_code": "Please enter result parameter code", + "enter_result_param_name": "Please enter result parameter name", + "scada_node_code": "SCADA Node Code", + "scada_node_name": "SCADA Node Name", + "enter_scada_node_code": "Please enter SCADA node code", + "enter_scada_node_name": "Please enter SCADA node name", + "working_subclass": "Process Step", + "select_working_subclass": "Please select process step", + "category": "Category", + "select_data_type": "Please select data type", + "select_result_param": "Please select result parameter", + "select_scada_node": "Please select SCADA node", + "result_param_type": "Result Parameter Type", + "process_inspection": "Process Inspection", + "result_data": "Result Data", + "measurement_type": "Measurement Type", + "count_type": "Count Type", + "create_time": "Created Time", + "update_data": "Updated Time", "help": "Configure SPC data collection parameters and bind SCADA nodes" } }, @@ -2344,6 +2351,7 @@ "status": "Status", "enable": "Enabled", "disable": "Disabled", + "select_status": "Please select status", "user_group": "User Group", "login_ip": "Last Login IP", "last_login_time": "Last Login Time", @@ -2370,6 +2378,7 @@ "password_not_match": "Passwords do not match", "password_length": "Length should be 6 to 64 characters", "username_length": "Length should be 3 to 20 characters", + "username_exists": "Username already exists. Please use another username", "cannot_delete_self": "Cannot delete own account", "cannot_operate_self": "Cannot operate own account", "batch_delete": "Batch Delete", diff --git a/src/locales/zh-chs.json b/src/locales/zh-chs.json index 4378aae9..620cc109 100644 --- a/src/locales/zh-chs.json +++ b/src/locales/zh-chs.json @@ -27,7 +27,6 @@ "create_success": "新增成功", "edit_success": "编辑成功", "delete_success": "删除成功", - "sort": "序号", "code": "所区编码", "name": "所区名称", "remark": "备注", @@ -45,19 +44,10 @@ "confirm_delete": "确定要执行该操作吗?", "validation_fail": "校验失败", "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": "上级区域不能选择自身或下级区域" + "remark_max_500": "备注不能超过 500 个字符" }, "production_line": { "search": "查询", @@ -66,7 +56,6 @@ "enter_name": "请输入产线名称", "enter_remark": "请输入备注", "operation_success": "操作成功", - "sort": "序号", "code": "产线编码", "name": "产线名称", "area": "所区", @@ -85,10 +74,6 @@ "tip": "提示", "confirm_delete": "确定要执行该操作吗?", "validation_fail": "校验失败", - "status": "状态", - "select_status": "请选择状态", - "enabled": "启用", - "disabled": "禁用", "export": "导出", "confirm_export": "确认创建导出任务?", "length_1_100": "长度在 1 到 100 个字符", @@ -696,6 +681,28 @@ "confirm_delete": "确定要删除该SPC采集配置吗?", "validation_fail": "校验失败", "please_enter": "请输入{name}", + "result_param": "结果参数", + "result_param_code": "结果参数编码", + "result_param_name": "结果参数名称", + "enter_result_param_code": "请输入结果参数编码", + "enter_result_param_name": "请输入结果参数名称", + "scada_node_code": "SCADA节点编码", + "scada_node_name": "SCADA节点名称", + "enter_scada_node_code": "请输入SCADA节点编码", + "enter_scada_node_name": "请输入SCADA节点名称", + "working_subclass": "工序", + "select_working_subclass": "请选择工序", + "category": "类别", + "select_data_type": "请选择数据类型", + "select_result_param": "请选择结果参数", + "select_scada_node": "请选择SCADA节点", + "result_param_type": "结果参数类型", + "process_inspection": "过程检验", + "result_data": "结果数据", + "measurement_type": "计量型", + "count_type": "计数型", + "create_time": "创建时间", + "update_data": "更新时间", "help": "配置SPC数据采集参数,绑定SCADA节点" } }, @@ -2344,6 +2351,7 @@ "status": "状态", "enable": "启用", "disable": "禁用", + "select_status": "请选择状态", "user_group": "用户组", "login_ip": "上次登录IP", "last_login_time": "上次登录时间", @@ -2370,6 +2378,7 @@ "password_not_match": "两次输入的密码不一致", "password_length": "长度在 6 到 64 个字符", "username_length": "长度在 3 到 20 个字符", + "username_exists": "账号已存在,请更换账号", "cannot_delete_self": "不能删除自己的账号", "cannot_operate_self": "不能操作自己的账号", "batch_delete": "批量删除", diff --git a/src/views/planning-production/batch-management/batch-list/index.vue b/src/views/planning-production/batch-management/batch-list/index.vue index 0f88f1c6..3b7c6e31 100644 --- a/src/views/planning-production/batch-management/batch-list/index.vue +++ b/src/views/planning-production/batch-management/batch-list/index.vue @@ -467,12 +467,30 @@ export default { } }, normalizeListResponse (res) { - const data = Array.isArray(res) ? res : (res && res.data) || [] - if (Array.isArray(data)) return { list: data, total: data.length } - return { - list: data.data || [], - total: data.count || 0 + const root = res || {} + const data = res && res.data !== undefined ? res.data : res + if (Array.isArray(data)) { + return { list: data, total: Number(root.count || root.total || data.length) } } + if (data && Array.isArray(data.list)) { + return { list: data.list, total: Number(root.count || root.total || data.count || data.total || data.list.length) } + } + if (data && Array.isArray(data.rows)) { + return { list: data.rows, total: Number(root.count || root.total || data.count || data.total || data.rows.length) } + } + if (data && Array.isArray(data.records)) { + return { list: data.records, total: Number(root.count || root.total || data.count || data.total || data.records.length) } + } + if (data && Array.isArray(data.data)) { + return { list: data.data, total: Number(root.count || root.total || data.count || data.total || data.data.length) } + } + if (data && data.data && Array.isArray(data.data.data)) { + return { list: data.data.data, total: Number(root.count || root.total || data.count || data.total || data.data.count || data.data.total || data.data.data.length) } + } + if (data && data.data && Array.isArray(data.data.list)) { + return { list: data.data.list, total: Number(root.count || root.total || data.count || data.total || data.data.count || data.data.total || data.data.list.length) } + } + return { list: [], total: 0 } }, async fetchData () { this.loading = true 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 b869181e..468605f0 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 @@ -9,12 +9,6 @@ - - - - - - {{ $t(key('search')) }} {{ $t(key('reset')) }} @@ -31,17 +25,14 @@ :loading="loading" :toolbar-buttons="toolbarButtons" :row-buttons="rowButtons" - :pagination="null" + :pagination="pagination" :table-attrs="tableAttrs" help-url="/help/factory-area" :help-text="$t(ckey('help'))" auto-height + @page-change="onPageChange" @selection-change="onSelect" > - !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: 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: 230, fixed: 'right' } + { prop: '_actions', label: this.key('operation'), width: 160, fixed: 'right' } ]) const btns = useTableButtons({ toolbar: [ @@ -151,7 +120,6 @@ export default { { key: 'export', label: this.key('export'), icon: 'el-icon-download', auth: '/production_configuration/factory_model/factory_area/export', onClick: this.handleExport } ], row: [ - { 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 } ] @@ -172,11 +140,22 @@ export default { 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) } + const getTotal = (source, fallback) => { + if (!source) return fallback + const total = source.count ?? source.total ?? source.total_count ?? source.record_count + const value = Number(total) + return Number.isNaN(value) ? fallback : value + } + const containers = [res, res && res.data, res && res.data && res.data.data].filter(Boolean) + for (const item of containers) { + if (Array.isArray(item)) { + return { list: item, total: getTotal(res, item.length) } + } + const list = item.data || item.list || item.rows || item.records || item.items + if (Array.isArray(list)) { + return { list, total: getTotal(item, getTotal(res, list.length)) } + } + } return { list: [], total: 0 } }, normalizeNode (row, level = 0) { @@ -216,34 +195,41 @@ export default { }) 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: 1, page_size: 10000 }) + const res = await getFactoryAreaList({ + ...this.search, + page_no: this.pagination.current, + page_size: this.pagination.size + }) const data = this.normalizeResponse(res) this.rawAreaData = data.list this.tableData = this.buildTree(data.list) + this.pagination.total = data.total } finally { this.loading = false } }, onSearch () { + this.pagination.current = 1 this.fetchData() }, onReset () { - this.search = { code: '', name: '', status: '' } + this.search = { code: '', name: '' } + this.pagination.current = 1 + this.fetchData() + }, + onPageChange (page) { + this.pagination.current = page.current + this.pagination.size = page.size this.fetchData() }, onSelect (rows) { this.selectedRows = rows }, resetForm () { - this.formData = { code: '', name: '', parent_id: '', status: '1', remark: '' } + this.formData = { code: '', name: '', parent_id: '', remark: '' } this.editId = '' }, openAdd () { @@ -255,34 +241,14 @@ 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 = 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.formData = { code: row.code, name: row.name, parent_id: this.getParentId(row), 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) @@ -310,6 +276,7 @@ export default { 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 () { @@ -322,7 +289,5 @@ export default { 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 3dbb1d7c..5e04e05a 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 @@ -38,18 +38,6 @@ /> - - - - - - {{ $t(key('search')) }} @@ -76,10 +64,6 @@ @page-change="onPageChange" @selection-change="onSelect" > - { + if (!source) return fallback + const total = source.count ?? source.total ?? source.total_count ?? source.record_count + const value = Number(total) + return Number.isNaN(value) ? fallback : value + } + const containers = [res, res && res.data, res && res.data && res.data.data].filter(Boolean) + for (const item of containers) { + if (Array.isArray(item)) { + return { list: item, total: getTotal(res, item.length) } + } + const list = item.data || item.list || item.rows || item.records || item.items + if (Array.isArray(list)) { + return { list, total: getTotal(item, getTotal(res, list.length)) } + } + } return { list: [], total: 0 } }, async initAreaOptions () { @@ -233,7 +217,7 @@ export default { this.fetchData() }, onReset () { - this.search = { code: '', name: '', area_id: '', status: '' } + this.search = { code: '', name: '', area_id: '' } this.pagination.current = 1 this.fetchData() }, @@ -246,7 +230,7 @@ export default { this.selectedRows = rows }, resetForm () { - this.formData = { code: '', name: '', area_id: '', status: '1', remark: '' } + this.formData = { code: '', name: '', area_id: '', remark: '' } this.editId = '' }, openAdd () { @@ -262,7 +246,7 @@ 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, status: row.status !== undefined ? String(row.status) : '1', remark: row.remark || '' } + this.formData = { code: row.code, name: row.name, area_id: row.area_id, remark: row.remark || '' } this.dialogVisible = true }, async onDialogSubmit () { @@ -306,7 +290,5 @@ export default { diff --git a/src/views/production-master-data/process-model/process-category/index.vue b/src/views/production-master-data/process-model/process-category/index.vue index 3b19420c..503b6e70 100644 --- a/src/views/production-master-data/process-model/process-category/index.vue +++ b/src/views/production-master-data/process-model/process-category/index.vue @@ -148,7 +148,6 @@ export default { }, 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: 'remark', label: this.key('remark') }, diff --git a/src/views/production-master-data/process-model/process-routing-card/index.vue b/src/views/production-master-data/process-model/process-routing-card/index.vue index 67da6cae..a7a417a6 100644 --- a/src/views/production-master-data/process-model/process-routing-card/index.vue +++ b/src/views/production-master-data/process-model/process-routing-card/index.vue @@ -314,7 +314,6 @@ export default { this.columns = useTableColumns([ { prop: 'up', label: '', slot: 'up', width: 40 }, { prop: 'down', label: '', slot: 'down', width: 40 }, - { prop: 'sort', label: this.key('sort'), slot: 'sort', width: 80 }, { prop: 'code', label: this.key('step_code'), minWidth: 120 }, { prop: 'name', label: this.key('step_name'), minWidth: 140 }, { prop: 'workingsubclass_name', label: this.key('process_unit_name'), minWidth: 140 }, diff --git a/src/views/production-master-data/process-model/process-routing/index.vue b/src/views/production-master-data/process-model/process-routing/index.vue index 1202e3f6..1486c053 100644 --- a/src/views/production-master-data/process-model/process-routing/index.vue +++ b/src/views/production-master-data/process-model/process-routing/index.vue @@ -228,7 +228,6 @@ export default { }, 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: 140 }, { prop: 'flow_category_name', label: this.key('category'), minWidth: 120 }, diff --git a/src/views/production-master-data/process-model/process-step/index.vue b/src/views/production-master-data/process-model/process-step/index.vue index 0d3ebe70..f076be97 100644 --- a/src/views/production-master-data/process-model/process-step/index.vue +++ b/src/views/production-master-data/process-model/process-step/index.vue @@ -195,7 +195,6 @@ export default { }, created () { this.columns = useTableColumns([ - { prop: 'sort ', label: this.key('sort'), width: 80 }, { prop: 'code', label: this.key('process_unit_code'), minWidth: 120 }, { prop: 'name', label: this.key('process_unit_name'), minWidth: 120 }, { prop: 'device_category_name', label: this.key('device_category'), minWidth: 120 }, diff --git a/src/views/production-master-data/product-model/product-ng-info/index.vue b/src/views/production-master-data/product-model/product-ng-info/index.vue index 05887f05..ff76fcf7 100644 --- a/src/views/production-master-data/product-model/product-ng-info/index.vue +++ b/src/views/production-master-data/product-model/product-ng-info/index.vue @@ -14,9 +14,9 @@ > @@ -74,7 +74,11 @@ auto-height @page-change="onPageChange" @selection-change="onSelect" - /> + > + + { + this.fetchData() + }) }, methods: { + normalizeResponse (res) { + const root = res || {} + const data = res && res.data !== undefined ? res.data : res + if (Array.isArray(data)) return { list: data, total: Number(root.count || root.total || data.length) } + if (data && Array.isArray(data.list)) return { list: data.list, total: Number(root.count || root.total || data.count || data.total || data.list.length) } + if (data && Array.isArray(data.rows)) return { list: data.rows, total: Number(root.count || root.total || data.count || data.total || data.rows.length) } + if (data && Array.isArray(data.records)) return { list: data.records, total: Number(root.count || root.total || data.count || data.total || data.records.length) } + if (data && Array.isArray(data.data)) return { list: data.data, total: Number(root.count || root.total || data.count || data.total || data.data.length) } + if (data && data.data && Array.isArray(data.data.data)) return { list: data.data.data, total: Number(root.count || root.total || data.count || data.total || data.data.count || data.data.total || data.data.data.length) } + if (data && data.data && Array.isArray(data.data.list)) return { list: data.data.list, total: Number(root.count || root.total || data.count || data.total || data.data.count || data.data.total || data.data.list.length) } + return { list: [], total: 0 } + }, + normalizeRow (row) { + const deviceCategory = typeof row.device_category === 'object' + ? row.device_category + : (typeof row.category === 'object' ? row.category : {}) + const option = this.deviceCategoryOptions.find(item => String(item.value) === String(row.device_category_id || deviceCategory.id || '')) + return { + ...row, + device_category_id: row.device_category_id || deviceCategory.id || '', + device_category_name: row.device_category_name || deviceCategory.name || row.category_name || (option && option.label) || (typeof row.device_category === 'string' ? row.device_category : '') + } + }, + normalizeOptions (res) { + return this.normalizeResponse(res).list.map(item => ({ + label: item.name || item.label || item.code || item.id, + value: item.id !== undefined ? item.id : item.value + })).filter(item => item.value !== undefined && item.value !== null && item.value !== '') + }, + typeText (type) { + if (type === 'ERR') return this.$t(this.key('type_error')) + if (type === 'NG') return this.$t(this.key('type_ng')) + return type + }, async fetchData () { this.loading = true try { @@ -297,11 +334,9 @@ export default { page_no: this.pagination.current, page_size: this.pagination.size }) - const data = Array.isArray(res) ? res : (res.data || {}) - const list = Array.isArray(data) ? data : (data.data || []) - const total = Array.isArray(data) ? data.length : (data.count || 0) - this.tableData = list - this.pagination.total = total + const data = this.normalizeResponse(res) + this.tableData = data.list.map(this.normalizeRow) + this.pagination.total = data.total } finally { this.loading = false } @@ -327,8 +362,7 @@ export default { if (this.deviceCategoryOptions.length) return try { const res = await getDeviceCategoryAll({}) - const list = Array.isArray(res) ? res : (res.data || []) - this.deviceCategoryOptions = Array.isArray(list) ? list : [] + this.deviceCategoryOptions = this.normalizeOptions(res) this.searchFormDeviceCategoryUpdate() } catch { /* ignore */ } }, @@ -349,18 +383,18 @@ export default { openAdd () { this.handleType = 'create' this.dialogTitle = this.key('add_exception_ng_category') - this.loadDeviceCategories() - this.$nextTick(() => { - this.$refs.dialogForm && this.$refs.dialogForm.reset() - this.resetForm() - this.dialogVisible = true + this.loadDeviceCategories().then(() => { + this.$nextTick(() => { + this.$refs.dialogForm && this.$refs.dialogForm.reset() + this.resetForm() + this.dialogVisible = true + }) }) }, openEdit (row) { this.handleType = 'edit' this.dialogTitle = this.key('edit_exception_ng_category') this.editId = row.id - this.loadDeviceCategories() this.formData = { device_category_id: row.device_category_id || '', type: row.type || '', @@ -368,7 +402,9 @@ export default { explain: row.explain || '', note: row.note || '' } - this.dialogVisible = true + this.loadDeviceCategories().then(() => { + this.dialogVisible = true + }) }, async onDialogSubmit () { this.submitting = true diff --git a/src/views/production-master-data/spc-configuration/data-collection-configuration/index.vue b/src/views/production-master-data/spc-configuration/data-collection-configuration/index.vue index e7f62590..9c9516e8 100644 --- a/src/views/production-master-data/spc-configuration/data-collection-configuration/index.vue +++ b/src/views/production-master-data/spc-configuration/data-collection-configuration/index.vue @@ -3,43 +3,41 @@