完善企业编辑页面并修复采购建单重试

This commit is contained in:
2026-10-30 15:42:38 +08:00
parent d6ef770e48
commit 55868177cd
19 changed files with 568 additions and 224 deletions
@@ -1,11 +1,11 @@
<script setup lang="ts">
import { computed, onBeforeUnmount, onMounted, reactive, ref } from 'vue'
import { useRoute } from 'vue-router'
import { useRoute, useRouter } from 'vue-router'
import { ElMessage, ElMessageBox } from 'element-plus'
import type { FormInstance, FormRules, UploadFile } from 'element-plus'
import type { UploadFile } from 'element-plus'
import { Building2, CheckCircle2, Clock3, FileCheck2, FileText, Pencil, Trash2, Upload, UserRound } from '@lucide/vue'
import DataTable, { type DataTableColumn } from '@/components/common/DataTable.vue'
import { useTenantAdministrationStore, type TenantCompanyProfile, type TenantQualification } from '@/modules/tenant-management/store/tenantAdministration'
import { useTenantAdministrationStore, type TenantQualification } from '@/modules/tenant-management/store/tenantAdministration'
import { useAuthStore } from '@/modules/auth/public'
import { formatQualificationFileSize, qualificationUploadErrorMessage, validateQualificationFile } from '@/modules/tenant-management/utils/qualificationFile'
import { qualificationStatusMeta } from '@/modules/tenant-management/utils/qualificationStatus'
@@ -20,6 +20,7 @@ import {
const store = useTenantAdministrationStore()
const auth = useAuthStore()
const route = useRoute()
const router = useRouter()
const companyApproved = computed(() => store.company.auditStatus === 'ACTIVE')
const auditStatusCopy = computed(() => ({
PROFILE_REQUIRED: { title: '请完善企业资质', detail: '上传营业执照并提交审核后,才能提交头程订单;法人身份证可按需补充。' },
@@ -30,7 +31,6 @@ const auditStatusCopy = computed(() => ({
ARCHIVED: { title: '企业已归档', detail: '该企业已结束使用,资料和历史业务仅供查看,不能再提交或修改。' },
})[store.company.auditStatus])
const activeTab = ref('basic')
const editing = ref(false)
const qualificationOpen = ref(false)
const previewOpen = ref(false)
const previewRecord = ref<TenantQualification | null>(null)
@@ -38,16 +38,13 @@ const previewUrl = ref('')
const previewKind = ref<'image' | 'pdf'>('image')
const previewError = ref('')
const previewLoading = ref(false)
const profileFormRef = ref<FormInstance>()
const qualificationPage = ref(1)
const qualificationPageSize = ref(10)
const qualificationSubmitting = ref(false)
const reviewSubmitting = ref(false)
const deletingQualificationId = ref('')
const profileSubmitting = ref(false)
const loading = ref(false)
const loadError = ref('')
const draft = reactive<TenantCompanyProfile>({ ...store.company })
type QualificationUploadState = 'idle' | 'uploading' | 'uploaded' | 'error'
type QualificationTypeDefinition = { value: MerchantQualificationType; label: string; description: string; required: boolean }
type QualificationDraftItem = QualificationTypeDefinition & {
@@ -146,16 +143,6 @@ const qualificationReviewDisabledReason = computed(() => {
const qualificationPanelHint = computed(() => canUploadQualification.value
? '营业执照为必填;法人身份证、货代资质证书、银行开户许可证可选填。文件保存后需另行提交审核。'
: qualificationUploadDisabledReason.value)
const profileFormRules: FormRules<TenantCompanyProfile> = {
companyName: [{ required: true, whitespace: true, message: '请输入公司名称', trigger: 'blur' }],
legalRepresentative: [{ required: true, whitespace: true, message: '请输入法人姓名', trigger: 'blur' }],
contactName: [{ required: true, whitespace: true, message: '请输入联系人姓名', trigger: 'blur' }],
contactPhone: [
{ required: true, whitespace: true, message: '请输入公司联系电话', trigger: 'blur' },
{ pattern: /^[0-9-]{4,32}$/, message: '公司联系电话仅支持 4–32 位数字或连字符', trigger: 'blur' },
],
contactEmail: [{ type: 'email', message: '请输入正确的联系邮箱', trigger: 'blur' }],
}
const qualificationColumns: DataTableColumn[] = [
{ key: 'actions', label: '操作', width: 132, fixed: 'left', slotName: 'actions' },
{ key: 'type', prop: 'type', label: '文件类型', minWidth: 150 },
@@ -173,7 +160,6 @@ async function refreshCompanyContext() {
loadError.value = ''
try {
await store.loadCompanyContext()
Object.assign(draft, store.company)
return true
} catch (error) {
loadError.value = error instanceof Error ? error.message : '企业资料加载失败'
@@ -197,35 +183,9 @@ onMounted(async () => {
onBeforeUnmount(() => qualificationDrafts.forEach(releaseQualificationPreview))
function startEdit() {
if (store.company.auditStatus === 'ARCHIVED') return
Object.assign(draft, store.company)
profileFormRef.value?.clearValidate()
editing.value = true
if (!auth.hasPermission('company:profile:edit') || store.company.auditStatus === 'ARCHIVED') return
void router.push({ name: 'company-profile-edit' })
}
function cancelEdit() {
Object.assign(draft, store.company)
editing.value = false
profileFormRef.value?.clearValidate()
}
async function saveProfile() {
if (profileSubmitting.value) return
const valid = await profileFormRef.value?.validate().then(() => true).catch(() => false)
if (!valid) return
profileSubmitting.value = true
try {
await store.updateCompany({ ...draft })
Object.assign(draft, store.company)
editing.value = false
ElMessage.success('企业资料已保存')
} catch (error) {
ElMessage.error(error instanceof Error ? error.message : '企业资料保存失败')
} finally {
profileSubmitting.value = false
}
}
function openQualificationDialog() {
if (!canUploadQualification.value) {
ElMessage.warning(qualificationUploadDisabledReason.value)
@@ -619,23 +579,7 @@ function closeQualificationPreview() {
</el-tab-pane>
</el-tabs>
<el-drawer v-model="editing" title="编辑企业资料" size="min(620px, 94vw)" @closed="cancelEdit">
<el-form ref="profileFormRef" :model="draft" :rules="profileFormRules" label-position="top" class="profile-form">
<h3>企业基本信息</h3>
<div class="form-grid-two">
<el-form-item label="公司名称" prop="companyName" required><el-input v-model="draft.companyName" placeholder="请输入公司名称" /></el-form-item>
<el-form-item label="统一社会信用代码"><el-input v-model="draft.creditCode" disabled /></el-form-item>
<el-form-item label="法人姓名" prop="legalRepresentative" required><el-input v-model="draft.legalRepresentative" placeholder="请输入法定代表人姓名" /></el-form-item>
</div>
<h3>联系信息</h3>
<div class="form-grid-two">
<el-form-item label="联系人" prop="contactName" required><el-input v-model="draft.contactName" placeholder="请输入联系人姓名" /></el-form-item>
<el-form-item label="公司联系电话" prop="contactPhone" required><el-input v-model="draft.contactPhone" maxlength="32" inputmode="tel" placeholder="请输入公司联系电话" /><small class="profile-field-hint">仅用于公司业务联系,不会修改任何成员的登录手机号。</small></el-form-item>
<el-form-item label="联系邮箱" prop="contactEmail"><el-input v-model="draft.contactEmail" placeholder="请输入联系邮箱(选填)" /></el-form-item>
</div>
</el-form>
<template #footer><div class="drawer-actions"><el-button :disabled="profileSubmitting" @click="cancelEdit">取消</el-button><el-button type="primary" :loading="profileSubmitting" @click="saveProfile">保存修改</el-button></div></template>
</el-drawer>
<el-dialog
v-model="qualificationOpen"
@@ -741,12 +685,6 @@ function closeQualificationPreview() {
.qualification-panel-actions { display:flex; flex-wrap:wrap; justify-content:flex-end; gap:8px; }
.qualification-update-control { display: inline-flex; }
.mobile-qualification-list { display: none; }
.profile-form h3 { margin: 4px 0 18px; padding-bottom: 10px; border-bottom: 1px solid var(--border); font-size: 15px; }
.profile-form h3:not(:first-child) { margin-top: 22px; }
.profile-field-hint { display: block; margin-top: 5px; color: var(--muted); font-size: 10px; line-height: 1.5; }
.form-grid-two { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 0 16px; }
.form-grid-two .full-row { grid-column: 1 / -1; }
.drawer-actions { display: flex; justify-content: flex-end; gap: 8px; }
.mobile-qualification-actions { display: flex; align-items: center; gap: 8px; }
.qualification-dialog-intro { display: flex; align-items: flex-start; justify-content: space-between; gap: 18px; margin-bottom: 16px; padding: 13px 15px; background: #f4f7f7; }
.qualification-dialog-intro strong { color: var(--navy); font-size: 13px; }
@@ -784,7 +722,7 @@ function closeQualificationPreview() {
.document-preview > span { max-width: 440px; padding: 0 16px; color: var(--muted); font-size: 11px; line-height: 1.6; text-align: center; }
.document-preview-error { max-width: 440px; margin: 0; padding: 0 16px; color: #9a5a09; font-size: 11px; line-height: 1.6; text-align: center; }
@media (max-width: 720px) {
.profile-grid, .form-grid-two { grid-template-columns: 1fr; }
.profile-grid { grid-template-columns: 1fr; }
.qualification-dialog-intro { flex-direction: column; gap: 5px; }
.qualification-dialog-intro span { text-align: left; }
.qualification-upload-grid { grid-template-columns: 1fr; }