This commit is contained in:
aaron 2025-03-14 22:54:37 +08:00
parent a093ca4766
commit 3731b0efff
6 changed files with 502 additions and 213 deletions

View File

@ -25,14 +25,24 @@
<a-menu-item key="user-list"> <a-menu-item key="user-list">
<router-link to="/user/list">用户列表</router-link> <router-link to="/user/list">用户列表</router-link>
</a-menu-item> </a-menu-item>
<a-menu-item key="user-partner">
<router-link to="/user/partner">运营商管理</router-link>
</a-menu-item>
<a-menu-item key="deliveryman-list"> <a-menu-item key="deliveryman-list">
<router-link to="/deliveryman/list">配送员列表</router-link> <router-link to="/deliveryman/list">配送员列表</router-link>
</a-menu-item> </a-menu-item>
</a-sub-menu> </a-sub-menu>
<a-sub-menu key="partner">
<template #icon>
<team-outlined />
</template>
<template #title>运营商管理</template>
<a-menu-item key="partner-list">
<router-link to="/partner/list">运营商列表</router-link>
</a-menu-item>
<a-menu-item key="partner-area">
<router-link to="/partner/area">片区管理</router-link>
</a-menu-item>
</a-sub-menu>
<a-sub-menu key="order"> <a-sub-menu key="order">
<template #icon> <template #icon>
<shopping-outlined /> <shopping-outlined />
@ -73,8 +83,8 @@
<a-menu-item key="community-time-periods"> <a-menu-item key="community-time-periods">
<router-link to="/community/time-periods">配送时段</router-link> <router-link to="/community/time-periods">配送时段</router-link>
</a-menu-item> </a-menu-item>
<a-menu-item key="community-sets"> <a-menu-item key="time-period-templates">
<router-link to="/community/sets">小区集合</router-link> <router-link to="/community/time-period-templates">时段原型管理</router-link>
</a-menu-item> </a-menu-item>
</a-sub-menu> </a-sub-menu>
@ -118,9 +128,6 @@
<a-menu-item key="system-config"> <a-menu-item key="system-config">
<router-link to="/system/config">系统配置</router-link> <router-link to="/system/config">系统配置</router-link>
</a-menu-item> </a-menu-item>
<a-menu-item key="system-time-periods">
<router-link to="/system/time-periods">时段配置</router-link>
</a-menu-item>
<a-menu-item key="system-tasks"> <a-menu-item key="system-tasks">
<router-link to="/system/tasks">任务管理</router-link> <router-link to="/system/tasks">任务管理</router-link>
</a-menu-item> </a-menu-item>
@ -191,7 +198,8 @@ import {
SettingOutlined, SettingOutlined,
ShoppingOutlined, ShoppingOutlined,
MoneyCollectOutlined, MoneyCollectOutlined,
GiftOutlined GiftOutlined,
TeamOutlined
} from '@ant-design/icons-vue' } from '@ant-design/icons-vue'
import { useRouter, useRoute } from 'vue-router' import { useRouter, useRoute } from 'vue-router'
@ -209,7 +217,8 @@ export default defineComponent({
SettingOutlined, SettingOutlined,
ShoppingOutlined, ShoppingOutlined,
MoneyCollectOutlined, MoneyCollectOutlined,
GiftOutlined GiftOutlined,
TeamOutlined
}, },
setup() { setup() {
const router = useRouter() const router = useRouter()
@ -250,11 +259,6 @@ export default defineComponent({
title: '用户列表', title: '用户列表',
path: '/user/list' path: '/user/list'
}, },
{
key: 'user-partner',
title: '运营商管理',
path: '/user/partner'
},
{ {
key: 'deliveryman-list', key: 'deliveryman-list',
title: '配送员列表', title: '配送员列表',
@ -262,6 +266,24 @@ export default defineComponent({
} }
] ]
}, },
{
key: 'partner',
icon: () => h(TeamOutlined),
title: '运营商管理',
path: '/partner',
children: [
{
key: 'partner-list',
title: '运营商列表',
path: '/partner/list'
},
{
key: 'partner-area',
title: '片区管理',
path: '/partner/area'
}
]
},
{ {
key: 'order', key: 'order',
icon: () => h(ShoppingOutlined), icon: () => h(ShoppingOutlined),
@ -320,9 +342,9 @@ export default defineComponent({
path: '/community/time-periods' path: '/community/time-periods'
}, },
{ {
key: 'community-sets', key: 'time-period-templates',
title: '小区集合', title: '时段原型管理',
path: '/community/sets' path: '/community/time-period-templates'
} }
] ]
}, },
@ -383,11 +405,6 @@ export default defineComponent({
title: '系统配置', title: '系统配置',
path: '/system/config' path: '/system/config'
}, },
{
key: 'system-time-periods',
title: '时段配置',
path: '/system/time-periods'
},
{ {
key: 'system-tasks', key: 'system-tasks',
title: '任务管理', title: '任务管理',

View File

@ -26,7 +26,7 @@ const routes = [
path: '/user/partner', path: '/user/partner',
name: 'PartnerList', name: 'PartnerList',
component: () => import('../views/user/PartnerList.vue'), component: () => import('../views/user/PartnerList.vue'),
meta: { title: '运营商管理' } meta: { title: '运营商列表' }
}, },
{ {
path: '/deliveryman/list', path: '/deliveryman/list',
@ -70,6 +70,12 @@ const routes = [
component: () => import('../views/community/TimePeriodList.vue'), component: () => import('../views/community/TimePeriodList.vue'),
meta: { title: '小区配送时段' } meta: { title: '小区配送时段' }
}, },
{
path: 'community/time-period-templates',
name: 'TimePeriodTemplates',
component: () => import('@/views/system/TimePeriodList.vue'),
meta: { title: '时段原型管理' }
},
{ {
path: 'community/sets', path: 'community/sets',
name: 'CommunitySets', name: 'CommunitySets',
@ -124,11 +130,6 @@ const routes = [
component: () => import('@/views/system/ConfigList.vue'), component: () => import('@/views/system/ConfigList.vue'),
meta: { title: '系统配置' } meta: { title: '系统配置' }
}, },
{
path: 'time-periods',
component: () => import('@/views/system/TimePeriodList.vue'),
meta: { title: '时段配置' }
},
{ {
path: 'tasks', path: 'tasks',
component: () => import('@/views/system/TaskManager.vue'), component: () => import('@/views/system/TaskManager.vue'),
@ -162,6 +163,30 @@ const routes = [
meta: { title: '提现管理' } meta: { title: '提现管理' }
} }
] ]
},
{
path: '/partner',
component: BasicLayout,
children: [
{
path: 'list',
name: 'PartnerList',
component: () => import('../views/user/PartnerList.vue'),
meta: { title: '运营商列表' }
},
{
path: 'area',
name: 'PartnerArea',
component: () => import('../views/community/CommunitySetList.vue'),
meta: { title: '片区管理' }
},
{
path: 'area/:id',
name: 'PartnerAreaDetail',
component: () => import('../views/community/CommunitySetDetail.vue'),
meta: { title: '片区详情' }
}
]
} }
] ]

