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

356 lines
12 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<x-search-bar class="mb-8-2">
<template #default="{ gutter, colSpan }">
<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">
<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 v-model:value="searchFormData.name" placeholder="请输入组织名称" />
</a-form-item>
</a-col>
<a-col v-bind="colSpan">
<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">
<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-col v-bind="colSpan">
<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 }}
</a-select-option>
</a-select>
</a-form-item>
</a-col>
</a-row>
<a-row :gutter="gutter" justify="end" style="margin-top: 20px;">
<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-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>
<!-- 所在区域 -->
<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>
<!-- 等级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-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 === 'enabled' ? '停用' : '启用' }}
</a-button>
<a-divider type="vertical" />
<!-- <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>
<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 { PlusCircleOutlined } from '@ant-design/icons-vue'
import apis from '@/apis'
import { config } from '@/config'
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 AreaCascader from '@/components/AreaCascader/index.vue'
import { useDicsStore } from '@/store'
import dayjs from 'dayjs'
const { t } = useI18n()
const dicsStore = useDicsStore()
// 分页与数据
const {
listData,
loading,
showLoading,
hideLoading,
searchFormData,
paginationState,
resetPagination
} = usePagination()
// 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 { 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) {
listData.value = data || []
paginationState.total = total || 0
}
} catch (error) {
hideLoading()
listData.value = []
paginationState.total = 0
}
}
// 搜索
function handleSearch() {
resetPagination()
getList()
}
// 重置
function handleResetSearch() {
searchFormData.value = {}
resetPagination()
getList()
}
// 区域变化
function onAreaChange(codes, labels) {
// 如果 AreaCascader 返回的是 [codes, labels],则:
searchFormData.value.areaCodes = codes
searchFormData.value.areaLabels = labels
}
// 编辑
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 isEnable = record.status !== '2'; // 当前不是启用 → 要启用
const actionText = isEnable ? '启用' : '停用';
const confirmText = isEnable ? '确定要启用该组织吗?' : '确定要停用该组织吗?';
Modal.confirm({
title: `${actionText}组织`,
content: confirmText,
okText: '确定',
cancelText: '取消',
okType: isEnable ? 'primary' : 'danger',
onOk: async () => {
try {
// ✅ 正确传参id + { status: '1' 或 '2' }
const { success } = await apis.serviceMenu.enableOrDisable(
record.id,
{ status: isEnable ? '1' : '2' }
);
if (success) {
message.success(`${actionText}成功`);
// 更新本地状态
getList()
} else {
message.error(`${actionText}失败`);
}
} catch (error) {
console.error('操作异常:', error);
message.error('操作失败');
}
}
});
}
// 设备管理
function handleDeviceManagement(record) {
if (deviceManagementModalRef.value) {
deviceManagementModalRef.value.open({ orgRecord: record })
} else {
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;
}
.title-line {
height: 1px;
width: 100%;
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>