@@ -228,7 +228,8 @@ let reviewLoadSequence = 0
let editorLoadSequence = 0
const editorTitle = computed ( ( ) => editingId . value ? '编辑客户' : '新增客户' )
const editorDialogWidth = 'min(1120px, calc(100vw - 28px))'
const canUploadQualifications = computed ( ( ) => ! editorStatus . value || [ 'PROFILE_REQUIRED' , 'REJECTED' ] . includes ( editorStatus . value ) )
const canUploadQualifications = computed ( ( ) => ! editorStatus . value
|| [ 'PROFILE_REQUIRED' , 'REJECTED' , 'ACTIVE' , 'DISABLED' ] . includes ( editorStatus . value ) )
const canSubmitReview = computed ( ( ) => Boolean ( editingId . value ) && [ 'PROFILE_REQUIRED' , 'REJECTED' ] . includes ( editorStatus . value || '' ) )
const uploadingQualifications = computed ( ( ) => qualifications . value . some ( ( item ) => item . uploading ) )
const hasSelectedQualifications = computed ( ( ) => qualifications . value . some ( ( item ) => item . file ) )
@@ -603,19 +604,22 @@ async function saveCustomer() {
editorStatus . value = saved . status
savedFormSnapshot . value = JSON . stringify ( form . value )
const failures = hadSelectedQualifications ? await uploadSelectedQualifications ( String ( saved . id ) ) : [ ]
const canSubmitSavedCustomerForReview = [ 'PROFILE_REQUIRED' , 'REJECTED' ] . includes ( saved . status )
if ( failures . length ) {
ElMessage . warning ( ` 客户资料已保存,但 ${ failures . join ( '、' ) } 上传失败;失败文件已保留,请修正后再次保存 ` )
} else if ( hadBusinessLicense && hadLegalPersonId ) {
} else if ( canSubmitSavedCustomerForReview && hadBusinessLicense && hadLegalPersonId ) {
ElMessage . success ( '营业执照、统一社会信用代码和选填的法人身份证已保存,尚未提交审核' )
} else if ( hadBusinessLicense ) {
} else if ( canSubmitSavedCustomerForReview && hadBusinessLicense ) {
ElMessage . success ( '营业执照和统一社会信用代码已保存,法人身份证可按需补充,尚未提交审核' )
} else if ( hadSelectedQualifications ) {
} else if ( canSubmitSavedCustomerForReview && hadSelectedQualifications ) {
ElMessage . success ( '客户资料和已选资质已保存,尚未提交审核' )
} else if ( hadSelectedQualifications ) {
ElMessage . success ( '客户资料和已选资质已保存' )
} else {
ElMessage . success ( '客户资料已保存' )
}
await loadCustomers ( )
if ( ! failures . length ) editorOpen . value = false
await loadCustomers ( )
} catch ( error ) { ElMessage . error ( getApiErrorMessage ( error , '客户资料保存失败,请稍后重试' ) ) }
finally { saving . value = false }
}
@@ -1112,7 +1116,7 @@ onMounted(() => { void loadCustomers() })
< / button >
< div class = "qualification-file-control" > < label class = "file-picker" : class = "{ 'is-disabled': !canUploadQualifications || draft.uploading }" > < span > { { draft . uploading ? '上传中' : ( draft . file ? '已选择新文件' : ( draft . uploaded ? '更换文件' : '选择文件' ) ) } } < / span > < input type = "file" accept = ".pdf,.jpg,.jpeg,.png,application/pdf,image/jpeg,image/png" : disabled = "!canUploadQualifications || draft.uploading" @change ="selectQualificationFile($event, draft)" / > < / label > < span class = "qualification-file-name" : title = "draft.file?.name || draft.uploadedName" > { { draft . file ? . name || draft . uploadedName || '未选择文件' } } < / span > < small v-if = "draft.error" class="qualification-error" role="alert" > {{ draft.error }} < / small > < / div >
< / div >
< div class = "qualification-validity" role = "cell" > < el-date-picker v-model = "draft.validTo" type="date" value-format="YYYY-MM-DD" placeholder="请选择有效期" :disabled="!canUploadQualifications || draft.uploaded " / > < / div >
< div class = "qualification-validity" role = "cell" > < el-date-picker v-model = "draft.validTo" type="date" value-format="YYYY-MM-DD" placeholder="请选择有效期" :disabled="!canUploadQualifications || draft.uploading || (draft.uploaded && !draft.file) " / > < / div >
< / div >
< / div >
< p class = "qualification-hint" > 支持 PDF 、 JPG 、 PNG , 单个文件不超过 5 MB ; < span > * < / span > 为提交审核必填项 。 < / p >
@@ -1222,7 +1226,7 @@ onMounted(() => { void loadCustomers() })
. capital - input { display : grid ; grid - template - columns : minmax ( 0 , 1 fr ) 130 px ; width : 100 % ; gap : var ( -- admin - space - 3 , 8 px ) ; } . capital - input : deep ( . el - input - number ) { width : 100 % ; } . capital - input : deep ( . el - select ) { width : 100 % ; }
. qualification - heading { display : flex ; justify - content : flex - end ; margin - bottom : var ( -- admin - space - 5 , 12 px ) ; } . qualification - hint { margin : var ( -- admin - space - 5 , 12 px ) 0 0 ; color : var ( -- cc - muted ) ; font - size : var ( -- admin - font - caption , 12 px ) ; line - height : 1.6 ; } . qualification - hint span { color : var ( -- el - color - danger ) ; } . qualification - label > span { color : var ( -- el - color - danger ) ; }
. qualification - credit - code { max - width : 420 px ; margin - top : var ( -- admin - space - 6 , 16 px ) ; } . qualification - credit - code small { display : block ; margin - top : var ( -- admin - space - 2 , 6 px ) ; color : var ( -- cc - muted ) ; font - size : var ( -- admin - font - caption , 11 px ) ; line - height : 1.5 ; } . field - hint { display : block ; margin - top : var ( -- admin - space - 2 , 6 px ) ; color : var ( -- cc - muted ) ; line - height : 1.5 ; }
. qualification - table { overflow : hidden ; margin - top : 14 px ; border : 1 px solid var ( -- cc - border ) ; border - radius : 8 px ; } . qualification - row { display : grid ; grid - template - columns : 170 px minmax ( 0 , 1 fr ) 220 px ; min - width : 0 ; border - top : 1 px solid var ( -- cc - border ) ; } . qualification - row : first - child { border - top : 0 ; } . qualification - row > * { display : flex ; min - width : 0 ; align - items : center ; } . qualification - header { min - height : 44 px ; background : # f7f8fc ; color : var ( -- cc - muted ) ; font - size : var ( -- admin - font - caption , 12 px ) ; font - weight : 600 ; }
. qualification - table { container - type : inline - size ; overflow : hidden ; margin - top : 14 px ; border : 1 px solid var ( -- cc - border ) ; border - radius : 8 px ; } . qualification - row { display : grid ; grid - template - columns : 170 px minmax ( 0 , 1 fr ) 220 px ; min - width : 0 ; border - top : 1 px solid var ( -- cc - border ) ; } . qualification - row : first - child { border - top : 0 ; } . qualification - row > * { display : flex ; min - width : 0 ; align - items : center ; } . qualification - header { min - height : 44 px ; background : # f7f8fc ; color : var ( -- cc - muted ) ; font - size : var ( -- admin - font - caption , 12 px ) ; font - weight : 600 ; }
. qualification - label { gap : 5 px ; font - weight : 600 ; } . qualification - label svg { margin - left : auto ; color : var ( -- el - color - success ) ; }
. qualification - optional { padding : 2 px 5 px ; border - radius : var ( -- admin - radius , 4 px ) ; background : var ( -- el - fill - color - light ) ; color : var ( -- cc - muted ) ; font - size : var ( -- admin - font - caption , 10 px ) ; font - weight : 500 ; line - height : 1.4 ; }
. qualification - file { gap : var ( -- admin - space - 5 , 12 px ) ; } . qualification - file - control { display : flex ; min - width : 0 ; flex : 1 ; flex - wrap : wrap ; align - items : center ; gap : var ( -- admin - space - 3 , 8 px ) ; } . file - picker { position : relative ; display : inline - flex ; flex : 0 0 auto ; align - items : center ; gap : 7 px ; overflow : hidden ; padding : 0 var ( -- admin - space - 5 , 12 px ) ; border : 1 px solid var ( -- cc - border ) ; border - radius : 6 px ; background : var ( -- admin - surface , # fff ) ; color : var ( -- cc - text ) ; cursor : pointer ; } . file - picker : focus - within { outline : 2 px solid color - mix ( in srgb , var ( -- cc - primary ) 35 % , transparent ) ; outline - offset : 2 px ; } . file - picker . is - disabled { cursor : not - allowed ; opacity : .6 ; } . file - picker input { position : absolute ; inset : 0 ; width : 100 % ; height : 100 % ; opacity : 0 ; cursor : inherit ; } . qualification - file - name { min - width : 0 ; overflow : hidden ; color : var ( -- cc - muted ) ; font - size : var ( -- admin - font - caption , 12 px ) ; text - overflow : ellipsis ; } . qualification - validity : deep ( . el - date - editor ) { width : 100 % ; min - width : 0 ; } . qualification - error { width : 100 % ; color : var ( -- el - color - danger ) ; line - height : 1.4 ; }
@@ -1230,6 +1234,12 @@ onMounted(() => { void loadCustomers() })
. qualification - preview - trigger : hover { border - color : var ( -- cc - primary ) ; color : var ( -- cc - primary ) ; }
. qualification - preview - trigger : focus - visible { outline : 2 px solid color - mix ( in srgb , var ( -- cc - primary ) 42 % , transparent ) ; outline - offset : 2 px ; }
. qualification - preview - trigger : disabled { cursor : wait ; opacity : .72 ; }
@ container ( max - width : 660 px ) {
. qualification - row { grid - template - columns : 112 px minmax ( 0 , 1 fr ) ; }
. qualification - header { display : none ; }
. qualification - label { grid - row : span 2 ; align - items : center ; }
. qualification - file , . qualification - validity { min - height : 44 px ; }
}
. qualification - preview - trigger img { width : 100 % ; height : 100 % ; object - fit : contain ; background : var ( -- admin - surface , # fff ) ; }
. qualification - preview - placeholder { display : grid ; place - items : center ; gap : 2 px ; }
. qualification - preview - placeholder small { font - size : var ( -- admin - font - caption , 10 px ) ; font - weight : 700 ; }