2025-10-15 11:18:48 +08:00

449 lines
14 KiB
Vue

<template>
<a-modal
:width="800"
:open="modal.open"
:title="modal.title"
:confirm-loading="modal.confirmLoading"
:after-close="onAfterClose"
:cancel-text="isViewMode ? '关闭' : '取消'"
:ok-text="okText"
@ok="handleOk"
@cancel="handleCancel"
:ok-button-props="{ hidden: isViewMode }"
>
<a-form layout="vertical" ref="formRef" :model="formData" :rules="formRules">
<!-- 基本信息 -->
<a-card title="基本信息" class="mb-4">
<a-row :gutter="16">
<a-col :span="12">
<a-form-item label="服务组织名称" name="orgName">
<a-input v-model:value="formData.orgName" :disabled="true" placeholder="系统生成或上级指定" />
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item label="组织编号" name="orgCode">
<a-input v-model:value="formData.orgCode" :disabled="true" placeholder="系统自动生成" />
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item label="组织机构代码" name="orgIdentityCode" :required="!isViewMode">
<a-input
v-model:value="formData.orgIdentityCode"
:disabled="isViewMode"
placeholder="请输入统一社会信用代码等"
/>
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item label="等级" name="level" :required="!isViewMode">
<a-select
v-model:value="formData.level"
:disabled="isViewMode"
placeholder="请选择等级"
>
<a-select-option value="1">一级</a-select-option>
<a-select-option value="2">二级</a-select-option>
<a-select-option value="3">三级</a-select-option>
<a-select-option value="4">四级</a-select-option>
<a-select-option value="5">五级</a-select-option>
</a-select>
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item label="负责人姓名" name="manager" :required="!isViewMode">
<a-input
v-model:value="formData.manager"
:disabled="isViewMode"
placeholder="请输入负责人姓名"
/>
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item label="联系电话" name="phone" :required="!isViewMode">
<a-input
v-model:value="formData.phone"
:disabled="isViewMode"
placeholder="请输入联系电话"
/>
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item label="法人姓名">
<a-input
v-model:value="formData.legalPerson"
:disabled="isViewMode"
placeholder="请输入法人姓名"
/>
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item label="法人联系电话">
<a-input
v-model:value="formData.legalPhone"
:disabled="isViewMode"
placeholder="请输入法人联系电话"
/>
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item label="营业执照名称">
<a-input
v-model:value="formData.businessLicenseName"
:disabled="isViewMode"
placeholder="请输入营业执照上的全称"
/>
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item label="登记机关">
<a-input
v-model:value="formData.registrationAuthority"
:disabled="isViewMode"
placeholder="如:南通市通州区市场监督管理局"
/>
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item label="登记证号">
<a-input
v-model:value="formData.registrationNumber"
:disabled="isViewMode"
placeholder="社会组织登记证号"
/>
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item label="中标组织">
<a-select
v-model:value="formData.isWinningOrg"
:disabled="isViewMode"
placeholder="请选择是否为中标组织"
>
<a-select-option value="yes"></a-select-option>
<a-select-option value="no"></a-select-option>
</a-select>
</a-form-item>
</a-col>
</a-row>
</a-card>
<!-- 钱包设置 -->
<a-card title="钱包设置" class="mb-4">
<a-row :gutter="16">
<a-col :span="12">
<a-form-item label="使用钱包" name="useWallet">
<a-switch v-model:checked="formData.useWallet" :disabled="isViewMode" />
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item label="可用钱包" name="availableWallets">
<a-select
mode="multiple"
v-model:value="formData.availableWallets"
placeholder="选择可接入的钱包"
:disabled="isViewMode || !formData.useWallet"
>
<a-select-option value="wallet_a">通用助餐钱包</a-select-option>
<a-select-option value="wallet_b">居家服务钱包</a-select-option>
<a-select-option value="wallet_c">康复辅具钱包</a-select-option>
</a-select>
</a-form-item>
</a-col>
</a-row>
</a-card>
<!-- 地址信息 -->
<a-card title="地址信息" class="mb-4">
<a-row :gutter="16">
<a-col :span="24">
<a-form-item label="服务组织地址" name="address" :required="!isViewMode">
<a-cascader
v-model:value="formData.address"
:options="addressOptions"
:disabled="isViewMode"
placeholder="请选择省/市/区/街道"
style="width: 100%"
/>
</a-form-item>
</a-col>
<a-col :span="24">
<a-form-item label="详细地址" name="detailAddress" :required="!isViewMode">
<a-input
v-model:value="formData.detailAddress"
:disabled="isViewMode"
placeholder="请输入街道门牌号等详细信息"
/>
</a-form-item>
</a-col>
<a-col :span="24">
<a-form-item label="地图定位地址">
<a-input
v-model:value="formData.location"
placeholder="点击右侧按钮选择地图位置"
readonly
addon-after-icon="environment"
:disabled="isViewMode"
>
<template #addonAfter>
<a-button
v-if="!isViewMode"
type="link"
@click="openMapSelector"
>
选择位置
</a-button>
<span v-else>已定位</span>
</template>
</a-input>
</a-form-item>
</a-col>
</a-row>
</a-card>
<!-- 资质上传 -->
<a-card title="资质材料" class="mb-4">
<a-row :gutter="16">
<a-col :span="24">
<a-form-item label="上传资质附件">
<a-upload
v-model:file-list="formData.qualificationFiles"
:before-upload="beforeUploadFile"
accept=".pdf,.doc,.docx"
:max-count="3"
:disabled="isViewMode"
>
<a-button v-if="!isViewMode" type="primary" ghost>
<plus-outlined /> 上传文件
</a-button>
</a-upload>
</a-form-item>
</a-col>
<a-col :span="24">
<a-form-item label="上传资质图片">
<a-upload
list-type="picture-card"
v-model:file-list="formData.qualificationImages"
:before-upload="beforeUploadImage"
:max-count="5"
:disabled="isViewMode"
>
<div v-if="!isViewMode && formData.qualificationImages.length < 5">
<plus-outlined />
<div class="ant-upload-text">上传图片</div>
</div>
</a-upload>
</a-form-item>
</a-col>
<a-col :span="24">
<a-form-item label="上传营业执照">
<a-upload
list-type="picture-card"
v-model:file-list="formData.businessLicenseImage"
:before-upload="beforeUploadImage"
:max-count="1"
:disabled="isViewMode"
>
<div v-if="!isViewMode && !formData.businessLicenseImage.length">
<plus-outlined />
<div class="ant-upload-text">上传执照</div>
</div>
</a-upload>
</a-form-item>
</a-col>
</a-row>
</a-card>
<!-- 其他信息 -->
<a-card title="其他信息" class="mb-4">
<a-form-item label="备注">
<a-textarea
v-model:value="formData.remark"
rows="4"
:disabled="isViewMode"
placeholder="请输入备注信息"
/>
</a-form-item>
</a-card>
</a-form>
</a-modal>
</template>
<script setup>
import { ref, reactive, defineEmits, defineExpose, computed } from 'vue' // ✅ 补充 computed
import { PlusOutlined } from '@ant-design/icons-vue'
import { message } from 'ant-design-vue'
import { useModal, useForm } from '@/hooks'
const emit = defineEmits(['ok'])
const { modal, showModal, hideModal, showLoading, hideLoading } = useModal()
const { formData, formRef, formRules, resetForm } = useForm()
// 初始化数据模型
formData.value = {
orgName: '',
orgCode: '',
orgIdentityCode: '',
level: '',
manager: '',
phone: '',
legalPerson: '',
legalPhone: '',
businessLicenseName: '',
registrationAuthority: '',
registrationNumber: '',
isWinningOrg: '',
useWallet: false,
availableWallets: [],
address: [],
detailAddress: '',
location: '',
qualificationFiles: [],
qualificationImages: [],
businessLicenseImage: [],
remark: '',
mode: 'edit' // 默认编辑模式
}
// 表单验证规则:查看模式下无需验证
formRules.value = {
orgIdentityCode: [{ required: true, message: '请输入组织机构代码' }],
level: [{ required: true, message: '请选择等级' }],
manager: [{ required: true, message: '请输入负责人姓名' }],
phone: [
{ required: true, message: '请输入联系电话' },
{ pattern: /^1[3-9]\d{9}$/, message: '请输入正确的手机号码' }
],
address: [{ required: true, message: '请选择服务组织地址' }],
detailAddress: [{ required: true, message: '请输入详细地址' }]
}
// 地址选项
const addressOptions = ref([
{
value: 'jiangsu',
label: '江苏省',
children: [
{
value: 'nantong',
label: '南通市',
children: [
{
value: 'tongzhou',
label: '通州区',
children: [
{ value: 'liuqiao', label: '刘桥镇' },
{ value: 'pingchao', label: '平潮镇' }
]
}
]
}
]
}
])
// ✅ 计算属性:是否为查看模式
const isViewMode = computed(() => formData.value.mode === 'view')
const okText = ref('确定')
/**
* 打开地图选择器
*/
function openMapSelector() {
formData.value.location = '江苏省南通市通州区刘桥镇人民政府附近 (经纬度: 32.1234, 120.5678)'
}
/**
* 文件上传前校验(文件)
*/
function beforeUploadFile(file) {
const isPdfOrDoc = [
'application/pdf',
'application/msword',
'application/vnd.openxmlformats-officedocument.wordprocessingml.document'
].includes(file.type)
if (!isPdfOrDoc) {
message.error('仅支持上传 PDF 或 Word 文档!')
return Upload.LIST_IGNORE
}
const isLt5M = file.size / 1024 / 1024 < 5
if (!isLt5M) {
message.error('文件大小不能超过 5MB!')
return Upload.LIST_IGNORE
}
return true
}
/**
* 图片上传前校验
*/
function beforeUploadImage(file) {
const isImg = file.type.startsWith('image/')
if (!isImg) {
message.error('只能上传图片文件!')
return false
}
const isLt2M = file.size / 1024 / 1024 < 2
if (!isLt2M) {
message.error('图片大小不能超过 2MB!')
return false
}
return true
}
// 暴露方法给父组件
defineExpose({
open({ record, mode = 'edit' }) {
showModal({
type: mode,
title: mode === 'edit' ? '编辑服务组织' : '服务组织详情'
})
Object.assign(formData.value, record || {})
formData.value.mode = mode
}
})
/**
* 提交处理(仅编辑模式触发)
*/
function handleOk() {
if (isViewMode.value) return // 安全兜底
formRef.value
.validateFields()
.then((values) => {
showLoading()
try {
console.log('提交数据:', values)
setTimeout(() => {
hideLoading()
hideModal()
emit('ok')
message.success('操作成功')
}, 800)
} catch (e) {
hideLoading()
}
})
.catch(() => hideLoading())
}
function handleCancel() {
hideModal()
}
function onAfterClose() {
resetForm()
}
</script>
<style lang="less" scoped>
.mb-4 {
margin-bottom: 16px;
}
.ant-upload-list-picture-card .ant-upload-list-item,
.ant-upload-list-picture .ant-upload-list-item {
width: 104px;
height: 104px;
}
</style>