feat: 完成客户端联调与通用列表组件
This commit is contained in:
@@ -1,8 +1,9 @@
|
||||
<script setup lang="ts">
|
||||
import { computed, onMounted, reactive, ref } from 'vue'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import type { UploadFile, UploadInstance } from 'element-plus'
|
||||
import type { FormInstance, FormRules, UploadFile, UploadInstance } 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 '@/stores/tenantAdministration'
|
||||
import { useAuthStore } from '@/stores/auth'
|
||||
import { formatQualificationFileSize, validateQualificationFile } from '@/utils/qualificationFile'
|
||||
@@ -25,7 +26,11 @@ const previewOpen = ref(false)
|
||||
const previewRecord = ref<TenantQualification | null>(null)
|
||||
const previewUrl = ref('')
|
||||
const previewLoading = ref(false)
|
||||
const profileFormRef = ref<FormInstance>()
|
||||
const qualificationFormRef = ref<FormInstance>()
|
||||
const uploadRef = ref<UploadInstance>()
|
||||
const qualificationPage = ref(1)
|
||||
const qualificationPageSize = ref(10)
|
||||
const selectedFileSize = ref(0)
|
||||
const selectedFileType = ref('')
|
||||
const qualificationFileError = ref('')
|
||||
@@ -36,6 +41,28 @@ const loadError = ref('')
|
||||
const selectedFile = ref<File | null>(null)
|
||||
const draft = reactive<TenantCompanyProfile>({ ...store.company })
|
||||
const qualificationDraft = reactive({ type: '营业执照', fileName: '', certificateNo: '' })
|
||||
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' }],
|
||||
contactEmail: [{ type: 'email', message: '请输入正确的联系邮箱', trigger: 'blur' }],
|
||||
}
|
||||
const qualificationFormRules: FormRules = {
|
||||
fileName: [{ required: true, message: '请选择营业执照图片', trigger: 'change' }],
|
||||
}
|
||||
const qualificationColumns: DataTableColumn[] = [
|
||||
{ key: 'actions', label: '操作', width: 90, fixed: 'left', slotName: 'actions' },
|
||||
{ key: 'type', prop: 'type', label: '文件类型', minWidth: 150 },
|
||||
{ key: 'fileName', prop: 'fileName', label: '文件名称', minWidth: 220, showOverflowTooltip: true },
|
||||
{ key: 'status', label: '状态', width: 110, slotName: 'status' },
|
||||
{ key: 'expiresAt', prop: 'expiresAt', label: '有效期', width: 130 },
|
||||
{ key: 'updatedAt', prop: 'updatedAt', label: '更新时间', minWidth: 160 },
|
||||
]
|
||||
const pagedQualifications = computed(() => {
|
||||
const start = (qualificationPage.value - 1) * qualificationPageSize.value
|
||||
return store.qualifications.slice(start, start + qualificationPageSize.value)
|
||||
})
|
||||
|
||||
async function loadCompanyContext() {
|
||||
loading.value = true
|
||||
@@ -54,20 +81,20 @@ onMounted(() => void loadCompanyContext())
|
||||
|
||||
function startEdit() {
|
||||
Object.assign(draft, store.company)
|
||||
profileFormRef.value?.clearValidate()
|
||||
editing.value = true
|
||||
}
|
||||
|
||||
function cancelEdit() {
|
||||
Object.assign(draft, store.company)
|
||||
editing.value = false
|
||||
profileFormRef.value?.clearValidate()
|
||||
}
|
||||
|
||||
async function saveProfile() {
|
||||
if (profileSubmitting.value) return
|
||||
if (!draft.companyName || !draft.legalRepresentative || !draft.contactName || !draft.contactPhone) {
|
||||
ElMessage.warning('请完整填写企业名称、法人及联系人信息')
|
||||
return
|
||||
}
|
||||
const valid = await profileFormRef.value?.validate().then(() => true).catch(() => false)
|
||||
if (!valid) return
|
||||
profileSubmitting.value = true
|
||||
try {
|
||||
await store.updateCompany({ ...draft })
|
||||
@@ -127,12 +154,14 @@ function resetQualificationDraft() {
|
||||
selectedFileType.value = ''
|
||||
qualificationFileError.value = ''
|
||||
selectedFile.value = null
|
||||
qualificationFormRef.value?.clearValidate()
|
||||
}
|
||||
|
||||
async function submitQualification() {
|
||||
if (qualificationSubmitting.value) return
|
||||
if (!qualificationDraft.fileName || !selectedFile.value) {
|
||||
ElMessage.warning('请选择营业执照图片')
|
||||
const valid = await qualificationFormRef.value?.validate().then(() => true).catch(() => false)
|
||||
if (!valid || !selectedFile.value) {
|
||||
qualificationFileError.value = '请选择营业执照图片'
|
||||
return
|
||||
}
|
||||
if (qualificationFileError.value) {
|
||||
@@ -226,14 +255,20 @@ function qualificationStatus(status: string) {
|
||||
<template #label><span class="tab-label"><FileCheck2 :size="16" />资质文件</span></template>
|
||||
<div class="client-card qualification-panel">
|
||||
<header><div><h3>企业资质</h3><p>文件更新后需等待平台重新审核,历史业务不受影响。</p></div><el-button v-if="auth.hasPermission('company:qualification:upload')" type="primary" @click="openQualificationDialog"><Upload :size="16" />更新资质</el-button></header>
|
||||
<el-table class="desktop-qualification-table" :data="store.qualifications" row-key="id" empty-text="暂无企业资质记录">
|
||||
<el-table-column label="操作" width="90" fixed="left"><template #default="{ row }"><el-button link type="primary" @click="previewQualification(row as TenantQualification)">查看</el-button></template></el-table-column>
|
||||
<el-table-column prop="type" label="文件类型" min-width="150" />
|
||||
<el-table-column prop="fileName" label="文件名称" min-width="220" show-overflow-tooltip />
|
||||
<el-table-column label="状态" width="110"><template #default="{ row }"><el-tag :type="row.status === 'VERIFIED' ? 'success' : row.status === 'PENDING' ? 'warning' : 'danger'" effect="light">{{ qualificationStatus(row.status) }}</el-tag></template></el-table-column>
|
||||
<el-table-column prop="expiresAt" label="有效期" width="130" />
|
||||
<el-table-column prop="updatedAt" label="更新时间" min-width="160" />
|
||||
</el-table>
|
||||
<DataTable
|
||||
v-model:page="qualificationPage"
|
||||
v-model:page-size="qualificationPageSize"
|
||||
class="desktop-qualification-table"
|
||||
:columns="qualificationColumns"
|
||||
:data="pagedQualifications"
|
||||
:empty-text="'暂无企业资质记录'"
|
||||
:page-sizes="[10, 20, 50]"
|
||||
:total="store.qualifications.length"
|
||||
row-key="id"
|
||||
>
|
||||
<template #actions="{ row }"><el-button link type="primary" @click="previewQualification(row as TenantQualification)">查看</el-button></template>
|
||||
<template #status="{ row }"><el-tag :type="row.status === 'VERIFIED' ? 'success' : row.status === 'PENDING' ? 'warning' : 'danger'" effect="light">{{ qualificationStatus(row.status) }}</el-tag></template>
|
||||
</DataTable>
|
||||
<div class="mobile-qualification-list">
|
||||
<article v-for="record in store.qualifications" :key="record.id">
|
||||
<header><strong>{{ record.type }}</strong><el-tag :type="record.status === 'VERIFIED' ? 'success' : record.status === 'PENDING' ? 'warning' : 'danger'" effect="light">{{ qualificationStatus(record.status) }}</el-tag></header>
|
||||
@@ -248,27 +283,27 @@ function qualificationStatus(status: string) {
|
||||
</el-tabs>
|
||||
|
||||
<el-drawer v-model="editing" title="编辑企业资料" size="min(620px, 94vw)" @closed="cancelEdit">
|
||||
<el-form label-position="top" class="profile-form">
|
||||
<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="公司名称" required><el-input v-model="draft.companyName" /></el-form-item>
|
||||
<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="法人姓名" required><el-input v-model="draft.legalRepresentative" /></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="联系人" required><el-input v-model="draft.contactName" /></el-form-item>
|
||||
<el-form-item label="联系电话" required><el-input v-model="draft.contactPhone" /></el-form-item>
|
||||
<el-form-item label="联系邮箱"><el-input v-model="draft.contactEmail" /></el-form-item>
|
||||
<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" placeholder="请输入联系电话" /></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" title="更新资质文件" width="min(520px, 92vw)" @closed="resetQualificationDraft">
|
||||
<el-form label-position="top">
|
||||
<el-form ref="qualificationFormRef" :model="qualificationDraft" :rules="qualificationFormRules" label-position="top">
|
||||
<el-form-item label="文件类型"><el-input v-model="qualificationDraft.type" disabled /></el-form-item>
|
||||
<el-form-item label="选择文件" required :error="qualificationFileError">
|
||||
<el-form-item label="选择文件" prop="fileName" required :error="qualificationFileError">
|
||||
<el-upload ref="uploadRef" :auto-upload="false" :limit="1" :show-file-list="false" accept=".jpg,.jpeg,.png" @change="handleFileChange">
|
||||
<el-button><Upload :size="16" />选择文件</el-button>
|
||||
<template #tip><div class="upload-tip">仅支持 JPG、PNG,单张图片不超过 5MB。</div></template>
|
||||
|
||||
Reference in New Issue
Block a user