Skip to content

Commit b1d0354

Browse files
committed
refactor:avoid duplicate error display between field and global messages
1 parent e0327ca commit b1d0354

4 files changed

Lines changed: 79 additions & 12 deletions

File tree

‎src/components/Form/AutoDataForm/index.vue‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,13 @@ export default {
220220
// 不写入 totalFields,避免触发 innerContent 变化导致表单值被覆盖
221221
this.$set(this.serverErrors, name, error)
222222
},
223+
getFieldNames() {
224+
const elForm = this._getElFormInstance()
225+
if (elForm && Array.isArray(elForm.fields)) {
226+
return elForm.fields.map(item => item.prop).filter(Boolean)
227+
}
228+
return (this.totalFields || []).map(item => item.prop).filter(Boolean)
229+
},
223230
setErrors(errors) {
224231
const mapped = {}
225232
Object.entries(errors || {}).forEach(([k, v]) => {

‎src/layout/components/GenericCreateUpdateForm/index.vue‎

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -70,49 +70,49 @@ export default {
7070
performSubmit: {
7171
type: Function,
7272
default(validValues) {
73-
return this.$axios[this.method](this.iUrl, validValues)
73+
return this.$axios[this.method](this.iUrl, validValues, this.getFieldErrorConfig())
7474
}
7575
},
7676
// 创建成功的msg
7777
createSuccessMsg: {
7878
type: String,
79-
default: function () {
79+
default: function() {
8080
return this.$t('CreateSuccessMsg')
8181
}
8282
},
8383
// 保存成功,继续添加的msg
8484
saveSuccessContinueMsg: {
8585
type: String,
86-
default: function () {
86+
default: function() {
8787
return this.$t('SaveSuccessContinueMsg')
8888
}
8989
},
9090
// 更新成功的msg
9191
updateSuccessMsg: {
9292
type: String,
93-
default: function () {
93+
default: function() {
9494
return this.$t('UpdateSuccessMsg')
9595
}
9696
},
9797
// 创建成功的跳转路由
9898
createSuccessNextRoute: {
9999
type: Object,
100-
default: function () {
100+
default: function() {
101101
const routeName = this.$route.name?.replace('Create', 'List')
102102
return { name: routeName }
103103
}
104104
},
105105
// 更新成功的跳转路由
106106
updateSuccessNextRoute: {
107107
type: Object,
108-
default: function () {
108+
default: function() {
109109
const routeName = this.$route.name?.replace('Update', 'List')
110110
return { name: routeName }
111111
}
112112
},
113113
objectDetailRoute: {
114114
type: Object,
115-
default: function () {
115+
default: function() {
116116
const routeName = this.$route.name?.replace('Update', 'Detail').replace('Create', 'Detail')
117117
return { name: routeName }
118118
}
@@ -126,7 +126,7 @@ export default {
126126
},
127127
cloneNameSuffix: {
128128
type: [String, Number],
129-
default: function () {
129+
default: function() {
130130
return this.$t('Duplicate').toLowerCase()
131131
}
132132
},
@@ -138,7 +138,7 @@ export default {
138138
// 获取创建和更新的url function
139139
getUrl: {
140140
type: Function,
141-
default: function () {
141+
default: function() {
142142
const objectId = this.getUpdateId()
143143
let url = this.url
144144
if (objectId) {
@@ -347,6 +347,12 @@ export default {
347347
isUpdateMethod() {
348348
return ['put', 'patch'].indexOf(this.method.toLowerCase()) > -1
349349
},
350+
getFieldErrorConfig() {
351+
const fields = this.$refs.form?.getFieldNames?.() || []
352+
return {
353+
fieldErrorFields: fields
354+
}
355+
},
350356
encryptFields(values) {
351357
// 批量提交,clean 后可能是个数组
352358
if (values instanceof Array) {

‎src/layout/components/GenericUpdateFormDialog/index.vue‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ export default {
6767
default: false
6868
}
6969
},
70-
data: function () {
70+
data: function() {
7171
return {
7272
internalKey: 0,
7373
selectPropertiesLabel: this.$t('SelectProperties'),
@@ -124,11 +124,11 @@ export default {
124124
}
125125
return formValue
126126
},
127-
onSubmit: function (validValues) {
127+
onSubmit: function(validValues) {
128128
const url = this.url
129129
const msg = this.updateSuccessMsg
130130
this.$axios
131-
.patch(url, validValues)
131+
.patch(url, validValues, this.getFieldErrorConfig())
132132
.then(res => {
133133
vm.$emit('update')
134134
this.$message.success(msg)

‎src/utils/request.js‎

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,59 @@ function ifBadRequest({ response, error }) {
112112
}
113113
}
114114

115+
function isPlainObject(data) {
116+
return Object.prototype.toString.call(data) === '[object Object]'
117+
}
118+
119+
const fieldErrorGlobalKeys = ['detail', 'non_field_errors', 'error', 'msg']
120+
121+
function hasErrorMessage(value) {
122+
if (typeof value === 'string') {
123+
return value.trim() !== ''
124+
}
125+
if (Array.isArray(value)) {
126+
return value.some(item => hasErrorMessage(item))
127+
}
128+
if (isPlainObject(value)) {
129+
return Object.values(value).some(item => hasErrorMessage(item))
130+
}
131+
return value !== null && value !== undefined
132+
}
133+
134+
function isFieldErrorValue(value) {
135+
if (!hasErrorMessage(value)) {
136+
return false
137+
}
138+
return typeof value === 'string' || Array.isArray(value) || isPlainObject(value)
139+
}
140+
141+
function isFieldErrorHandledByForm(response) {
142+
const data = response.data
143+
const fields = response.config?.fieldErrorFields || []
144+
if (response.status !== 400) {
145+
return false
146+
}
147+
if (!Array.isArray(fields) || fields.length === 0) {
148+
return false
149+
}
150+
if (!isPlainObject(data) || Object.keys(data).length === 0) {
151+
return false
152+
}
153+
154+
const errorKeys = Object.keys(data).filter(key => hasErrorMessage(data[key]))
155+
if (errorKeys.length === 0 || errorKeys.some(key => fieldErrorGlobalKeys.includes(key))) {
156+
return false
157+
}
158+
159+
return errorKeys.every(key => fields.includes(key) && isFieldErrorValue(data[key]))
160+
}
161+
162+
function disableHandledFieldErrorFlash({ response }) {
163+
if (isFieldErrorHandledByForm(response)) {
164+
response.config.disableFlashErrorMsg = true
165+
}
166+
}
167+
115168
export function logout() {
116169
const next = encodeURIComponent(getCurrentPageUrl())
117170
window.location.href = `${addBasePath(process.env.VUE_APP_LOGOUT_PATH)}?next=${next}`
@@ -192,6 +245,7 @@ service.interceptors.response.use(
192245

193246
await ifUnauthorized({ response, error })
194247
await ifBadRequest({ response, error })
248+
await disableHandledFieldErrorFlash({ response, error })
195249
await flashErrorMsg({ response, error })
196250
return Promise.reject(error)
197251
}

0 commit comments

Comments
 (0)