generated from Leo_Ding/web-template
代码修改
This commit is contained in:
parent
7b65c5e27f
commit
e51736879a
@ -1,5 +1,7 @@
|
||||
// 服务设施模块
|
||||
import request from '@/utils/request'
|
||||
|
||||
// 节点管理
|
||||
// 获取节点
|
||||
export const getNodeList = (params) => request.basic.get('/api/v1/service-nodes', params)
|
||||
|
||||
@ -9,3 +11,41 @@ export const createNode = (params) => request.basic.post('/api/v1/service-nodes'
|
||||
// 删除节点
|
||||
export const delNode = (id) => request.basic.delete(`/api/v1/service-nodes/${id}`)
|
||||
|
||||
// 服务组织管理
|
||||
// 新建服务组织
|
||||
export const createServiceOrg = (params) => request.basic.post('/api/v1/organizations', params)
|
||||
|
||||
// 获取服务组织列表
|
||||
export const getServiceOrgList = (params) => request.basic.get('/api/v1/organizations', params)
|
||||
|
||||
// 获取服务组织详情
|
||||
export const getServiceOrgDetail = (id) => request.basic.get(`/api/v1/organizations/${id}`)
|
||||
|
||||
// 修改服务组织
|
||||
export const updateServiceOrg = (id, params) => request.basic.put(`/api/v1/organizations/${id}`, params)
|
||||
|
||||
// 停用启用接口
|
||||
export const enableOrDisable = (id, params) => request.basic.put(`/api/v1/organizations/status/${id}`, params)
|
||||
|
||||
// 服务站点
|
||||
// 新增服务站点
|
||||
export const createServiceSite = (params) => request.basic.post('/api/v1/stations', params)
|
||||
|
||||
// 获取所有机构下拉
|
||||
export const getOrgSelect = () => request.basic.get('/api/v1/organizations/all')
|
||||
|
||||
|
||||
// 获取服务站点列表
|
||||
export const getServiceSiteList = (params) => request.basic.get('/api/v1/stations', params)
|
||||
|
||||
// 获取服务站点详情
|
||||
export const getServiceSiteDetail = (id) => request.basic.get(`/api/v1/stations/${id}`)
|
||||
|
||||
// 修改服务站点
|
||||
export const updateServiceSite = (id, params) => request.basic.put(`/api/v1/stations/${id}`, params)
|
||||
|
||||
// 删除服务站点
|
||||
export const delServiceSite = (id) => request.basic.delete(`/api/v1/stations/${id}`)
|
||||
|
||||
//停用启用服务站点的参数是id和params,params里面有status,1为启用,0为停用
|
||||
export const enableOrDisableServiceSite = (id, params) => request.basic.put(`/api/v1/stations/status/${id}`, params)
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<!-- 主弹框:标题显示当前组织名称 -->
|
||||
<a-modal
|
||||
:title="`${orgRecord.orgName || '组织'} - 设备管理`"
|
||||
:title="`${currentOrg.orgName || '组织'} - 设备管理`"
|
||||
v-model:visible="visible"
|
||||
:maskClosable="false"
|
||||
:width="800"
|
||||
@ -22,14 +22,12 @@
|
||||
row-key="deviceId"
|
||||
:pagination="false"
|
||||
>
|
||||
<!-- 连接状态列:用徽章显示 -->
|
||||
<template #bodyCell="{ column, record }">
|
||||
<template v-if="column.key === 'online'">
|
||||
<a-badge :status="record.online ? 'success' : 'error'">
|
||||
{{ record.online ? '在线' : '离线' }}
|
||||
</a-badge>
|
||||
</template>
|
||||
<!-- 操作列:编辑/删除 -->
|
||||
<template v-if="column.key === 'action'">
|
||||
<a-button size="small" type="link" @click="handleEdit(record)">
|
||||
编辑
|
||||
@ -51,7 +49,6 @@
|
||||
>
|
||||
<a-form
|
||||
:model="formData"
|
||||
:rules="formRules"
|
||||
ref="formRef"
|
||||
layout="horizontal"
|
||||
:label-col="{ span: 6 }"
|
||||
@ -114,18 +111,12 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive, defineProps, defineEmits, defineExpose } from 'vue';
|
||||
import { ref, reactive, defineExpose } from 'vue';
|
||||
import { PlusOutlined } from '@ant-design/icons-vue';
|
||||
import { message, Form } from 'ant-design-vue';
|
||||
import { message } from 'ant-design-vue';
|
||||
|
||||
// 1. 定义props:接收父组件传递的组织信息
|
||||
const props = defineProps({
|
||||
orgRecord: {
|
||||
type: Object,
|
||||
default: () => ({ orgName: '默认组织' }), // 默认值防止空值报错
|
||||
required: false
|
||||
}
|
||||
})
|
||||
// ✅ 1. 不再定义 props.orgRecord 为可修改对象,而是用内部 ref 存储
|
||||
const currentOrg = ref({ orgName: '默认组织' }); // 当前管理的组织
|
||||
|
||||
// 弹框状态
|
||||
const visible = ref(false);
|
||||
@ -133,7 +124,22 @@ const showAddModal = ref(false);
|
||||
const formRef = ref(null);
|
||||
const isEditing = ref(false);
|
||||
|
||||
// 2. 设备表格列配置(优化显示文本)
|
||||
// 设备列表(后续可替换为 API 数据)
|
||||
const devices = ref([
|
||||
{ deviceId: 'DEV001', deviceName: '温度传感器', deviceType: 'sensor', deviceManufacturer: 'vendor1', online: true },
|
||||
{ deviceId: 'DEV002', deviceName: '智能控制器', deviceType: 'controller', deviceManufacturer: 'vendor2', online: false },
|
||||
{ deviceId: 'DEV003', deviceName: '网络网关', deviceType: 'gateway', deviceManufacturer: 'vendor3', online: true },
|
||||
]);
|
||||
|
||||
// 表单数据
|
||||
const formData = reactive({
|
||||
deviceId: '',
|
||||
deviceName: '',
|
||||
deviceType: '',
|
||||
deviceManufacturer: '',
|
||||
});
|
||||
|
||||
// 列配置(保持不变)
|
||||
const columns = ref([
|
||||
{ title: '设备ID', dataIndex: 'deviceId', key: 'deviceId', align: 'center' },
|
||||
{ title: '设备名称', dataIndex: 'deviceName', key: 'deviceName', align: 'center' },
|
||||
@ -167,73 +173,49 @@ const columns = ref([
|
||||
{ title: '操作', key: 'action', align: 'center', fixed: 'right', width: 120 }
|
||||
]);
|
||||
|
||||
// 设备数据(后续可替换为接口请求:根据orgRecord.id获取该组织的设备)
|
||||
const devices = ref([
|
||||
{ deviceId: 'DEV001', deviceName: '温度传感器', deviceType: 'sensor', deviceManufacturer: 'vendor1', online: true },
|
||||
{ deviceId: 'DEV002', deviceName: '智能控制器', deviceType: 'controller', deviceManufacturer: 'vendor2', online: false },
|
||||
{ deviceId: 'DEV003', deviceName: '网络网关', deviceType: 'gateway', deviceManufacturer: 'vendor3', online: true },
|
||||
]);
|
||||
|
||||
// 表单数据
|
||||
const formData = reactive({
|
||||
deviceId: '',
|
||||
deviceName: '',
|
||||
deviceType: '',
|
||||
deviceManufacturer: '',
|
||||
});
|
||||
|
||||
// 表单验证规则
|
||||
const formRules = reactive({
|
||||
deviceId: [{ required: true, message: '请输入设备ID' }],
|
||||
deviceName: [{ required: true, message: '请输入设备名称' }],
|
||||
deviceType: [{ required: true, message: '请选择设备类型' }],
|
||||
deviceManufacturer: [{ required: true, message: '请选择设备供应商' }],
|
||||
});
|
||||
|
||||
// 3. 暴露给父组件的方法:打开弹框(可接收参数)
|
||||
// ✅ 2. 暴露 open 方法:接收 orgRecord 并保存到 currentOrg
|
||||
function open(options = {}) {
|
||||
const { orgRecord } = options;
|
||||
if (orgRecord) {
|
||||
// 更新当前组织信息(父组件传递的组织数据)
|
||||
props.orgRecord = orgRecord;
|
||||
currentOrg.value = { ...orgRecord }; // 深拷贝避免引用问题
|
||||
} else {
|
||||
currentOrg.value = { orgName: '默认组织' };
|
||||
}
|
||||
|
||||
// ✅ 未来可在这里调用 API 加载该组织的设备:
|
||||
// loadDevicesByOrgId(currentOrg.value.id);
|
||||
|
||||
visible.value = true;
|
||||
}
|
||||
|
||||
// 关闭主弹框
|
||||
function handleCancel() {
|
||||
visible.value = false;
|
||||
// 关闭主弹框时同时关闭子弹框并重置表单
|
||||
showAddModal.value = false;
|
||||
resetForm();
|
||||
}
|
||||
|
||||
// 提交表单(添加/编辑设备)
|
||||
// 提交表单
|
||||
async function handleFormSubmit() {
|
||||
try {
|
||||
// 表单验证
|
||||
await formRef.value.validate();
|
||||
|
||||
if (isEditing.value) {
|
||||
// 编辑设备:更新现有数据
|
||||
const index = devices.value.findIndex(dev => dev.deviceId === formData.deviceId);
|
||||
if (index !== -1) {
|
||||
devices.value[index] = { ...formData, online: devices.value[index].online };
|
||||
message.success('设备编辑成功');
|
||||
}
|
||||
} else {
|
||||
// 添加设备:检查ID唯一性
|
||||
const isExist = devices.value.some(dev => dev.deviceId === formData.deviceId);
|
||||
if (isExist) {
|
||||
message.error('设备ID已存在');
|
||||
return;
|
||||
}
|
||||
// 新增设备(默认离线)
|
||||
devices.value.push({ ...formData, online: false });
|
||||
message.success('设备添加成功');
|
||||
}
|
||||
|
||||
// 关闭子弹框并重置表单
|
||||
showAddModal.value = false;
|
||||
resetForm();
|
||||
} catch (error) {
|
||||
@ -253,7 +235,7 @@ function resetForm() {
|
||||
formData.deviceManufacturer = '';
|
||||
}
|
||||
|
||||
// 编辑设备:加载当前设备数据到表单
|
||||
// 编辑设备
|
||||
function handleEdit(record) {
|
||||
isEditing.value = true;
|
||||
formData.deviceId = record.deviceId;
|
||||
@ -269,14 +251,13 @@ function handleDelete(record) {
|
||||
message.success('设备已删除');
|
||||
}
|
||||
|
||||
// 4. 暴露方法给父组件调用
|
||||
// ✅ 3. 暴露 open 方法给父组件
|
||||
defineExpose({
|
||||
open,
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
/* 可选:调整弹框内边距 */
|
||||
.ant-modal-body {
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
@ -0,0 +1,449 @@
|
||||
<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>
|
||||
@ -1,449 +1,526 @@
|
||||
<template>
|
||||
<a-modal
|
||||
:width="800"
|
||||
:open="modal.open"
|
||||
:title="modal.title"
|
||||
:confirm-loading="modal.confirmLoading"
|
||||
:open="visible"
|
||||
:title="mode === 'create' ? '新增组织' : mode === 'edit' ? '编辑组织' : '组织详情'"
|
||||
:confirm-loading="confirmLoading"
|
||||
:after-close="onAfterClose"
|
||||
:cancel-text="isViewMode ? '关闭' : '取消'"
|
||||
:ok-text="okText"
|
||||
:cancel-text="t('button.cancel')"
|
||||
:ok-text="mode === 'view' ? t('button.close') : mode === 'edit' ? '保存' : '新增'"
|
||||
@ok="handleOk"
|
||||
@cancel="handleCancel"
|
||||
:ok-button-props="{ hidden: isViewMode }"
|
||||
:maskClosable="false"
|
||||
>
|
||||
<a-form layout="vertical" ref="formRef" :model="formData" :rules="formRules">
|
||||
<!-- 基本信息 -->
|
||||
<a-card title="基本信息" class="mb-4">
|
||||
<a-form
|
||||
ref="formRef"
|
||||
:model="formData"
|
||||
:rules="isView ? {} : formRules"
|
||||
layout="vertical"
|
||||
autocomplete="off"
|
||||
:disabled="isView"
|
||||
>
|
||||
<!-- 基础信息 -->
|
||||
<a-card class="mb-4" title="基础信息">
|
||||
<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 :label="'组织名称'" name="name" :required="true">
|
||||
<a-input v-model:value="formData.name" placeholder="请输入组织全称" allow-clear />
|
||||
</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 :label="'组织机构代码'" name="orgCode" :required="true">
|
||||
<a-input v-model:value="formData.orgCode" placeholder="统一社会信用代码或组织机构代码" allow-clear />
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
</a-row>
|
||||
<a-row :gutter="16">
|
||||
<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-form-item :label="'组织等级'" name="orgLv" :required="true">
|
||||
<a-select v-model:value="formData.orgLv" placeholder="请选择组织等级" allow-clear>
|
||||
<a-select-option
|
||||
v-for="item in dicsStore.dictOptions.Level"
|
||||
:key="item.dval"
|
||||
:value="item.dval"
|
||||
>
|
||||
{{ item.introduction }}
|
||||
</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
</a-row>
|
||||
</a-card>
|
||||
|
||||
<!-- 钱包设置 -->
|
||||
<a-card title="钱包设置" class="mb-4">
|
||||
<!-- 联系人信息 -->
|
||||
<a-card class="mb-4" title="联系人信息" style="margin-top: 20px">
|
||||
<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 :label="'负责人姓名'" name="concatName" :required="true">
|
||||
<a-input v-model:value="formData.concatName" placeholder="请输入负责人姓名" allow-clear />
|
||||
</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 :label="'联系电话'" name="concatPhone" :required="true">
|
||||
<a-input v-model:value="formData.concatPhone" placeholder="请输入手机号或固话" allow-clear />
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
</a-row>
|
||||
<a-row :gutter="16">
|
||||
<a-col :span="12">
|
||||
<a-form-item :label="'法人姓名'" name="legalName">
|
||||
<a-input v-model:value="formData.legalName" placeholder="非必填" allow-clear />
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="12">
|
||||
<a-form-item :label="'法人联系电话'" name="legalPhone">
|
||||
<a-input v-model:value="formData.legalPhone" placeholder="非必填" allow-clear />
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
</a-row>
|
||||
</a-card>
|
||||
|
||||
<!-- 资质信息 -->
|
||||
<a-card class="mb-4" title="资质信息" style="margin-top: 20px">
|
||||
<template #extra>
|
||||
<a-tooltip title="营业执照、登记机关等用于资质审核">
|
||||
<info-circle-outlined style="color: #8c8c8c" />
|
||||
</a-tooltip>
|
||||
</template>
|
||||
<a-row :gutter="16">
|
||||
<a-col :span="12">
|
||||
<a-form-item :label="'营业执照名称'" name="businessLicenseName">
|
||||
<a-input v-model:value="formData.businessLicenseName" placeholder="非必填" allow-clear />
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="12">
|
||||
<a-form-item :label="'登记机关'" name="registrationAuthorityName">
|
||||
<a-input v-model:value="formData.registrationAuthorityName" placeholder="非必填" allow-clear />
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
</a-row>
|
||||
<a-row :gutter="16">
|
||||
<a-col :span="24">
|
||||
<a-form-item :label="'登记证号'" name="registrationAuthorityNo">
|
||||
<a-input v-model:value="formData.registrationAuthorityNo" placeholder="非必填" allow-clear />
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
</a-row>
|
||||
<a-row :gutter="16">
|
||||
<a-col :span="24">
|
||||
<a-form-item :label="'中标组织'" name="winOrg">
|
||||
<a-input v-model:value="formData.winOrg" placeholder="若为中标单位请填写,否则可留空" allow-clear />
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
</a-row>
|
||||
</a-card>
|
||||
|
||||
<!-- 资质附件 -->
|
||||
<a-card class="mb-4" title="资质附件" style="margin-top: 20px">
|
||||
<!-- 营业执照 -->
|
||||
<a-form-item :label="'营业执照图片'" name="businessLicenseFiles">
|
||||
<a-upload
|
||||
v-model:file-list="formData.businessLicenseFiles"
|
||||
list-type="picture-card"
|
||||
:before-upload="beforeUploadImage"
|
||||
:custom-request="dummyRequest"
|
||||
accept="image/*"
|
||||
multiple
|
||||
:disabled="isView"
|
||||
>
|
||||
<div v-if="formData.businessLicenseFiles.length < 5">
|
||||
<plus-outlined />
|
||||
<div class="ant-upload-text">上传</div>
|
||||
</div>
|
||||
</a-upload>
|
||||
<div class="upload-tip">仅支持 JPG/PNG,最多5张,每张 ≤5MB</div>
|
||||
</a-form-item>
|
||||
|
||||
<!-- 登记证 -->
|
||||
<a-form-item :label="'登记证附件'" name="registrationCertificateFiles">
|
||||
<a-upload
|
||||
v-model:file-list="formData.registrationCertificateFiles"
|
||||
list-type="picture-card"
|
||||
:before-upload="beforeUploadImage"
|
||||
:custom-request="dummyRequest"
|
||||
accept="image/*"
|
||||
multiple
|
||||
:disabled="isView"
|
||||
>
|
||||
<div v-if="formData.registrationCertificateFiles.length < 5">
|
||||
<plus-outlined />
|
||||
<div class="ant-upload-text">上传</div>
|
||||
</div>
|
||||
</a-upload>
|
||||
<div class="upload-tip">仅支持 JPG/PNG,最多5张,每张 ≤5MB</div>
|
||||
</a-form-item>
|
||||
|
||||
<!-- 其他资质 -->
|
||||
<a-form-item :label="'其他资质附件'" name="otherQualificationFiles">
|
||||
<a-upload
|
||||
v-model:file-list="formData.otherQualificationFiles"
|
||||
:before-upload="beforeUploadFile"
|
||||
:custom-request="dummyRequest"
|
||||
accept=".pdf,.doc,.docx,.xls,.xlsx,.jpg,.jpeg,.png"
|
||||
multiple
|
||||
:disabled="isView"
|
||||
>
|
||||
<a-button>点击上传资质文件</a-button>
|
||||
</a-upload>
|
||||
<div class="upload-tip">支持 PDF/Word/Excel/图片,单个 ≤10MB</div>
|
||||
</a-form-item>
|
||||
</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-card class="mb-4" title="地址信息" style="margin-top: 20px">
|
||||
<a-form-item :label="'所在地区'" name="areaCodes" :required="true">
|
||||
<AreaCascader
|
||||
v-model:value="formData.areaValue"
|
||||
@change="onAreaChange"
|
||||
:disabled="isView"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item :label="'详细地址'" name="address" :required="true">
|
||||
<a-textarea
|
||||
v-model:value="formData.address"
|
||||
placeholder="请输入街道、门牌号等详细地址"
|
||||
:rows="2"
|
||||
show-count
|
||||
:maxlength="256"
|
||||
/>
|
||||
</a-form-item>
|
||||
</a-card>
|
||||
|
||||
<!-- 其他 -->
|
||||
<a-card class="mb-4" title="其他" style="margin-top: 20px">
|
||||
<a-row :gutter="16">
|
||||
<a-col :span="12">
|
||||
<a-form-item :label="'状态'" name="status" :required="true">
|
||||
<a-select v-model:value="formData.status" style="width: 120px">
|
||||
<a-select-option value="1">启用</a-select-option>
|
||||
<a-select-option value="2">禁用</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
</a-row>
|
||||
<a-row :gutter="16">
|
||||
<a-col :span="24">
|
||||
<a-form-item :label="'备注'" name="remark">
|
||||
<a-textarea
|
||||
v-model:value="formData.remark"
|
||||
placeholder="可填写特殊说明、内部备注等"
|
||||
:rows="3"
|
||||
show-count
|
||||
:maxlength="500"
|
||||
/>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
</a-row>
|
||||
</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'
|
||||
import { ref, reactive, nextTick, computed } from 'vue';
|
||||
import { message } from 'ant-design-vue';
|
||||
import { InfoCircleOutlined, PlusOutlined } from '@ant-design/icons-vue';
|
||||
import AreaCascader from '@/components/AreaCascader/index.vue';
|
||||
import { useDicsStore } from '@/store';
|
||||
import apis from '@/apis';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
|
||||
const emit = defineEmits(['ok'])
|
||||
const { modal, showModal, hideModal, showLoading, hideLoading } = useModal()
|
||||
const { formData, formRef, formRules, resetForm } = useForm()
|
||||
const { t } = useI18n();
|
||||
const visible = ref(false);
|
||||
const formRef = ref();
|
||||
const confirmLoading = ref(false);
|
||||
const dicsStore = useDicsStore();
|
||||
const mode = ref('create');
|
||||
const isView = computed(() => mode.value === 'view');
|
||||
const isEditing = computed(() => mode.value === 'edit');
|
||||
const emit = defineEmits(['success']);
|
||||
const editingId = ref(null);
|
||||
|
||||
// 初始化数据模型
|
||||
formData.value = {
|
||||
orgName: '',
|
||||
const formData = reactive({
|
||||
name: '',
|
||||
orgCode: '',
|
||||
orgIdentityCode: '',
|
||||
level: '',
|
||||
manager: '',
|
||||
phone: '',
|
||||
legalPerson: '',
|
||||
orgLv: '',
|
||||
concatName: '',
|
||||
concatPhone: '',
|
||||
legalName: '',
|
||||
legalPhone: '',
|
||||
businessLicenseName: '',
|
||||
registrationAuthority: '',
|
||||
registrationNumber: '',
|
||||
isWinningOrg: '',
|
||||
useWallet: false,
|
||||
availableWallets: [],
|
||||
address: [],
|
||||
detailAddress: '',
|
||||
location: '',
|
||||
qualificationFiles: [],
|
||||
qualificationImages: [],
|
||||
businessLicenseImage: [],
|
||||
registrationAuthorityName: '',
|
||||
registrationAuthorityNo: '',
|
||||
winOrg: '',
|
||||
areaValue: [],
|
||||
address: '',
|
||||
remark: '',
|
||||
mode: 'edit' // 默认编辑模式
|
||||
}
|
||||
status: '1',
|
||||
businessLicenseFiles: [],
|
||||
registrationCertificateFiles: [],
|
||||
otherQualificationFiles: [],
|
||||
});
|
||||
|
||||
// 表单验证规则:查看模式下无需验证
|
||||
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: '请输入正确的手机号码' }
|
||||
const formRules = {
|
||||
name: [{ required: true, message: '请输入组织名称' }],
|
||||
orgCode: [{ required: true, message: '请输入组织机构代码' }],
|
||||
orgLv: [{ required: true, message: '请选择组织等级' }],
|
||||
concatName: [{ required: true, message: '请输入负责人姓名' }],
|
||||
concatPhone: [{ required: true, message: '请输入联系电话' }],
|
||||
status: [{ required: true, message: '请选择状态' }],
|
||||
areaCodes: [
|
||||
{
|
||||
required: true,
|
||||
validator: () => {
|
||||
if (!Array.isArray(formData.areaValue) || formData.areaValue.length === 0) {
|
||||
return Promise.reject(new Error('请选择服务组织地址'));
|
||||
}
|
||||
return Promise.resolve();
|
||||
},
|
||||
},
|
||||
],
|
||||
address: [{ required: true, message: '请选择服务组织地址' }],
|
||||
detailAddress: [{ required: true, message: '请输入详细地址' }]
|
||||
}
|
||||
address: [{ 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 open = async ({ record = null, mode: _mode = 'create' }) => {
|
||||
visible.value = true;
|
||||
mode.value = _mode;
|
||||
editingId.value = null;
|
||||
|
||||
await nextTick();
|
||||
if (record && _mode !== 'create') {
|
||||
editingId.value = record.id;
|
||||
await getDetail(record.id);
|
||||
} else {
|
||||
resetForm();
|
||||
}
|
||||
])
|
||||
|
||||
// ✅ 计算属性:是否为查看模式
|
||||
const isViewMode = computed(() => formData.value.mode === 'view')
|
||||
const okText = ref('确定')
|
||||
if (formRef.value) formRef.value.clearValidate();
|
||||
};
|
||||
|
||||
/**
|
||||
* 打开地图选择器
|
||||
*/
|
||||
function openMapSelector() {
|
||||
formData.value.location = '江苏省南通市通州区刘桥镇人民政府附近 (经纬度: 32.1234, 120.5678)'
|
||||
}
|
||||
const getDetail = async (id) => {
|
||||
const res = await apis.serviceMenu.getServiceOrgDetail(id);
|
||||
if (res?.success) {
|
||||
const data = res.data;
|
||||
|
||||
/**
|
||||
* 文件上传前校验(文件)
|
||||
*/
|
||||
function beforeUploadFile(file) {
|
||||
const isPdfOrDoc = [
|
||||
const areaLabels = data.areaLabels
|
||||
? (Array.isArray(data.areaLabels) ? data.areaLabels : String(data.areaLabels).split('/').filter(Boolean))
|
||||
: [];
|
||||
|
||||
const bizFiles = (data.businessLicenseUrls || []).map((url, i) => ({
|
||||
uid: `biz-${i}`,
|
||||
name: `营业执照-${i + 1}.jpg`,
|
||||
status: 'done',
|
||||
url,
|
||||
}));
|
||||
const regFiles = (data.registrationCertificateUrls || []).map((url, i) => ({
|
||||
uid: `reg-${i}`,
|
||||
name: `登记证-${i + 1}.jpg`,
|
||||
status: 'done',
|
||||
url,
|
||||
}));
|
||||
const qualFiles = (data.qualificationFileUrls || []).map((item, i) => ({
|
||||
uid: `qual-${i}`,
|
||||
name: item.name || `附件-${i + 1}`,
|
||||
status: 'done',
|
||||
url: item.url,
|
||||
}));
|
||||
|
||||
Object.assign(formData, {
|
||||
name: data.name || '',
|
||||
orgCode: data.orgCode || '',
|
||||
orgLv: data.orgLv || '',
|
||||
concatName: data.concatName || '',
|
||||
concatPhone: data.concatPhone || '',
|
||||
legalName: data.legalName || '',
|
||||
legalPhone: data.legalPhone || '',
|
||||
businessLicenseName: data.businessLicenseName || '',
|
||||
registrationAuthorityName: data.registrationAuthorityName || '',
|
||||
registrationAuthorityNo: data.registrationAuthorityNo || '',
|
||||
winOrg: data.winOrg || '',
|
||||
areaValue: areaLabels,
|
||||
address: data.address || '',
|
||||
remark: data.remark || '',
|
||||
status: String(data.status) || '1',
|
||||
businessLicenseFiles: bizFiles,
|
||||
registrationCertificateFiles: regFiles,
|
||||
otherQualificationFiles: qualFiles,
|
||||
});
|
||||
} else {
|
||||
message.error(res?.message || '获取详情失败');
|
||||
}
|
||||
};
|
||||
|
||||
const handleOk = () => {
|
||||
if (mode.value === 'view') {
|
||||
handleCancel();
|
||||
return;
|
||||
}
|
||||
handleSubmit();
|
||||
};
|
||||
|
||||
const handleSubmit = async () => {
|
||||
try {
|
||||
const values = await formRef.value.validateFields();
|
||||
confirmLoading.value = true;
|
||||
|
||||
// 上传文件逻辑(略,与原逻辑一致)
|
||||
const bizUrls = [];
|
||||
for (const f of formData.businessLicenseFiles) {
|
||||
if (f.originFileObj) bizUrls.push(await uploadFile(f.originFileObj));
|
||||
else if (f.url) bizUrls.push(f.url);
|
||||
}
|
||||
|
||||
const regUrls = [];
|
||||
for (const f of formData.registrationCertificateFiles) {
|
||||
if (f.originFileObj) regUrls.push(await uploadFile(f.originFileObj));
|
||||
else if (f.url) regUrls.push(f.url);
|
||||
}
|
||||
|
||||
const qualFiles = [];
|
||||
for (const f of formData.otherQualificationFiles) {
|
||||
if (f.originFileObj) {
|
||||
const url = await uploadFile(f.originFileObj);
|
||||
qualFiles.push({ name: f.name, url });
|
||||
} else if (f.url) {
|
||||
qualFiles.push({ name: f.name, url: f.url });
|
||||
}
|
||||
}
|
||||
|
||||
const submitData = {
|
||||
...values,
|
||||
areaCodes: formData.areaValue,
|
||||
businessLicenseUrls: bizUrls,
|
||||
registrationCertificateUrls: regUrls,
|
||||
qualificationFileUrls: qualFiles,
|
||||
};
|
||||
|
||||
let res;
|
||||
if (isEditing.value) {
|
||||
res = await apis.serviceMenu.updateServiceOrg(editingId.value, submitData);
|
||||
} else {
|
||||
res = await apis.serviceMenu.createServiceOrg(submitData);
|
||||
}
|
||||
|
||||
confirmLoading.value = false;
|
||||
if (res?.success) {
|
||||
message.success(isEditing.value ? '更新成功' : '创建成功');
|
||||
handleCancel();
|
||||
emit('success');
|
||||
} else {
|
||||
message.error(res?.message || '操作失败');
|
||||
}
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
confirmLoading.value = false;
|
||||
message.error('提交失败,请重试');
|
||||
}
|
||||
};
|
||||
|
||||
const handleCancel = () => {
|
||||
visible.value = false;
|
||||
};
|
||||
|
||||
const onAfterClose = () => {
|
||||
resetForm();
|
||||
confirmLoading.value = false;
|
||||
if (formRef.value) formRef.value.clearValidate();
|
||||
};
|
||||
|
||||
// === 上传相关 ===
|
||||
const dummyRequest = ({ onSuccess }) => {
|
||||
setTimeout(() => onSuccess('ok'), 0);
|
||||
};
|
||||
|
||||
const beforeUploadImage = (file) => {
|
||||
const isImage = file.type.startsWith('image/');
|
||||
if (!isImage) {
|
||||
message.error('只能上传图片!');
|
||||
return false;
|
||||
}
|
||||
const isLt5M = file.size / 1024 / 1024 < 5;
|
||||
if (!isLt5M) {
|
||||
message.error('图片不能超过5MB!');
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
const beforeUploadFile = (file) => {
|
||||
const allowedTypes = [
|
||||
'application/pdf',
|
||||
'application/msword',
|
||||
'application/vnd.openxmlformats-officedocument.wordprocessingml.document'
|
||||
].includes(file.type)
|
||||
if (!isPdfOrDoc) {
|
||||
message.error('仅支持上传 PDF 或 Word 文档!')
|
||||
return Upload.LIST_IGNORE
|
||||
'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
|
||||
'application/vnd.ms-excel',
|
||||
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
|
||||
'image/jpeg',
|
||||
'image/png',
|
||||
'image/jpg',
|
||||
];
|
||||
if (!allowedTypes.includes(file.type)) {
|
||||
message.error('仅支持 PDF、Word、Excel、JPG、PNG 格式!');
|
||||
return false;
|
||||
}
|
||||
const isLt5M = file.size / 1024 / 1024 < 5
|
||||
if (!isLt5M) {
|
||||
message.error('文件大小不能超过 5MB!')
|
||||
return Upload.LIST_IGNORE
|
||||
if (file.size / 1024 / 1024 >= 10) {
|
||||
message.error('文件不能超过10MB!');
|
||||
return false;
|
||||
}
|
||||
return true
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
/**
|
||||
* 图片上传前校验
|
||||
*/
|
||||
function beforeUploadImage(file) {
|
||||
const isImg = file.type.startsWith('image/')
|
||||
if (!isImg) {
|
||||
message.error('只能上传图片文件!')
|
||||
return false
|
||||
const uploadFile = async (file) => {
|
||||
const formData = new FormData();
|
||||
formData.append('file', file);
|
||||
const res = await apis.file.upload(formData);
|
||||
if (res?.success && res.data?.url) {
|
||||
return res.data.url;
|
||||
} else {
|
||||
throw new Error(res?.message || '上传失败');
|
||||
}
|
||||
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
|
||||
}
|
||||
})
|
||||
const resetForm = () => {
|
||||
Object.assign(formData, {
|
||||
name: '',
|
||||
orgCode: '',
|
||||
orgLv: '',
|
||||
concatName: '',
|
||||
concatPhone: '',
|
||||
legalName: '',
|
||||
legalPhone: '',
|
||||
businessLicenseName: '',
|
||||
registrationAuthorityName: '',
|
||||
registrationAuthorityNo: '',
|
||||
winOrg: '',
|
||||
areaValue: [],
|
||||
address: '',
|
||||
remark: '',
|
||||
status: '1',
|
||||
businessLicenseFiles: [],
|
||||
registrationCertificateFiles: [],
|
||||
otherQualificationFiles: [],
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 提交处理(仅编辑模式触发)
|
||||
*/
|
||||
function handleOk() {
|
||||
if (isViewMode.value) return // 安全兜底
|
||||
const onAreaChange = (selectedCodes, selectedLabels) => {
|
||||
formData.areaValue = [...selectedCodes];
|
||||
formRef.value?.validateFields(['areaCodes']).catch(() => {});
|
||||
};
|
||||
|
||||
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()
|
||||
}
|
||||
defineExpose({ open, close: handleCancel });
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.upload-tip {
|
||||
color: #8c8c8c;
|
||||
font-size: 12px;
|
||||
margin-top: 4px;
|
||||
}
|
||||
|
||||
.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;
|
||||
.ant-upload-text {
|
||||
margin-top: 4px;
|
||||
}
|
||||
</style>
|
||||
@ -4,49 +4,40 @@
|
||||
<a-form :label-col="{ style: { width: '100px' } }" :model="searchFormData" layout="inline">
|
||||
<a-row :gutter="gutter">
|
||||
<a-col v-bind="colSpan">
|
||||
<a-form-item :label="'所在区域'" name="area">
|
||||
<a-form-item label="所在区域" name="area">
|
||||
<AreaCascader v-model:value="searchFormData.currentNode" @change="onAreaChange" />
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
|
||||
<a-col v-bind="colSpan">
|
||||
<a-form-item :label="'组织名称'" name="name">
|
||||
<a-input :placeholder="'请输组织名称'" v-model:value="searchFormData.name"></a-input>
|
||||
<a-form-item label="组织名称" name="name">
|
||||
<a-input v-model:value="searchFormData.name" placeholder="请输入组织名称" />
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
|
||||
<a-col v-bind="colSpan">
|
||||
<a-form-item :label="'负责人'" name="contactPerson">
|
||||
<a-input :placeholder="'请输负责人'" v-model:value="searchFormData.contactPerson"></a-input>
|
||||
<a-form-item label="负责人" name="contactPerson">
|
||||
<a-input v-model:value="searchFormData.contactPerson" placeholder="请输入负责人" />
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
|
||||
<a-col v-bind="colSpan">
|
||||
<a-form-item :label="'等级'" name="level">
|
||||
<a-select v-model:value="searchFormData.level" @change="handleChange">
|
||||
<a-form-item label="等级" name="level">
|
||||
<a-select v-model:value="searchFormData.level">
|
||||
<a-select-option v-for="item in dicsStore.dictOptions.level" :key="item.dval"
|
||||
:value="item.dval">
|
||||
{{ item.introduction }}
|
||||
{{ item.introduction }}
|
||||
</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
|
||||
<!-- <a-col v-bind="colSpan">
|
||||
<a-form-item :label="'可用钱包'" name="wallet">
|
||||
<a-select v-model:value="searchFormData.wallet" @change="handleChange">
|
||||
<a-select-option value="jack">已结单</a-select-option>
|
||||
<a-select-option value="lucy">已作废</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
</a-col> -->
|
||||
|
||||
<a-col v-bind="colSpan">
|
||||
<a-form-item :label="'是否中标'" name="bidStatus">
|
||||
<a-select v-model:value="searchFormData.bidStatus" @change="handleChange">
|
||||
<a-select-option v-for="item in dicsStore.dictOptions.WinTheBidding" :key="item.dval"
|
||||
<a-form-item label="是否中标" name="bidStatus">
|
||||
<a-select v-model:value="searchFormData.bidStatus">
|
||||
<a-select-option v-for="item in dicsStore.dictOptions.WinTheBidding" :key="item.dval"
|
||||
:value="item.dval">
|
||||
{{ item.introduction }}
|
||||
{{ item.introduction }}
|
||||
</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
@ -57,324 +48,289 @@
|
||||
<a-col>
|
||||
<a-space>
|
||||
<a-button @click="handleResetSearch">{{ $t('button.reset') }}</a-button>
|
||||
<a-button ghost type="primary" @click="handleSearch">
|
||||
{{ $t('button.search') }}
|
||||
</a-button>
|
||||
<a-button ghost type="primary" @click="handleSearch">{{ $t('button.search') }}</a-button>
|
||||
</a-space>
|
||||
</a-col>
|
||||
</a-row>
|
||||
|
||||
</a-form>
|
||||
</template>
|
||||
</x-search-bar>
|
||||
|
||||
<a-card>
|
||||
<!-- 添加标题和横线 -->
|
||||
<div class="title-container">
|
||||
<h3>服务组织列表</h3>
|
||||
<div class="title-line"></div>
|
||||
</div>
|
||||
<div style="margin: 20px 0;">
|
||||
<a-button type="primary" @click="handleCreate">
|
||||
<template #icon>
|
||||
<PlusCircleOutlined />
|
||||
</template>
|
||||
新建
|
||||
</a-button>
|
||||
</div>
|
||||
<a-table rowKey="id" :loading="loading" :columns="columns" :data-source="listData"
|
||||
:pagination="paginationConfig" :scroll="{ x: 2200 }">
|
||||
<template #bodyCell="{ column, record, index }">
|
||||
<!-- 序号 -->
|
||||
<template v-if="column.key === 'serialNumber'">
|
||||
{{ index + 1 }}
|
||||
</template>
|
||||
|
||||
<a-table rowKey="id" :loading="loading" :pagination="true" :columns="columns" :data-source="listData">
|
||||
<template #bodyCell="{ column, record }">
|
||||
<template v-if="'menuType' === column.key">
|
||||
<!--菜单-->
|
||||
<a-tag v-if="menuTypeEnum.is('page', record.type)" color="processing">
|
||||
{{ menuTypeEnum.getDesc(record.type) }}
|
||||
</a-tag>
|
||||
<!--按钮-->
|
||||
<a-tag v-if="menuTypeEnum.is('button', record.type)" color="success">
|
||||
{{ menuTypeEnum.getDesc(record.type) }}
|
||||
|
||||
<!-- 所在区域 -->
|
||||
<template v-else-if="column.key === 'areaLabels'">
|
||||
{{ record.areaLabels?.join('/') || '-' }}
|
||||
</template>
|
||||
|
||||
<!-- 状态 -->
|
||||
<template v-else-if="column.key === 'status'">
|
||||
<a-tag :color="record.status === '1' ? 'processing' : 'default'">
|
||||
{{ record.status === '1' ? '启用' : '停用' }}
|
||||
</a-tag>
|
||||
</template>
|
||||
|
||||
<template v-if="'createAt' === column.key">
|
||||
<!-- 等级(orgLv) -->
|
||||
<!-- 等级 -->
|
||||
<template v-else-if="column.key === 'orgLv'">
|
||||
{{ getLevelText(record.orgLv) }}
|
||||
</template>
|
||||
|
||||
<!-- 是否中标(winOrg) -->
|
||||
<template v-else-if="column.key === 'winOrg'">
|
||||
{{
|
||||
record.winOrg
|
||||
? (dicsStore.dictOptions.WinTheBidding.find(item => item.dval === record.winOrg)?.introduction ||
|
||||
record.winOrg)
|
||||
: '-'
|
||||
}}
|
||||
</template>
|
||||
|
||||
<!-- 创建时间 -->
|
||||
<template v-else-if="column.key === 'createdAt'">
|
||||
{{ formatUtcDateTime(record.created_at) }}
|
||||
</template>
|
||||
|
||||
<template v-if="'statusType' === column.key">
|
||||
<!--状态-->
|
||||
<a-tag v-if="statusTypeEnum.is('enabled', record.status)" color="processing">
|
||||
{{ statusTypeEnum.getDesc(record.status) }}
|
||||
</a-tag>
|
||||
<!--状态-->
|
||||
<a-tag v-if="statusTypeEnum.is('disabled', record.status)" color="processing">
|
||||
{{ statusTypeEnum.getDesc(record.status) }}
|
||||
</a-tag>
|
||||
</template>
|
||||
|
||||
<template v-if="'actions' === column.key">
|
||||
<!-- 操作 -->
|
||||
<template v-else-if="column.key === 'actions'">
|
||||
<span class="action-buttons">
|
||||
<a-button type="link" size="small" @click="handleEdit(record)">编辑</a-button>
|
||||
<a-divider type="vertical" />
|
||||
<a-button type="link" size="small" @click="handleDetail(record)">详情</a-button>
|
||||
<a-divider type="vertical" />
|
||||
<a-button type="link" size="small" @click="handleToggleStatus(record)">
|
||||
{{ record.status === 'active' ? '停用' : '启用' }}
|
||||
{{ record.status === 'enabled' ? '停用' : '启用' }}
|
||||
</a-button>
|
||||
<a-divider type="vertical" />
|
||||
<a-button type="link" size="small" @click="handleDeviceManagement(record)">设备管理</a-button>
|
||||
<!-- <a-button type="link" size="small" @click="handleDeviceManagement(record)">设备管理</a-button> -->
|
||||
</span>
|
||||
</template>
|
||||
|
||||
<!-- 其他字段默认显示 -->
|
||||
<template v-else>
|
||||
{{ record[column.dataIndex] || '-' }}
|
||||
</template>
|
||||
</template>
|
||||
</a-table>
|
||||
</a-card>
|
||||
|
||||
<edit-dialog @ok="onOk" ref="editDialogRef" />
|
||||
<!-- 设备管理弹框组件 -->
|
||||
<device-management-modal ref="deviceManagementModalRef" />
|
||||
<EditDialog ref="editDialogRef" @success="handleRefresh" />
|
||||
<DeviceManagementModal ref="deviceManagementModalRef" />
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, computed } from 'vue'
|
||||
import { Modal, message, Divider } from 'ant-design-vue'
|
||||
import { ref } from 'vue'
|
||||
import { UnorderedListOutlined, EditOutlined, PlusCircleOutlined, DeleteOutlined } from '@ant-design/icons-vue'
|
||||
import { PlusCircleOutlined } from '@ant-design/icons-vue'
|
||||
import apis from '@/apis'
|
||||
import { config } from '@/config'
|
||||
import { menuTypeEnum, statusTypeEnum } from '@/enums/system'
|
||||
import { usePagination, useForm } from '@/hooks'
|
||||
import { statusTypeEnum } from '@/enums/system'
|
||||
import { usePagination } from '@/hooks'
|
||||
import { formatUtcDateTime } from '@/utils/util'
|
||||
import EditDialog from './components/EditDialog.vue'
|
||||
// 导入设备管理组件
|
||||
import DeviceManagementModal from './components/AddEquipments.vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import storage from '@/utils/storage'
|
||||
import AreaCascader from '@/components/AreaCascader/index.vue'
|
||||
import { useDicsStore } from '@/store'
|
||||
import { useDicsStore } from '@/store'
|
||||
import dayjs from 'dayjs'
|
||||
|
||||
defineOptions({
|
||||
name: 'menu',
|
||||
})
|
||||
const { t } = useI18n() // 解构出t方法
|
||||
|
||||
// 控制导入弹框显示/隐藏的变量
|
||||
const showImportModal = ref(false)
|
||||
|
||||
// 定义设备管理弹框的ref引用 - 这是修复错误的关键
|
||||
const deviceManagementModalRef = ref(null)
|
||||
// 编辑对话框的ref引用
|
||||
const editDialogRef = ref(null)
|
||||
|
||||
const columns = ref([
|
||||
{ title: '序号', dataIndex: 'serialNumber', key: 'serialNumber', fixed: true, width: 180 },
|
||||
{ title: '机构编号', dataIndex: 'orgCode', key: 'orgCode', width: 240 },
|
||||
{ title: '节点编号', dataIndex: 'nodeCode', key: 'nodeCode', width: 240 },
|
||||
{ title: '机构名称', dataIndex: 'orgName', key: 'orgName', width: 240 },
|
||||
{ title: '联系人', dataIndex: 'contactPerson', key: 'contactPerson', width: 240 },
|
||||
{ title: '联系电话', dataIndex: 'contactPhone', key: 'contactPhone', width: 240 },
|
||||
{ title: '机构类型', dataIndex: 'orgType', key: 'orgType', width: 240 },
|
||||
{ title: '机构性质', dataIndex: 'orgNature', key: 'orgNature', width: 240 },
|
||||
{ title: '状态', dataIndex: 'status', key: 'status', width: 240 },
|
||||
{ title: '等级', dataIndex: 'level', key: 'level', width: 240 },
|
||||
{ title: '营业执照注册号', dataIndex: 'businessLicenseNo', key: 'businessLicenseNo', width: 240 },
|
||||
{ title: '所在区域', dataIndex: 'region', key: 'region', width: 240 },
|
||||
{ title: '详细地址', dataIndex: 'addressDetail', key: 'addressDetail', width: 240 },
|
||||
{ title: '操作', dataIndex: 'actions', key: 'actions', width: 320 },
|
||||
])
|
||||
|
||||
const { listData, loading, showLoading, hideLoading, searchFormData, paginationState, resetPagination } =
|
||||
usePagination()
|
||||
const { resetForm } = useForm()
|
||||
const { t } = useI18n()
|
||||
const dicsStore = useDicsStore()
|
||||
|
||||
getMenuList()
|
||||
// 分页与数据
|
||||
const {
|
||||
listData,
|
||||
loading,
|
||||
showLoading,
|
||||
hideLoading,
|
||||
searchFormData,
|
||||
paginationState,
|
||||
resetPagination
|
||||
} = usePagination()
|
||||
|
||||
/**
|
||||
* 获取菜单列表
|
||||
* @return {Promise<void>}
|
||||
*/
|
||||
async function getMenuList() {
|
||||
// refs
|
||||
const editDialogRef = ref(null)
|
||||
const deviceManagementModalRef = ref(null)
|
||||
|
||||
// 表格列定义
|
||||
const columns = ref([
|
||||
{ title: '序号', key: 'serialNumber', width: 80 },
|
||||
{ title: '机构编号', dataIndex: 'orgCode', key: 'orgCode', width: 150 },
|
||||
{ title: '机构名称', dataIndex: 'name', key: 'name', width: 180 }, // ← 改为 name
|
||||
{ title: '联系人', dataIndex: 'concatName', key: 'concatName', width: 120 }, // ← concatName
|
||||
{ title: '联系电话', dataIndex: 'concatPhone', key: 'concatPhone', width: 150 }, // ← concatPhone
|
||||
{ title: '状态', dataIndex: 'status', key: 'status', width: 100 },
|
||||
{ title: '等级', dataIndex: 'orgLv', key: 'orgLv', width: 100 }, // ← orgLv
|
||||
{ title: '所在区域', key: 'areaLabels', width: 200 },
|
||||
{ title: '详细地址', dataIndex: 'address', key: 'address', width: 200 },
|
||||
{ title: '是否中标', dataIndex: 'winOrg', key: 'winOrg', width: 100 },
|
||||
{ title: '创建时间', dataIndex: 'created_at', key: 'createdAt', width: 180 }, // ← created_at
|
||||
{ title: '操作', key: 'actions', width: 320, fixed: 'right' },
|
||||
])
|
||||
|
||||
// 分页配置
|
||||
const paginationConfig = computed(() => ({
|
||||
current: paginationState.current,
|
||||
pageSize: paginationState.pageSize,
|
||||
total: paginationState.total,
|
||||
showSizeChanger: true,
|
||||
showQuickJumper: true,
|
||||
onChange(page, pageSize) {
|
||||
paginationState.current = page
|
||||
paginationState.pageSize = pageSize
|
||||
getList()
|
||||
},
|
||||
onShowSizeChange(current, size) {
|
||||
paginationState.current = 1
|
||||
paginationState.pageSize = size
|
||||
getList()
|
||||
}
|
||||
}))
|
||||
|
||||
// 获取列表
|
||||
async function getList() {
|
||||
try {
|
||||
showLoading()
|
||||
const platform = storage.local.getItem('platform')
|
||||
const { data, success, total } = await apis.menu
|
||||
.getMenuList({
|
||||
...searchFormData.value,
|
||||
platform
|
||||
})
|
||||
.catch(() => {
|
||||
throw new Error()
|
||||
})
|
||||
const { pageSize, current } = paginationState
|
||||
const params = {
|
||||
...searchFormData.value,
|
||||
pageSize,
|
||||
current
|
||||
}
|
||||
const { success, data, total } = await apis.serviceMenu.getServiceOrgList(params)
|
||||
hideLoading()
|
||||
if (config('http.code.success') === success) {
|
||||
data.forEach((item) => {
|
||||
item.name = t(item.code) || item.name
|
||||
})
|
||||
listData.value = data
|
||||
paginationState.total = total
|
||||
listData.value = data || []
|
||||
paginationState.total = total || 0
|
||||
}
|
||||
} catch (error) {
|
||||
hideLoading()
|
||||
listData.value = []
|
||||
paginationState.total = 0
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 搜索
|
||||
*/
|
||||
// 搜索
|
||||
function handleSearch() {
|
||||
resetPagination()
|
||||
getMenuList()
|
||||
getList()
|
||||
}
|
||||
|
||||
/**
|
||||
* 重置
|
||||
*/
|
||||
// 重置
|
||||
function handleResetSearch() {
|
||||
searchFormData.value = {}
|
||||
resetPagination()
|
||||
getMenuList()
|
||||
getList()
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除
|
||||
* @param id
|
||||
*/
|
||||
function handleDelete({ id }) {
|
||||
Modal.confirm({
|
||||
title: t('pages.system.menu.delTip'),
|
||||
content: t('button.confirm'),
|
||||
okText: t('button.confirm'),
|
||||
onOk: () => {
|
||||
return new Promise((resolve, reject) => {
|
||||
; (async () => {
|
||||
try {
|
||||
const { success } = await apis.menu.delMenu(id).catch(() => {
|
||||
throw new Error()
|
||||
})
|
||||
if (config('http.code.success') === success) {
|
||||
resolve()
|
||||
message.success(t('component.message.success.delete'))
|
||||
await getMenuList()
|
||||
}
|
||||
} catch (error) {
|
||||
reject()
|
||||
}
|
||||
})()
|
||||
})
|
||||
},
|
||||
})
|
||||
// 区域变化
|
||||
function onAreaChange(codes, labels) {
|
||||
// 如果 AreaCascader 返回的是 [codes, labels],则:
|
||||
searchFormData.value.areaCodes = codes
|
||||
searchFormData.value.areaLabels = labels
|
||||
}
|
||||
|
||||
/**
|
||||
* 编辑完成
|
||||
*/
|
||||
async function onOk() {
|
||||
await getMenuList()
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理下载模板
|
||||
*/
|
||||
function handleDownloadTemplate() {
|
||||
// 调用API下载模板
|
||||
apis.downloadTemplate().then(() => {
|
||||
message.success('模板下载成功')
|
||||
}).catch(() => {
|
||||
message.error('模板下载失败')
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理文件上传
|
||||
* @param file 选中的文件
|
||||
*/
|
||||
async function handleFileUpload(file) {
|
||||
try {
|
||||
showLoading()
|
||||
// 创建FormData对象
|
||||
const formData = new FormData()
|
||||
formData.append('file', file)
|
||||
|
||||
// 调用上传API
|
||||
const { success } = await apis.uploadServiceSite(formData)
|
||||
|
||||
hideLoading()
|
||||
if (config('http.code.success') === success) {
|
||||
message.success('文件上传成功')
|
||||
showImportModal.value = false
|
||||
// 重新获取列表数据
|
||||
await getMenuList()
|
||||
} else {
|
||||
message.error('文件上传失败')
|
||||
}
|
||||
} catch (error) {
|
||||
hideLoading()
|
||||
message.error('文件上传失败,请重试')
|
||||
}
|
||||
}
|
||||
|
||||
// 处理选择框变化
|
||||
function handleChange() {
|
||||
// 可以添加选择框变化后的逻辑
|
||||
}
|
||||
|
||||
// 新增操作方法
|
||||
// 编辑
|
||||
function handleEdit(record) {
|
||||
console.log("==record===", record)
|
||||
editDialogRef.value.open({ record, mode: 'edit' })
|
||||
}
|
||||
|
||||
// 详情
|
||||
function handleDetail(record) {
|
||||
// 查看详情逻辑
|
||||
editDialogRef.value.open({ record, mode: 'view' })
|
||||
}
|
||||
|
||||
// 启用/停用
|
||||
function handleToggleStatus(record) {
|
||||
// 根据当前状态决定操作文本
|
||||
const isActivate = record.status !== 'active';
|
||||
const actionText = isActivate ? '启用' : '停用';
|
||||
const confirmText = isActivate ? '确定要启用该组织吗?' : '确定要停用该组织吗?';
|
||||
|
||||
const isEnable = record.status !== '2'; // 当前不是启用 → 要启用
|
||||
const actionText = isEnable ? '启用' : '停用';
|
||||
const confirmText = isEnable ? '确定要启用该组织吗?' : '确定要停用该组织吗?';
|
||||
|
||||
Modal.confirm({
|
||||
title: `${actionText}组织`,
|
||||
content: confirmText,
|
||||
okText: '确定',
|
||||
cancelText: '取消',
|
||||
okType: isActivate ? 'primary' : 'danger',
|
||||
okType: isEnable ? 'primary' : 'danger',
|
||||
onOk: async () => {
|
||||
try {
|
||||
// 模拟API调用
|
||||
console.log(`${actionText}操作执行`, record);
|
||||
|
||||
// 这里应该调用实际的API
|
||||
// const { success } = await apis.org.toggleStatus({ id: record.id, status: isActivate ? 'active' : 'inactive' });
|
||||
|
||||
// 模拟成功响应
|
||||
const success = true;
|
||||
|
||||
// ✅ 正确传参:id + { status: '1' 或 '2' }
|
||||
const { success } = await apis.serviceMenu.enableOrDisable(
|
||||
record.id,
|
||||
{ status: isEnable ? '1' : '2' }
|
||||
);
|
||||
|
||||
if (success) {
|
||||
message.success(`${actionText}成功`);
|
||||
// 更新本地数据状态
|
||||
record.status = isActivate ? 'active' : 'inactive';
|
||||
// 刷新列表
|
||||
await getMenuList();
|
||||
// 更新本地状态
|
||||
getList()
|
||||
} else {
|
||||
message.error(`${actionText}失败`);
|
||||
}
|
||||
} catch (error) {
|
||||
message.error(`${actionText}过程中发生错误: ${error.message}`);
|
||||
console.error('操作异常:', error);
|
||||
message.error('操作失败');
|
||||
}
|
||||
},
|
||||
onCancel() {
|
||||
console.log('取消操作');
|
||||
},
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 设备管理按钮点击事件
|
||||
// 设备管理
|
||||
function handleDeviceManagement(record) {
|
||||
// 检查设备管理弹框引用是否存在
|
||||
if (deviceManagementModalRef.value) {
|
||||
// 调用弹框的open方法,并传递当前组织记录
|
||||
deviceManagementModalRef.value.open({ orgRecord: record });
|
||||
deviceManagementModalRef.value.open({ orgRecord: record })
|
||||
} else {
|
||||
console.error('设备管理弹框组件未正确初始化');
|
||||
message.error('设备管理功能加载失败,请刷新页面重试');
|
||||
message.error('设备管理组件未加载')
|
||||
}
|
||||
}
|
||||
|
||||
// 新建
|
||||
function handleCreate() {
|
||||
editDialogRef.value.open({ record: null, mode: 'create' })
|
||||
}
|
||||
|
||||
// 刷新列表(由子组件 emit 触发)
|
||||
function handleRefresh() {
|
||||
getList()
|
||||
}
|
||||
|
||||
|
||||
// 等级映射函数
|
||||
const getLevelText = (level) => {
|
||||
if (!level) return '-'
|
||||
const num = Number(level)
|
||||
if (num >= 1 && num <= 5) {
|
||||
return `${num}级`
|
||||
}
|
||||
return level // 非预期值原样返回
|
||||
}
|
||||
|
||||
// 初始化
|
||||
getList()
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
// 标题和横线样式
|
||||
.title-container {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
@ -382,20 +338,19 @@ function handleDeviceManagement(record) {
|
||||
.title-line {
|
||||
height: 1px;
|
||||
width: 100%;
|
||||
background-color: #e8e8e8; // 灰色横线
|
||||
background-color: #e8e8e8;
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
// 操作按钮样式
|
||||
.action-buttons {
|
||||
.ant-btn-link {
|
||||
padding: 0 4px;
|
||||
height: auto;
|
||||
line-height: inherit;
|
||||
}
|
||||
|
||||
|
||||
.ant-divider {
|
||||
margin: 0 2px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</style>
|
||||
File diff suppressed because it is too large
Load Diff
@ -14,7 +14,7 @@
|
||||
<a-select v-model:value="searchFormData.type" placeholder="请选择站点类型" allow-clear>
|
||||
<a-select-option v-for="item in dicsStore.dictOptions.Station_Type" :key="item.dval"
|
||||
:value="item.dval">
|
||||
{{ item.introduction }}
|
||||
{{ item.introduction }}
|
||||
</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
@ -35,7 +35,7 @@
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
|
||||
<a-col v-bind="colSpan" style="text-align: right;">
|
||||
<a-col v-bind="colSpan" style="text-align: right;">
|
||||
<a-space>
|
||||
<a-button @click="handleResetSearch">{{ $t('button.reset') }}</a-button>
|
||||
<a-button ghost type="primary" @click="handleSearch">
|
||||
@ -44,7 +44,7 @@
|
||||
</a-space>
|
||||
</a-col>
|
||||
</a-row>
|
||||
|
||||
|
||||
</a-form>
|
||||
</template>
|
||||
</x-search-bar>
|
||||
@ -55,7 +55,7 @@
|
||||
<h3>服务站点列表</h3>
|
||||
<div class="title-line"></div>
|
||||
</div>
|
||||
|
||||
|
||||
<x-action-bar class="mb-8-2">
|
||||
<!-- 增加按钮之间的间距 -->
|
||||
<a-space :size="12">
|
||||
@ -87,9 +87,9 @@
|
||||
</a-button>
|
||||
</a-space>
|
||||
</x-action-bar>
|
||||
|
||||
<a-table rowKey="id" :loading="loading" :pagination="true" :columns="columns" :data-source="listData">
|
||||
<template #bodyCell="{ column, record }">
|
||||
|
||||
<a-table rowKey="id" :loading="loading" :pagination="true" :columns="columns" :data-source="listData" :scroll="{ x: 'max-content' }">
|
||||
<template #bodyCell="{ column, record }" >
|
||||
<template v-if="'menuType' === column.key">
|
||||
<!--菜单-->
|
||||
<a-tag v-if="menuTypeEnum.is('page', record.type)" color="processing">
|
||||
@ -105,71 +105,61 @@
|
||||
{{ formatUtcDateTime(record.created_at) }}
|
||||
</template>
|
||||
|
||||
<template v-if="'statusType' === column.key">
|
||||
<!--状态-->
|
||||
<a-tag v-if="statusTypeEnum.is('enabled', record.status)" color="processing">
|
||||
{{ statusTypeEnum.getDesc(record.status) }}
|
||||
</a-tag>
|
||||
<!--状态-->
|
||||
<a-tag v-if="statusTypeEnum.is('disabled', record.status)" color="processing">
|
||||
{{ statusTypeEnum.getDesc(record.status) }}
|
||||
<template v-else-if="column.key === 'status'">
|
||||
<a-tag :color="record.status === '1' ? 'processing' : 'default'" v-if="record.status != '' ">
|
||||
{{ record.status === '1' ? '启用' : '停用' }}
|
||||
</a-tag>
|
||||
<span v-else>
|
||||
--
|
||||
</span>
|
||||
</template>
|
||||
|
||||
<template v-if="'action' === column.key">
|
||||
<x-action-button @click="$refs.editDialogRef.handleEdit(record)">
|
||||
<a-tooltip>
|
||||
<template #title>{{ $t('pages.system.menu.edit') }}</template>
|
||||
<edit-outlined />
|
||||
<template #title>编辑</template>
|
||||
编辑
|
||||
</a-tooltip>
|
||||
</x-action-button>
|
||||
|
||||
<x-action-button @click="$refs.editDialogRef.handleCreateChild(record)">
|
||||
<x-action-button @click="$refs.editDialogRef.handleView(record)">
|
||||
<a-tooltip>
|
||||
<template #title>{{ $t('pages.system.menu.button.addChild') }}</template>
|
||||
<plus-circle-outlined />
|
||||
<template #title>查看详情</template>
|
||||
详情
|
||||
</a-tooltip>
|
||||
</x-action-button>
|
||||
<x-action-button @click="handleDelete(record)">
|
||||
<a-tooltip>
|
||||
<template #title>{{ $t('pages.system.delete') }}</template>
|
||||
<delete-outlined style="color: #ff4d4f" />
|
||||
删除
|
||||
</a-tooltip>
|
||||
</x-action-button>
|
||||
<x-action-button @click="handleStatusChange(record)">
|
||||
<a-tooltip>
|
||||
<template #title>{{ $t('pages.system.delete') }}</template>
|
||||
{{ record.status === '1' ? '停用' : '启用' }}
|
||||
</a-tooltip>
|
||||
</x-action-button>
|
||||
</template>
|
||||
</template>
|
||||
|
||||
</a-table>
|
||||
</a-card>
|
||||
|
||||
<edit-dialog @ok="onOk" ref="editDialogRef" />
|
||||
|
||||
|
||||
<!-- 导入弹框组件 -->
|
||||
<import-modal
|
||||
v-model:visible="showImportModal"
|
||||
@download="handleDownloadTemplate"
|
||||
@upload="handleFileUpload"/>
|
||||
|
||||
<import-modal v-model:visible="showImportModal" @download="handleDownloadTemplate" @upload="handleFileUpload" />
|
||||
|
||||
<!-- 导入记录弹框组件 -->
|
||||
<ImportRecordsModal
|
||||
v-model:visible="showImportRecordModal"
|
||||
title="导入记录"
|
||||
:fetchData="fetchImportRecords"
|
||||
@close="handleImportRecordClose"
|
||||
@view-details="handleViewImportDetails"
|
||||
@download-result="handleDownloadImportResult"
|
||||
@retry-import="handleRetryImport"
|
||||
/>
|
||||
<ImportRecordsModal v-model:visible="showImportRecordModal" title="导入记录" :fetchData="fetchImportRecords"
|
||||
@close="handleImportRecordClose" @view-details="handleViewImportDetails"
|
||||
@download-result="handleDownloadImportResult" @retry-import="handleRetryImport" />
|
||||
|
||||
<!-- 导出记录弹框组件 -->
|
||||
<ExportRecordsModal
|
||||
v-model="showExportRecordModal"
|
||||
title="导出记录"
|
||||
:fetchData="fetchExportRecords"
|
||||
@close="handleExportRecordClose"
|
||||
@view-details="handleViewExportDetails"
|
||||
@download-result="handleDownloadExportResult"
|
||||
@retry-export="handleRetryExport"
|
||||
/>
|
||||
<ExportRecordsModal v-model="showExportRecordModal" title="导出记录" :fetchData="fetchExportRecords"
|
||||
@close="handleExportRecordClose" @view-details="handleViewExportDetails"
|
||||
@download-result="handleDownloadExportResult" @retry-export="handleRetryExport" />
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
@ -205,20 +195,41 @@ const showImportRecordModal = ref(false)
|
||||
const showExportRecordModal = ref(false)
|
||||
|
||||
const columns = ref([
|
||||
{ title: '工单号', dataIndex: 'name', key: 'name', fixed: true, width: 280 },
|
||||
{ title: '服务对象', dataIndex: 'code', key: 'code', width: 240 },
|
||||
{ title: '身份证号', dataIndex: 'type', key: 'menuType', width: 240 },
|
||||
{ title: '联系方式1', dataIndex: 'status', key: 'statusType', width: 240 },
|
||||
{ title: '联系方式2', dataIndex: 'sequence', width: 240 },
|
||||
{ title: '计划服务时间', dataIndex: 'created_at', key: 'createAt', width: 240 },
|
||||
{ title: '计划服务时常(分钟)', dataIndex: 'created_at', key: 'createAt', width: 240 },
|
||||
{ title: '服务项目', dataIndex: 'created_at', key: 'createAt', width: 240 },
|
||||
{ title: '所属区域', dataIndex: 'created_at', key: 'createAt', width: 240 },
|
||||
{ title: '服务地址', dataIndex: 'created_at', key: 'createAt', width: 240 },
|
||||
{ title: '服务组织', dataIndex: 'created_at', key: 'createAt', width: 240 },
|
||||
{ title: '服务人员', dataIndex: 'created_at', key: 'createAt', width: 240 },
|
||||
{ title: '下单员', dataIndex: 'created_at', key: 'createAt', width: 240 },
|
||||
{ title: '下单时间', dataIndex: 'created_at', key: 'createAt', width: 240 },
|
||||
{
|
||||
title: '站点名称',
|
||||
key: 'name',
|
||||
width: 150,
|
||||
ellipsis: true,
|
||||
customRender: ({ record }) => {
|
||||
return record?.name || '--'
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '所在机构',
|
||||
key: 'orgName',
|
||||
width: 150,
|
||||
ellipsis: true,
|
||||
customRender: ({ record }) => {
|
||||
return record.organization?.name || '--'
|
||||
}
|
||||
},
|
||||
{ title: '组织编码', dataIndex: 'orgCode', key: 'orgCode', width: 150 },
|
||||
{ title: '站点类型', dataIndex: 'stationType', key: 'stationType', width: 120 },
|
||||
{ title: '地址', dataIndex: 'address', key: 'address', width: 200, ellipsis: true },
|
||||
{
|
||||
title: '营业时间', key: 'businessHours', width: 150, customRender: ({ record }) => {
|
||||
return `${record.openAt || '--'} - ${record.closeAt || '--'}`;
|
||||
}
|
||||
},
|
||||
{ title: '面积(㎡)', dataIndex: 'area', key: 'area', width: 100 },
|
||||
{ title: '人员数量', dataIndex: 'memberNum', key: 'memberNum', width: 100 },
|
||||
{
|
||||
title: '创建时间', key: 'created_at', width: 180, customRender: ({ record }) => {
|
||||
return formatUtcDateTime(record.created_at);
|
||||
}
|
||||
},
|
||||
{ title: '状态', dataIndex: 'status', key: 'status', width: 100 },
|
||||
{ title: '操作', key: 'action', width: 260, fixed: 'right' }
|
||||
])
|
||||
const { listData, loading, showLoading, hideLoading, searchFormData, paginationState, resetPagination } =
|
||||
usePagination()
|
||||
@ -227,29 +238,28 @@ const editDialogRef = ref()
|
||||
import { useDicsStore } from '@/store'
|
||||
const dicsStore = useDicsStore()
|
||||
|
||||
getMenuList()
|
||||
getList()
|
||||
|
||||
/**
|
||||
* 获取菜单列表
|
||||
* @return {Promise<void>}
|
||||
*/
|
||||
async function getMenuList() {
|
||||
async function getList() {
|
||||
try {
|
||||
showLoading()
|
||||
const platform = storage.local.getItem('platform')
|
||||
const { data, success, total } = await apis.menu
|
||||
.getMenuList({
|
||||
const { pageSize, current } = paginationState
|
||||
const { success, data, total } = await apis.serviceMenu
|
||||
.getServiceSiteList({
|
||||
pageSize,
|
||||
current: current,
|
||||
...searchFormData.value,
|
||||
platform
|
||||
})
|
||||
.catch(() => {
|
||||
throw new Error()
|
||||
})
|
||||
hideLoading()
|
||||
if (config('http.code.success') === success) {
|
||||
data.forEach((item) => {
|
||||
item.name = t(item.code) || item.name
|
||||
})
|
||||
//筛选type的值80对应about
|
||||
listData.value = data
|
||||
paginationState.total = total
|
||||
}
|
||||
@ -262,7 +272,7 @@ async function getMenuList() {
|
||||
*/
|
||||
function handleSearch() {
|
||||
resetPagination()
|
||||
getMenuList()
|
||||
getList()
|
||||
}
|
||||
/**
|
||||
* 重置
|
||||
@ -270,7 +280,7 @@ function handleSearch() {
|
||||
function handleResetSearch() {
|
||||
searchFormData.value = {}
|
||||
resetPagination()
|
||||
getMenuList()
|
||||
getList()
|
||||
}
|
||||
/**
|
||||
* 删除
|
||||
@ -278,20 +288,20 @@ function handleResetSearch() {
|
||||
*/
|
||||
function handleDelete({ id }) {
|
||||
Modal.confirm({
|
||||
title: t('pages.system.menu.delTip'),
|
||||
content: t('button.confirm'),
|
||||
title: '确认删除',
|
||||
content: '确认删除该服务站点?',
|
||||
okText: t('button.confirm'),
|
||||
onOk: () => {
|
||||
return new Promise((resolve, reject) => {
|
||||
; (async () => {
|
||||
try {
|
||||
const { success } = await apis.menu.delMenu(id).catch(() => {
|
||||
const { success } = await apis.serviceMenu.delServiceSite(id).catch(() => {
|
||||
throw new Error()
|
||||
})
|
||||
if (config('http.code.success') === success) {
|
||||
resolve()
|
||||
message.success(t('component.message.success.delete'))
|
||||
await getMenuList()
|
||||
await getList()
|
||||
}
|
||||
} catch (error) {
|
||||
reject()
|
||||
@ -302,11 +312,46 @@ function handleDelete({ id }) {
|
||||
})
|
||||
}
|
||||
|
||||
// 停用启用
|
||||
function handleStatusChange(record) {
|
||||
console.log(record.status);
|
||||
const isEnable = record.status == '1'; // 当前不是启用 → 要启用
|
||||
const actionText = isEnable ? '停用' : '启用';
|
||||
const confirmText = isEnable ? '确定要停用该站点吗?' : '确定要启用该站点吗?';
|
||||
|
||||
Modal.confirm({
|
||||
title: `${actionText}站点`,
|
||||
content: confirmText,
|
||||
okText: '确定',
|
||||
cancelText: '取消',
|
||||
okType: isEnable ? 'danger' : 'primary',
|
||||
onOk: async () => {
|
||||
try {
|
||||
const { success } = await apis.serviceMenu.enableOrDisableServiceSite(
|
||||
record.id,
|
||||
{ status: isEnable ? '2' : '1' }
|
||||
);
|
||||
|
||||
if (success) {
|
||||
message.success(`${actionText}成功`);
|
||||
// 更新本地状态
|
||||
getList()
|
||||
} else {
|
||||
message.error(`${actionText}失败`);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('操作异常:', error);
|
||||
message.error('操作失败');
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 编辑完成
|
||||
*/
|
||||
async function onOk() {
|
||||
await getMenuList()
|
||||
await getList()
|
||||
}
|
||||
|
||||
/**
|
||||
@ -357,10 +402,10 @@ async function handleFileUpload(file) {
|
||||
// 创建FormData对象
|
||||
const formData = new FormData()
|
||||
formData.append('file', file)
|
||||
|
||||
|
||||
// 调用上传API
|
||||
const { success } = await apis.uploadServiceSite(formData)
|
||||
|
||||
|
||||
hideLoading()
|
||||
if (config('http.code.success') === success) {
|
||||
message.success('文件上传成功')
|
||||
@ -385,7 +430,7 @@ function handleChange() {
|
||||
const fetchImportRecords = async (params) => {
|
||||
// 模拟API调用 - 实际项目中需要替换为真实的API调用
|
||||
await new Promise(resolve => setTimeout(resolve, 800));
|
||||
|
||||
|
||||
// 模拟数据
|
||||
const mockData = [
|
||||
{
|
||||
@ -444,12 +489,12 @@ const fetchImportRecords = async (params) => {
|
||||
progress: 100
|
||||
}
|
||||
];
|
||||
|
||||
|
||||
// 根据分页参数返回数据
|
||||
const start = (params.page - 1) * params.pageSize;
|
||||
const end = start + params.pageSize;
|
||||
const list = mockData.slice(start, end);
|
||||
|
||||
|
||||
return {
|
||||
list,
|
||||
total: mockData.length
|
||||
@ -460,7 +505,7 @@ const fetchImportRecords = async (params) => {
|
||||
const fetchExportRecords = async (params) => {
|
||||
// 模拟API调用 - 实际项目中需要替换为真实的API调用
|
||||
await new Promise(resolve => setTimeout(resolve, 800));
|
||||
|
||||
|
||||
// 模拟数据
|
||||
const mockData = [
|
||||
{
|
||||
@ -519,12 +564,12 @@ const fetchExportRecords = async (params) => {
|
||||
progress: 100
|
||||
}
|
||||
];
|
||||
|
||||
|
||||
// 根据分页参数返回数据
|
||||
const start = (params.page - 1) * params.pageSize;
|
||||
const end = start + params.pageSize;
|
||||
const list = mockData.slice(start, end);
|
||||
|
||||
|
||||
return {
|
||||
list,
|
||||
total: mockData.length
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user