增加小区配送时段

This commit is contained in:
aaron 2025-03-04 12:37:38 +08:00
parent 59f9891a5d
commit 76c0602564
3 changed files with 478 additions and 0 deletions

View File

@ -67,6 +67,9 @@
<a-menu-item key="station-list">
<router-link to="/community/station">驿站列表</router-link>
</a-menu-item>
<a-menu-item key="community-time-periods">
<router-link to="/community/time-periods">配送时段</router-link>
</a-menu-item>
</a-sub-menu>
<a-sub-menu key="coupon">
@ -280,6 +283,11 @@ export default defineComponent({
key: 'station-list',
title: '驿站列表',
path: '/community/station'
},
{
key: 'community-time-periods',
title: '配送时段',
path: '/community/time-periods'
}
]
},

View File

@ -57,6 +57,12 @@ const routes = [
name: 'StationList',
component: () => import('../views/station/StationList.vue'),
meta: { title: '驿站列表' }
},
{
path: 'community/time-periods',
name: 'CommunityTimePeriods',
component: () => import('../views/community/TimePeriodList.vue'),
meta: { title: '小区配送时段' }
}
]
},

View File

@ -0,0 +1,464 @@
<template>
<page-container>
<div class="community-time-period-list">
<div class="table-header">
<h1>小区配送时段</h1>
<a-button type="primary" @click="showAddModal">
配置时段
</a-button>
</div>
<a-table
:columns="columns"
:data-source="tableData"
:pagination="pagination"
:loading="loading"
@change="handleTableChange"
row-key="community_id"
>
<template #bodyCell="{ column, record }">
<template v-if="column.key === 'time_periods'">
<a-space wrap>
<a-tag v-for="(period, index) in record.time_periods || []" :key="index" color="blue">
{{ period.time_period_name }}
<span>(运力:{{ period.capacity > 0 ? period.capacity : '不限制' }})</span>
</a-tag>
</a-space>
</template>
<template v-if="column.key === 'action'">
<a-space>
<a @click="handleEdit(record)">编辑</a>
</a-space>
</template>
</template>
</a-table>
<!-- 配置时段模态框 -->
<a-modal
v-model:visible="modalVisible"
title="配置小区配送时段"
@ok="handleSubmit"
@cancel="handleCancel"
:confirmLoading="submitting"
width="720px"
>
<a-form
ref="formRef"
:model="formState"
layout="vertical"
>
<a-form-item
label="选择小区"
name="community_id"
:rules="[{ required: true, message: '请选择小区' }]"
>
<a-select
v-model:value="formState.community_id"
placeholder="请选择小区"
:options="communityOptions"
:disabled="!!currentCommunityId"
@change="handleCommunityChange"
/>
</a-form-item>
<a-form-item
label="配送时段"
name="time_periods"
:rules="[{ required: true, message: '请至少选择一个配送时段' }]"
>
<a-table
:columns="timePeriodColumns"
:data-source="availableTimePeriods"
:pagination="false"
size="small"
:scroll="{ y: 300 }"
>
<template #bodyCell="{ column, record }">
<template v-if="column.key === 'time_range'">
{{ formatTime(record.from_time) }} ~ {{ formatTime(record.to_time) }}
</template>
<template v-if="column.key === 'selected'">
<a-checkbox
:checked="isTimePeriodSelected(record.id)"
@change="(e) => handleTimePeriodSelect(record.id, e.target.checked)"
/>
</template>
<template v-if="column.key === 'capacity'">
<a-input-number
:value="getTimePeriodCapacity(record.id)"
@change="(value) => updateTimePeriodCapacity(record.id, value)"
:min="0"
:disabled="!isTimePeriodSelected(record.id)"
size="small"
/>
</template>
</template>
</a-table>
</a-form-item>
</a-form>
</a-modal>
</div>
</page-container>
</template>
<script>
import { defineComponent, ref, onMounted, computed, h } from 'vue'
import { message, Table, Space, Tag, Button, Modal, Form, Select, Checkbox, InputNumber } from 'ant-design-vue'
import PageContainer from '@/components/PageContainer.vue'
import request from '@/utils/request'
export default defineComponent({
components: {
PageContainer,
ATable: Table,
ASpace: Space,
ATag: Tag,
AButton: Button,
AModal: Modal,
AForm: Form,
AFormItem: Form.Item,
ASelect: Select,
ACheckbox: Checkbox,
AInputNumber: InputNumber
},
setup() {
const loading = ref(false)
const tableData = ref([])
const pagination = ref({
current: 1,
pageSize: 10,
total: 0,
showSizeChanger: true,
showTotal: (total) => `${total} 条记录`
})
const columns = [
{
title: '小区ID',
dataIndex: 'community_id',
key: 'community_id',
width: 80,
align: 'center'
},
{
title: '小区名称',
dataIndex: 'community_name',
key: 'community_name',
width: 200
},
{
title: '配送时段',
key: 'time_periods',
width: 400
},
{
title: '操作',
key: 'action',
width: 80,
fixed: 'right'
}
]
//
const fetchData = async () => {
try {
loading.value = true
const res = await request.get('/api/community-time-periods/group_by_community')
if (res.code === 200) {
tableData.value = res.data
pagination.value.total = res.data.length
} else {
message.error(res.message || '获取数据失败')
}
} catch (error) {
console.error('获取小区配送时段列表失败:', error)
message.error('获取数据失败')
} finally {
loading.value = false
}
}
//
const handleTableChange = (pag) => {
pagination.value.current = pag.current
pagination.value.pageSize = pag.pageSize
fetchData()
}
const modalVisible = ref(false)
const submitting = ref(false)
const currentCommunityId = ref(null)
const formRef = ref(null)
const communities = ref([])
const availableTimePeriods = ref([])
const formState = ref({
community_id: undefined,
time_periods: []
})
//
const timePeriodColumns = [
{
title: '时段名称',
dataIndex: 'name',
key: 'name',
width: 150
},
{
title: '时间范围',
key: 'time_range',
width: 150
},
{
title: '选择',
key: 'selected',
width: 80,
align: 'center'
},
{
title: '配送容量',
key: 'capacity',
width: 120,
align: 'center'
}
]
//
const formatTime = (timeStr) => {
if (!timeStr) return '';
if (timeStr.length > 5 && timeStr.includes(':')) {
return timeStr.substring(0, 5);
}
return timeStr;
}
//
const communityOptions = computed(() => {
return Array.isArray(communities.value) ? communities.value.map(item => ({
label: item.name,
value: item.id
})) : []
})
//
const fetchCommunities = async () => {
try {
const res = await request.get('/api/community')
if (res.code === 200) {
if (res.data && res.data.items && Array.isArray(res.data.items)) {
communities.value = res.data.items
} else {
communities.value = []
}
} else {
message.error(res.message || '获取小区列表失败')
}
} catch (error) {
console.error('获取小区列表失败:', error)
message.error('获取小区列表失败')
}
}
//
const fetchTimePeriods = async () => {
try {
const res = await request.get('/api/time-periods')
if (res.code === 200) {
availableTimePeriods.value = res.data
} else {
message.error(res.message || '获取时段列表失败')
}
} catch (error) {
console.error('获取时段列表失败:', error)
message.error('获取时段列表失败')
}
}
//
const isTimePeriodSelected = (timePeriodId) => {
return formState.value.time_periods.some(item => item.time_period_id === timePeriodId)
}
//
const getTimePeriodCapacity = (timePeriodId) => {
const found = formState.value.time_periods.find(item => item.time_period_id === timePeriodId)
return found ? found.capacity : 0
}
//
const updateTimePeriodCapacity = (timePeriodId, value) => {
const index = formState.value.time_periods.findIndex(item => item.time_period_id === timePeriodId)
if (index !== -1) {
formState.value.time_periods[index].capacity = value
}
}
//
const handleTimePeriodSelect = (timePeriodId, checked) => {
if (checked) {
//
if (!isTimePeriodSelected(timePeriodId)) {
formState.value.time_periods.push({
time_period_id: timePeriodId,
capacity: 0
})
}
} else {
//
formState.value.time_periods = formState.value.time_periods.filter(
item => item.time_period_id !== timePeriodId
)
}
}
//
const handleCommunityChange = (value) => {
//
formState.value.time_periods = []
}
//
const showAddModal = async () => {
currentCommunityId.value = null
formState.value = {
community_id: undefined,
time_periods: []
}
await Promise.all([
fetchCommunities(),
fetchTimePeriods()
])
modalVisible.value = true
}
//
const handleEdit = async (record) => {
currentCommunityId.value = record.community_id
await Promise.all([
fetchCommunities(),
fetchTimePeriods()
])
//
formState.value = {
community_id: record.community_id,
time_periods: []
}
//
record.time_periods.forEach(period => {
// ID
const timePeriod = availableTimePeriods.value.find(
tp => tp.from_time === period.time_period_from_time && tp.to_time === period.time_period_to_time
)
if (timePeriod) {
formState.value.time_periods.push({
time_period_id: timePeriod.id,
capacity: period.capacity
})
}
})
modalVisible.value = true
}
//
const handleSubmit = () => {
formRef.value.validate().then(async () => {
try {
submitting.value = true
//
const params = {
community_id: formState.value.community_id,
time_period_capacity_list: formState.value.time_periods.map(item => ({
community_id: formState.value.community_id,
time_period_id: item.time_period_id,
capacity: item.capacity
}))
}
const res = await request.post('/api/community-time-periods/batch', params)
if (res.code === 200) {
message.success(currentCommunityId.value ? '更新成功' : '配置成功')
modalVisible.value = false
fetchData()
} else {
message.error(res.message || '操作失败')
}
} catch (error) {
console.error('配置小区配送时段失败:', error)
message.error('操作失败')
} finally {
submitting.value = false
}
})
}
//
const handleCancel = () => {
formRef.value?.resetFields()
modalVisible.value = false
}
onMounted(() => {
fetchData()
})
return {
loading,
tableData,
columns,
pagination,
formatTime,
handleTableChange,
modalVisible,
submitting,
formState,
formRef,
showAddModal,
handleEdit,
handleSubmit,
handleCancel,
timePeriodColumns,
availableTimePeriods,
communityOptions,
isTimePeriodSelected,
getTimePeriodCapacity,
updateTimePeriodCapacity,
handleTimePeriodSelect,
handleCommunityChange,
currentCommunityId
}
}
})
</script>
<style scoped>
.table-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 16px;
}
.table-header h1 {
margin: 0;
}
:deep(.ant-table-content) {
overflow-x: auto;
}
:deep(.ant-tag) {
margin-bottom: 5px;
}
</style>