View File

@ -52,7 +52,7 @@
<!-- 添加小区模态框 --> <!-- 添加小区模态框 -->
<a-modal <a-modal
v-model:visible="addCommunityVisible" v-model:visible="addCommunityVisible"
title="添加小区" title="添加小区到片区"
:footer="null" :footer="null"
> >
<div class="search-community"> <div class="search-community">

View File

@ -2,9 +2,9 @@
<page-container> <page-container>
<div class="community-set-list"> <div class="community-set-list">
<div class="table-header"> <div class="table-header">
<h1>小区集合</h1> <h1>片区管理</h1>
<a-button type="primary" @click="showCreateModal"> <a-button type="primary" @click="showCreateModal">
创建小区集合 创建片区
</a-button> </a-button>
</div> </div>
@ -34,18 +34,18 @@
<!-- 创建/修改小区集合模态框 --> <!-- 创建/修改小区集合模态框 -->
<a-modal <a-modal
v-model:visible="modalVisible" v-model:visible="modalVisible"
:title="isEdit ? '修改小区集合' : '创建小区集合'" :title="isEdit ? '修改片区' : '创建片区'"
@ok="handleSubmit" @ok="handleSubmit"
@cancel="handleCancel" @cancel="handleCancel"
:confirmLoading="submitting" :confirmLoading="submitting"
> >
<a-form :model="formData" layout="vertical"> <a-form :model="formData" layout="vertical">
<a-form-item <a-form-item
label="集合名称" label="片区名称"
name="set_name" name="set_name"
:rules="[{ required: true, message: '请输入集合名称' }]" :rules="[{ required: true, message: '请输入片区名称' }]"
> >
<a-input v-model:value="formData.set_name" placeholder="请输入集合名称" /> <a-input v-model:value="formData.set_name" placeholder="请输入片区名称" />
</a-form-item> </a-form-item>
<a-form-item <a-form-item
@ -194,7 +194,7 @@ export default defineComponent({
width: 80, width: 80,
}, },
{ {
title: '集合名称', title: '片区名称',
dataIndex: 'set_name', dataIndex: 'set_name',
key: 'set_name', key: 'set_name',
width: 200, width: 200,
@ -292,7 +292,7 @@ export default defineComponent({
// //
const handleSubmit = async () => { const handleSubmit = async () => {
if (!formData.set_name) { if (!formData.set_name) {
message.warning('请输入集合名称') message.warning('请输入片区名称')
return return
} }
@ -301,13 +301,13 @@ export default defineComponent({
let res let res
if (isEdit.value) { if (isEdit.value) {
// //
res = await request.put(`/api/community-sets/${editingSetId.value}`, { res = await request.put(`/api/community-sets/${editingSetId.value}`, {
set_name: formData.set_name, set_name: formData.set_name,
user_id: formData.user_id || null user_id: formData.user_id || null
}) })
} else { } else {
// //
res = await request.post('/api/community-sets/', { res = await request.post('/api/community-sets/', {
set_name: formData.set_name, set_name: formData.set_name,
user_id: formData.user_id || null user_id: formData.user_id || null
@ -322,7 +322,7 @@ export default defineComponent({
message.error(res.message || (isEdit.value ? '修改失败' : '创建失败')) message.error(res.message || (isEdit.value ? '修改失败' : '创建失败'))
} }
} catch (error) { } catch (error) {
console.error(isEdit.value ? '修改小区集合失败:' : '创建小区集合失败:', error) console.error(isEdit.value ? '修改片区失败:' : '创建片区失败:', error)
message.error(isEdit.value ? '修改失败' : '创建失败') message.error(isEdit.value ? '修改失败' : '创建失败')
} finally { } finally {
submitting.value = false submitting.value = false

View File

@ -8,39 +8,78 @@
</a-button> </a-button>
</div> </div>
<a-table <!-- 过滤区域 -->
:columns="columns" <div class="table-filter">
:data-source="tableData" <a-form layout="inline">
:pagination="pagination" <a-form-item label="小区名称">
:loading="loading" <a-input
@change="handleTableChange" v-model:value="searchKeyword"
row-key="community_id" placeholder="请输入小区名称搜索"
> style="width: 200px"
<template #bodyCell="{ column, record }"> allowClear
<template v-if="column.key === 'time_periods'"> @change="handleSearch"
<a-space wrap> @pressEnter="handleSearch"
<a-tag v-for="(period, index) in record.time_periods || []" :key="index" color="blue"> />
{{ period.time_period_name }} </a-form-item>
<span>(运力:{{ period.capacity > 0 ? period.capacity : '不限制' }})</span> <a-form-item>
</a-tag> <a-button type="primary" @click="handleSearch">
</a-space> 搜索
</a-button>
</a-form-item>
</a-form>
</div>
<!-- 表格区域 -->
<a-card :bordered="false" class="table-card">
<a-table
:columns="columns"
:data-source="tableData"
:pagination="pagination"
:loading="loading"
@change="handleTableChange"
row-key="community_id"
:rowClassName="() => 'custom-table-row'"
>
<template #bodyCell="{ column, record }">
<template v-if="column.key === 'time_periods'">
<div class="time-periods-container">
<a-tag
v-for="(period, index) in record.time_periods || []"
:key="index"
:color="getTagColor(period.capacity)"
class="time-period-tag"
>
<span class="period-name">{{ period.time_period_name }}</span>
<span class="period-time">{{ formatTime(period.time_period_from_time) }} ~ {{ formatTime(period.time_period_to_time) }}</span>
<span class="period-capacity">运力: {{ period.capacity > 0 ? period.capacity : '不限制' }}</span>
</a-tag>
<a-empty
v-if="!record.time_periods || record.time_periods.length === 0"
description="未配置配送时段"
:image="Empty.PRESENTED_IMAGE_SIMPLE"
class="empty-time-periods"
/>
</div>
</template>
<template v-if="column.key === 'action'">
<a-button type="link" @click="handleEdit(record)" class="edit-button">
<template #icon><edit-outlined /></template>
编辑
</a-button>
</template>
</template> </template>
<template v-if="column.key === 'action'"> </a-table>
<a-space> </a-card>
<a @click="handleEdit(record)">编辑</a>
</a-space>
</template>
</template>
</a-table>
<!-- 配置时段模态框 --> <!-- 配置时段模态框 -->
<a-modal <a-modal
v-model:visible="modalVisible" v-model:visible="modalVisible"
title="配置小区配送时段" :title="currentCommunityId ? `编辑 ${getCurrentCommunityName()} 配送时段` : '配置小区配送时段'"
@ok="handleSubmit" @ok="handleSubmit"
@cancel="handleCancel" @cancel="handleCancel"
:confirmLoading="submitting" :confirmLoading="submitting"
width="720px" width="720px"
class="time-period-modal"
> >
<a-form <a-form
ref="formRef" ref="formRef"
@ -58,6 +97,7 @@
:options="communityOptions" :options="communityOptions"
:disabled="!!currentCommunityId" :disabled="!!currentCommunityId"
@change="handleCommunityChange" @change="handleCommunityChange"
style="width: 100%"
/> />
</a-form-item> </a-form-item>
@ -72,6 +112,7 @@
:pagination="false" :pagination="false"
size="small" size="small"
:scroll="{ y: 300 }" :scroll="{ y: 300 }"
:rowClassName="(record) => isTimePeriodSelected(record.id) ? 'selected-time-period-row' : ''"
> >
<template #bodyCell="{ column, record }"> <template #bodyCell="{ column, record }">
<template v-if="column.key === 'time_range'"> <template v-if="column.key === 'time_range'">
@ -103,9 +144,10 @@
<script> <script>
import { defineComponent, ref, onMounted, computed, h } from 'vue' import { defineComponent, ref, onMounted, computed, h } from 'vue'
import { message, Table, Space, Tag, Button, Modal, Form, Select, Checkbox, InputNumber } from 'ant-design-vue' import { message, Table, Space, Tag, Button, Modal, Form, Select, Checkbox, InputNumber, Empty, Card } from 'ant-design-vue'
import PageContainer from '@/components/PageContainer.vue' import PageContainer from '@/components/PageContainer.vue'
import request from '@/utils/request' import request from '@/utils/request'
import { EditOutlined } from '@ant-design/icons-vue'
export default defineComponent({ export default defineComponent({
components: { components: {
@ -119,12 +161,15 @@ export default defineComponent({
AFormItem: Form.Item, AFormItem: Form.Item,
ASelect: Select, ASelect: Select,
ACheckbox: Checkbox, ACheckbox: Checkbox,
AInputNumber: InputNumber AInputNumber: InputNumber,
ACard: Card,
EditOutlined
}, },
setup() { setup() {
const loading = ref(false) const loading = ref(false)
const tableData = ref([]) const tableData = ref([])
const searchKeyword = ref('')
const pagination = ref({ const pagination = ref({
current: 1, current: 1,
@ -156,8 +201,9 @@ export default defineComponent({
{ {
title: '操作', title: '操作',
key: 'action', key: 'action',
width: 80, width: 100,
fixed: 'right' fixed: 'right',
align: 'center'
} }
] ]
@ -169,6 +215,11 @@ export default defineComponent({
skip: (pagination.value.current - 1) * pagination.value.pageSize, skip: (pagination.value.current - 1) * pagination.value.pageSize,
limit: pagination.value.pageSize limit: pagination.value.pageSize
} }
if (searchKeyword.value) {
params.keyword = searchKeyword.value
}
const res = await request.get('/api/community-time-periods/group_by_community', { params }) const res = await request.get('/api/community-time-periods/group_by_community', { params })
if (res.code === 200) { if (res.code === 200) {
tableData.value = res.data.items || res.data tableData.value = res.data.items || res.data
@ -184,6 +235,12 @@ export default defineComponent({
} }
} }
//
const handleSearch = () => {
pagination.value.current = 1
fetchData()
}
// //
const handleTableChange = (pag) => { const handleTableChange = (pag) => {
pagination.value.current = pag.current pagination.value.current = pag.current
@ -203,6 +260,20 @@ export default defineComponent({
time_periods: [] time_periods: []
}) })
//
const getCurrentCommunityName = () => {
if (!currentCommunityId.value) return ''
const community = communities.value.find(c => c.id === currentCommunityId.value)
return community ? community.name : ''
}
//
const getTagColor = (capacity) => {
if (capacity === 0) return 'green'
if (capacity < 10) return 'orange'
return 'blue'
}
// //
const timePeriodColumns = [ const timePeriodColumns = [
{ {
@ -422,8 +493,10 @@ export default defineComponent({
tableData, tableData,
columns, columns,
pagination, pagination,
searchKeyword,
formatTime, formatTime,
handleTableChange, handleTableChange,
handleSearch,
modalVisible, modalVisible,
submitting, submitting,
formState, formState,
@ -440,7 +513,10 @@ export default defineComponent({
updateTimePeriodCapacity, updateTimePeriodCapacity,
handleTimePeriodSelect, handleTimePeriodSelect,
handleCommunityChange, handleCommunityChange,
currentCommunityId currentCommunityId,
getCurrentCommunityName,
getTagColor,
Empty
} }
} }
}) })
@ -458,11 +534,103 @@ export default defineComponent({
margin: 0; margin: 0;
} }
.table-filter {
margin-bottom: 16px;
padding: 16px 24px;
background: #fff;
border-radius: 4px;
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.03);
}
.table-card {
margin-bottom: 24px;
border-radius: 4px;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05);
}
/* 时段标签样式 */
.time-periods-container {
display: flex;
flex-wrap: wrap;
gap: 8px;
padding: 4px 0;
}
.time-period-tag {
display: flex;
flex-direction: column;
padding: 6px 8px;
border-radius: 4px;
margin: 0;
}
.period-name {
font-weight: 500;
margin-bottom: 2px;
}
.period-time {
font-size: 12px;
margin-bottom: 2px;
}
.period-capacity {
font-size: 12px;
background-color: rgba(255, 255, 255, 0.2);
padding: 1px 4px;
border-radius: 2px;
margin-top: 2px;
}
.empty-time-periods {
padding: 8px 0;
width: 100%;
}
/* 表格样式 */
:deep(.custom-table-row) {
transition: all 0.3s;
}
:deep(.custom-table-row:hover) {
background-color: #f5f7fa;
}
:deep(.ant-table-thead > tr > th) {
background-color: #f5f7fa;
font-weight: 500;
}
.edit-button {
padding: 0 8px;
}
/* 模态框样式 */
.time-period-modal {
:deep(.ant-modal-header) {
border-bottom: 1px solid #f0f0f0;
padding: 16px 24px;
}
:deep(.ant-modal-body) {
padding: 24px;
}
:deep(.ant-modal-footer) {
border-top: 1px solid #f0f0f0;
padding: 12px 24px;
}
}
:deep(.selected-time-period-row) {
background-color: #e6f7ff;
}
:deep(.selected-time-period-row:hover) {
background-color: #cceeff !important;
}
:deep(.ant-table-content) { :deep(.ant-table-content) {
overflow-x: auto; overflow-x: auto;
} }
:deep(.ant-tag) {
margin-bottom: 5px;
}
</style> </style>

View File

@ -30,30 +30,48 @@
</a-form> </a-form>
</div> </div>
<a-table <!-- 按小区分组显示驿站 -->
:columns="columns" <div v-if="!loading" class="community-station-list">
:data-source="tableData" <div v-if="groupedData.length === 0" class="empty-data">
:pagination="pagination" <a-empty description="暂无驿站数据" />
:loading="loading" </div>
@change="handleTableChange"
row-key="id" <div v-else class="community-groups">
> <div v-for="community in groupedData" :key="community.community_id" class="community-card">
<template #bodyCell="{ column, record }"> <div class="community-header">
<template v-if="column.key === 'action'"> <h3 class="community-name">{{ community.community_name }}</h3>
<a-space> <div class="header-right">
<a-button type="link" @click="handleEdit(record)">修改</a-button> <span class="station-count"> {{ community.stations.length }} 个驿站</span>
<a-popconfirm <a-button type="link" @click="showAddModalForCommunity(community.community_id)">
title="确定要删除该驿站吗?" 添加驿站
ok-text="确定" </a-button>
cancel-text="取消" </div>
@confirm="handleDelete(record)" </div>
<div class="station-grid">
<div
v-for="station in community.stations"
:key="station.station_id"
class="station-item"
@click="handleEdit(station)"
> >
<a-button type="link" danger>删除</a-button> <div class="station-content">
</a-popconfirm> <div class="station-name">{{ station.station_name }}</div>
</a-space> <div class="station-id">ID: {{ station.station_id }}</div>
</template> </div>
</template> <div class="station-edit-icon">
</a-table> <edit-outlined />
</div>
</div>
</div>
</div>
</div>
</div>
<!-- 加载中状态 -->
<div v-else class="loading-container">
<a-spin tip="加载中..."></a-spin>
</div>
<!-- 添加驿站模态框 --> <!-- 添加驿站模态框 -->
<a-modal <a-modal
@ -95,7 +113,7 @@
</a-form> </a-form>
</a-modal> </a-modal>
<!-- 添加修改驿站模态框 --> <!-- 修改驿站模态框 -->
<a-modal <a-modal
v-model:visible="editModalVisible" v-model:visible="editModalVisible"
title="修改驿站" title="修改驿站"
@ -104,23 +122,12 @@
@cancel="handleEditCancel" @cancel="handleEditCancel"
> >
<template #footer> <template #footer>
<div class="modal-footer-with-delete"> <a-space>
<a-popconfirm <a-button @click="handleEditCancel">取消</a-button>
title="确定要删除该驿站吗?" <a-button type="primary" :loading="editLoading" @click="handleEditSubmit">
ok-text="确定" 保存
cancel-text="取消" </a-button>
@confirm="handleDelete({ id: currentEditId })" </a-space>
:disabled="deleteLoading"
>
<a-button danger :loading="deleteLoading">删除驿站</a-button>
</a-popconfirm>
<a-space>
<a-button @click="handleEditCancel">取消</a-button>
<a-button type="primary" :loading="editLoading" @click="handleEditSubmit">
保存
</a-button>
</a-space>
</div>
</template> </template>
<a-form <a-form
@ -152,73 +159,39 @@
<script> <script>
import { defineComponent, ref, onMounted } from 'vue' import { defineComponent, ref, onMounted } from 'vue'
import { message } from 'ant-design-vue' import { message } from 'ant-design-vue'
import { getStationList, createStation, updateStation } from '@/api/station' import { createStation, updateStation } from '@/api/station'
import { getCommunityList } from '@/api/community' import { getCommunityList } from '@/api/community'
import PageContainer from '@/components/PageContainer.vue' import PageContainer from '@/components/PageContainer.vue'
import request from '@/utils/request' import request from '@/utils/request'
import { EditOutlined } from '@ant-design/icons-vue'
export default defineComponent({ export default defineComponent({
components: { components: {
PageContainer PageContainer,
EditOutlined
}, },
setup() { setup() {
const loading = ref(false) const loading = ref(false)
const tableData = ref([]) const groupedData = ref([])
const communityOptions = ref([]) const communityOptions = ref([])
const filterForm = ref({ const filterForm = ref({
community_id: undefined community_id: undefined
}) })
const pagination = ref({
current: 1,
pageSize: 10,
total: 0,
showSizeChanger: true,
showTotal: (total) => `${total} 条记录`
})
const columns = [ // 驿
{
title: 'ID',
dataIndex: 'id',
key: 'id',
width: 80,
align: 'center'
},
{
title: '驿站名称',
dataIndex: 'name',
key: 'name',
width: 150
},
{
title: '所属小区',
dataIndex: 'community_name',
key: 'community_name',
width: 150
},
{
title: '操作',
key: 'action',
width: 120,
align: 'center'
}
]
// 驿
const fetchData = async () => { const fetchData = async () => {
try { try {
loading.value = true loading.value = true
const params = { const params = {}
skip: (pagination.value.current - 1) * pagination.value.pageSize,
limit: pagination.value.pageSize, //
community_id: filterForm.value.community_id if (filterForm.value.community_id) {
params.community_id = filterForm.value.community_id
} }
const res = await getStationList(params) const res = await request.get('/api/station/group_by_community', { params })
if (res.code === 200) { if (res.code === 200) {
tableData.value = res.data.items groupedData.value = res.data || []
pagination.value.total = res.data.total
} else { } else {
message.error(res.message || '获取数据失败') message.error(res.message || '获取数据失败')
} }
@ -242,16 +215,8 @@ export default defineComponent({
} }
} }
//
const handleTableChange = (pag) => {
pagination.value.current = pag.current
pagination.value.pageSize = pag.pageSize
fetchData()
}
// //
const handleFilter = () => { const handleFilter = () => {
pagination.value.current = 1
fetchData() fetchData()
} }
@ -272,6 +237,19 @@ export default defineComponent({
// //
const showAddModal = () => { const showAddModal = () => {
formState.value = {
name: '',
community_id: undefined
}
addModalVisible.value = true
}
//
const showAddModalForCommunity = (communityId) => {
formState.value = {
name: '',
community_id: communityId
}
addModalVisible.value = true addModalVisible.value = true
} }
@ -306,7 +284,6 @@ export default defineComponent({
// 驿 // 驿
const editModalVisible = ref(false) const editModalVisible = ref(false)
const editLoading = ref(false) const editLoading = ref(false)
const deleteLoading = ref(false)
const editFormRef = ref(null) const editFormRef = ref(null)
const editFormState = ref({ const editFormState = ref({
name: '', name: '',
@ -315,21 +292,34 @@ export default defineComponent({
const currentEditId = ref(null) const currentEditId = ref(null)
// //
const handleEdit = (record) => { const handleEdit = (station) => {
currentEditId.value = record.id currentEditId.value = station.station_id
editFormState.value = { editFormState.value = {
name: record.name, name: station.station_name,
community_id: record.community_id community_id: findCommunityIdByStation(station)
} }
editModalVisible.value = true editModalVisible.value = true
} }
// 驿ID
const findCommunityIdByStation = (station) => {
for (const community of groupedData.value) {
if (community.stations.some(s => s.station_id === station.station_id)) {
return community.community_id
}
}
return undefined
}
// //
const handleEditSubmit = () => { const handleEditSubmit = () => {
editFormRef.value.validate().then(async () => { editFormRef.value.validate().then(async () => {
try { try {
editLoading.value = true editLoading.value = true
const res = await updateStation(currentEditId.value, editFormState.value) const res = await updateStation(currentEditId.value, {
name: editFormState.value.name,
community_id: editFormState.value.community_id
})
if (res.code === 200) { if (res.code === 200) {
message.success('修改成功') message.success('修改成功')
editModalVisible.value = false editModalVisible.value = false
@ -352,29 +342,6 @@ export default defineComponent({
editModalVisible.value = false editModalVisible.value = false
} }
// 驿
const handleDelete = async (record) => {
try {
deleteLoading.value = true
const res = await request.delete(`/api/station/${record.id}`)
if (res.code === 200) {
message.success('删除成功')
//
if (editModalVisible.value) {
editModalVisible.value = false
}
fetchData() //
} else {
message.error(res.message || '删除失败')
}
} catch (error) {
console.error('删除驿站失败:', error)
message.error('删除失败')
} finally {
deleteLoading.value = false
}
}
onMounted(() => { onMounted(() => {
fetchData() fetchData()
fetchCommunityOptions() fetchCommunityOptions()
@ -382,12 +349,9 @@ export default defineComponent({
return { return {
loading, loading,
columns, groupedData,
tableData,
pagination,
communityOptions, communityOptions,
filterForm, filterForm,
handleTableChange,
handleFilter, handleFilter,
addModalVisible, addModalVisible,
confirmLoading, confirmLoading,
@ -395,17 +359,17 @@ export default defineComponent({
formRef, formRef,
rules, rules,
showAddModal, showAddModal,
showAddModalForCommunity,
handleAdd, handleAdd,
handleCancel, handleCancel,
editModalVisible, editModalVisible,
editLoading, editLoading,
deleteLoading,
editFormRef, editFormRef,
editFormState, editFormState,
handleEdit, handleEdit,
handleEditSubmit, handleEditSubmit,
handleEditCancel, handleEditCancel,
handleDelete currentEditId
} }
} }
}) })
@ -430,6 +394,129 @@ export default defineComponent({
border-radius: 2px; border-radius: 2px;
} }
/* 社区驿站列表样式 */
.community-station-list {
display: flex;
flex-direction: column;
gap: 16px;
}
.community-groups {
display: flex;
flex-direction: column;
gap: 16px;
}
.community-card {
background: #fff;
border-radius: 8px;
padding: 20px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
transition: all 0.3s;
}
.community-card:hover {
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.12);
}
.community-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 16px;
padding-bottom: 12px;
border-bottom: 1px solid #f0f0f0;
}
.community-name {
margin: 0;
font-size: 18px;
color: #1890ff;
font-weight: 500;
}
.header-right {
display: flex;
align-items: center;
gap: 8px;
}
.station-count {
font-size: 14px;
color: rgba(0, 0, 0, 0.45);
background: #f5f5f5;
padding: 4px 10px;
border-radius: 12px;
}
.station-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
gap: 12px;
}
.station-item {
background-color: #f0f7ff;
border-radius: 6px;
transition: all 0.3s;
cursor: pointer;
border: 1px solid #d9e8ff;
position: relative;
overflow: hidden;
}
.station-item:hover {
transform: translateY(-2px);
box-shadow: 0 2px 6px rgba(24, 144, 255, 0.15);
background-color: #e6f7ff;
}
.station-item:hover .station-edit-icon {
opacity: 1;
}
.station-content {
padding: 12px;
text-align: center;
}
.station-name {
font-size: 16px;
font-weight: 500;
color: #1890ff;
margin-bottom: 4px;
}
.station-id {
font-size: 12px;
color: rgba(0, 0, 0, 0.45);
}
.station-edit-icon {
position: absolute;
top: 0;
right: 0;
background-color: rgba(24, 144, 255, 0.1);
color: #1890ff;
padding: 4px;
border-bottom-left-radius: 6px;
opacity: 0;
transition: opacity 0.3s;
}
.empty-data {
margin: 32px 0;
text-align: center;
}
/* 加载状态容器 */
.loading-container {
display: flex;
justify-content: center;
align-items: center;
height: 200px;
}
/* Select 组件样式调整 */ /* Select 组件样式调整 */
:deep(.ant-select-selector) { :deep(.ant-select-selector) {
height: 32px !important; height: 32px !important;
@ -476,12 +563,4 @@ export default defineComponent({
border-top: 1px solid #f0f0f0; border-top: 1px solid #f0f0f0;
padding: 16px 24px; padding: 16px 24px;
} }
/* 带删除按钮的模态框底部样式 */
.modal-footer-with-delete {
display: flex;
justify-content: space-between;
align-items: center;
width: 100%;
}
</style> </style>