refactor: 抽出 replaceAllKeys 共享工具,消除两处重复的表单重置
This commit is contained in:
parent
7f19a37591
commit
f3124e96cc
14
frontend/src/utils/replaceAllKeys.js
Normal file
14
frontend/src/utils/replaceAllKeys.js
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
// 用 values 的键值对整体替换 target 的内容:先清空 target 已有的全部键,再赋值。
|
||||||
|
//
|
||||||
|
// 不能直接用 Object.assign(target, values):assign 只覆盖 target 上**已存在**的键,
|
||||||
|
// 不会删除多余的键。表单对象上残留的 id / organization_id 这类字段就是这么漏进来的 ——
|
||||||
|
// values(新建用的空表单)里没有 id,assign 便原样保留了上一次编辑并进来的 id,
|
||||||
|
// 于是新增请求体里带上了别人的 id。这里先 delete 再赋值,保证结果只含 values 的键。
|
||||||
|
//
|
||||||
|
// target 通常是 Vue 的 reactive 对象,delete 与赋值都会触发 Proxy 的拦截,
|
||||||
|
// 视图能正常同步;同样也适用于普通对象。
|
||||||
|
export function replaceAllKeys(target, values) {
|
||||||
|
Object.keys(target).forEach(key => { delete target[key] })
|
||||||
|
Object.assign(target, values)
|
||||||
|
return target
|
||||||
|
}
|
||||||
51
frontend/src/utils/replaceAllKeys.test.js
Normal file
51
frontend/src/utils/replaceAllKeys.test.js
Normal file
|
|
@ -0,0 +1,51 @@
|
||||||
|
import { describe, expect, test } from 'vitest'
|
||||||
|
import { reactive } from 'vue'
|
||||||
|
import { replaceAllKeys } from './replaceAllKeys'
|
||||||
|
|
||||||
|
describe('replaceAllKeys', () => {
|
||||||
|
test('删掉 values 里没有的键,不留残留字段', () => {
|
||||||
|
const form = { id: 1, code: 'A', name: '旧名称' }
|
||||||
|
|
||||||
|
replaceAllKeys(form, { code: '', name: '' })
|
||||||
|
|
||||||
|
expect(form).toEqual({ code: '', name: '' })
|
||||||
|
expect(Object.keys(form)).not.toContain('id')
|
||||||
|
})
|
||||||
|
|
||||||
|
test('这一点正是 Object.assign 做不到的', () => {
|
||||||
|
const assigned = { id: 1, code: 'A' }
|
||||||
|
Object.assign(assigned, { code: 'B' })
|
||||||
|
|
||||||
|
expect(assigned.id).toBe(1)
|
||||||
|
|
||||||
|
const replaced = { id: 1, code: 'A' }
|
||||||
|
replaceAllKeys(replaced, { code: 'B' })
|
||||||
|
|
||||||
|
expect(replaced.id).toBeUndefined()
|
||||||
|
})
|
||||||
|
|
||||||
|
test('覆盖同名的键并写入新增的键', () => {
|
||||||
|
const form = { code: 'A', name: '旧名称' }
|
||||||
|
|
||||||
|
replaceAllKeys(form, { code: 'A09', name: '新增类', parent_id: null })
|
||||||
|
|
||||||
|
expect(form).toEqual({ code: 'A09', name: '新增类', parent_id: null })
|
||||||
|
})
|
||||||
|
|
||||||
|
test('用于 reactive 对象时,键集合与取值都同步更新', () => {
|
||||||
|
const form = reactive({ id: 7, code: 'A' })
|
||||||
|
|
||||||
|
replaceAllKeys(form, { code: 'B', status: 'active' })
|
||||||
|
|
||||||
|
expect(Object.keys(form)).toEqual(['code', 'status'])
|
||||||
|
expect(form.id).toBeUndefined()
|
||||||
|
expect(form.code).toBe('B')
|
||||||
|
expect(form.status).toBe('active')
|
||||||
|
})
|
||||||
|
|
||||||
|
test('返回 target,便于链式书写', () => {
|
||||||
|
const form = {}
|
||||||
|
|
||||||
|
expect(replaceAllKeys(form, { code: 'A' })).toBe(form)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
@ -106,6 +106,7 @@
|
||||||
import { computed, onMounted, reactive, ref } from 'vue'
|
import { computed, onMounted, reactive, ref } from 'vue'
|
||||||
import { ElMessage } from 'element-plus'
|
import { ElMessage } from 'element-plus'
|
||||||
import { codeRulesApi, materialCategoriesApi, unitsApi } from '../../api/masterData'
|
import { codeRulesApi, materialCategoriesApi, unitsApi } from '../../api/masterData'
|
||||||
|
import { replaceAllKeys } from '../../utils/replaceAllKeys'
|
||||||
|
|
||||||
const tabs = [
|
const tabs = [
|
||||||
{ key: 'categories', label: '物料分类', api: materialCategoriesApi },
|
{ key: 'categories', label: '物料分类', api: materialCategoriesApi },
|
||||||
|
|
@ -150,16 +151,11 @@ async function ensureCategories() {
|
||||||
categories.value = response.data || []
|
categories.value = response.data || []
|
||||||
}
|
}
|
||||||
|
|
||||||
// 与 PartnerList.vue 同理:Object.assign 删不掉上一次编辑残留的 id,
|
|
||||||
// 新增前必须把表单整体清空。
|
|
||||||
function resetForm(values) {
|
|
||||||
Object.keys(form).forEach(key => { delete form[key] })
|
|
||||||
Object.assign(form, values)
|
|
||||||
}
|
|
||||||
|
|
||||||
async function openCreate() {
|
async function openCreate() {
|
||||||
editingId.value = null
|
editingId.value = null
|
||||||
resetForm(defaultForm())
|
// 用 replaceAllKeys 而不是 Object.assign:openEdit 会把 row 的全部字段并进 form,
|
||||||
|
// 其中 id / organization_id 在新增时必须清掉,assign 做不到。
|
||||||
|
replaceAllKeys(form, defaultForm())
|
||||||
if (activeTab.value === 'rules') await ensureCategories()
|
if (activeTab.value === 'rules') await ensureCategories()
|
||||||
dialogVisible.value = true
|
dialogVisible.value = true
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -38,6 +38,7 @@
|
||||||
import { computed, onMounted, reactive, ref, watch } from 'vue'
|
import { computed, onMounted, reactive, ref, watch } from 'vue'
|
||||||
import { ElMessage } from 'element-plus'
|
import { ElMessage } from 'element-plus'
|
||||||
import { partnersApi } from '../../api/partners'
|
import { partnersApi } from '../../api/partners'
|
||||||
|
import { replaceAllKeys } from '../../utils/replaceAllKeys'
|
||||||
|
|
||||||
const props = defineProps({ role: { type: String, required: true }, title: { type: String, required: true } })
|
const props = defineProps({ role: { type: String, required: true }, title: { type: String, required: true } })
|
||||||
const rows = ref([])
|
const rows = ref([])
|
||||||
|
|
@ -54,13 +55,9 @@ const form = reactive(emptyForm())
|
||||||
|
|
||||||
function emptyForm() { return { partner_code: '', legal_name: '', unified_credit_code: '', contact_name: '', contact_phone: '', address: '', status: 'active', is_supplier: false, is_customer: false } }
|
function emptyForm() { return { partner_code: '', legal_name: '', unified_credit_code: '', contact_name: '', contact_phone: '', address: '', status: 'active', is_supplier: false, is_customer: false } }
|
||||||
async function load() { loading.value = true; try { const response = await partnersApi.list(props.role); rows.value = response.data || [] } finally { loading.value = false } }
|
async function load() { loading.value = true; try { const response = await partnersApi.list(props.role); rows.value = response.data || [] } finally { loading.value = false } }
|
||||||
// Object.assign 只覆盖已存在的键,不会删掉上次编辑残留的 id,
|
// 用 replaceAllKeys 而不是 Object.assign:后者删不掉上次编辑残留的 id,
|
||||||
// 所以这里先清空再整体赋值,保证新增提交的是一张干净的表单。
|
// 新增时会把别人的 id 一起提交上去。
|
||||||
function resetForm(values) {
|
function openCreate() { editingId.value = null; replaceAllKeys(form, emptyForm()); dialogVisible.value = true }
|
||||||
Object.keys(form).forEach(key => { delete form[key] })
|
|
||||||
Object.assign(form, values)
|
|
||||||
}
|
|
||||||
function openCreate() { editingId.value = null; resetForm(emptyForm()); dialogVisible.value = true }
|
|
||||||
function openEdit(row) { editingId.value = row.id; Object.assign(form, row, { status: row[statusField.value] || 'active' }); dialogVisible.value = true }
|
function openEdit(row) { editingId.value = row.id; Object.assign(form, row, { status: row[statusField.value] || 'active' }); dialogVisible.value = true }
|
||||||
function payload() {
|
function payload() {
|
||||||
return {
|
return {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user