update
This commit is contained in:
parent
d05216743c
commit
321ff3452b
@ -73,6 +73,9 @@
|
|||||||
<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">
|
||||||
|
<router-link to="/community/sets">小区集合</router-link>
|
||||||
|
</a-menu-item>
|
||||||
</a-sub-menu>
|
</a-sub-menu>
|
||||||
|
|
||||||
<a-sub-menu key="coupon">
|
<a-sub-menu key="coupon">
|
||||||
@ -296,6 +299,11 @@ export default defineComponent({
|
|||||||
key: 'community-time-periods',
|
key: 'community-time-periods',
|
||||||
title: '配送时段',
|
title: '配送时段',
|
||||||
path: '/community/time-periods'
|
path: '/community/time-periods'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'community-sets',
|
||||||
|
title: '小区集合',
|
||||||
|
path: '/community/sets'
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|||||||
@ -69,6 +69,18 @@ const routes = [
|
|||||||
name: 'CommunityTimePeriods',
|
name: 'CommunityTimePeriods',
|
||||||
component: () => import('../views/community/TimePeriodList.vue'),
|
component: () => import('../views/community/TimePeriodList.vue'),
|
||||||
meta: { title: '小区配送时段' }
|
meta: { title: '小区配送时段' }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'community/sets',
|
||||||
|
name: 'CommunitySets',
|
||||||
|
component: () => import('../views/community/CommunitySetList.vue'),
|
||||||
|
meta: { title: '小区集合' }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'community/sets/:id',
|
||||||
|
name: 'CommunitySetDetail',
|
||||||
|
component: () => import('../views/community/CommunitySetDetail.vue'),
|
||||||
|
meta: { title: '小区集合详情' }
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|||||||
500
src/views/community/CommunitySetDetail.vue
Normal file
500
src/views/community/CommunitySetDetail.vue
Normal file
@ -0,0 +1,500 @@
|
|||||||
|
<template>
|
||||||
|
<page-container>
|
||||||
|
<div class="community-set-detail">
|
||||||
|
<div class="detail-header">
|
||||||
|
<div class="header-info">
|
||||||
|
<div class="info-card">
|
||||||
|
<h1 class="set-name">{{ setInfo.set_name || '加载中...' }}</h1>
|
||||||
|
<div class="operator-info" v-if="setInfo.user_name">
|
||||||
|
<span class="label">运营商:</span>
|
||||||
|
<span class="value">{{ setInfo.user_name }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="meta-info" v-if="setInfo.create_time">
|
||||||
|
<span class="label">创建时间:</span>
|
||||||
|
<span class="value">{{ setInfo.create_time }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<a-divider />
|
||||||
|
|
||||||
|
<div class="communities-list">
|
||||||
|
<div class="list-header">
|
||||||
|
<h2>关联小区列表</h2>
|
||||||
|
<a-button type="primary" @click="showAddCommunityModal">
|
||||||
|
添加小区
|
||||||
|
</a-button>
|
||||||
|
</div>
|
||||||
|
<a-spin :spinning="loading">
|
||||||
|
<a-empty v-if="communities.length === 0" description="暂无关联小区" />
|
||||||
|
<a-table
|
||||||
|
v-else
|
||||||
|
:columns="columns"
|
||||||
|
:data-source="communities"
|
||||||
|
:pagination="pagination"
|
||||||
|
:loading="loading"
|
||||||
|
@change="handleTableChange"
|
||||||
|
row-key="id"
|
||||||
|
>
|
||||||
|
<template #bodyCell="{ column, record }">
|
||||||
|
<template v-if="column.key === 'action'">
|
||||||
|
<a-button type="link" danger @click="handleRemoveCommunity(record)">
|
||||||
|
移除关联
|
||||||
|
</a-button>
|
||||||
|
</template>
|
||||||
|
</template>
|
||||||
|
</a-table>
|
||||||
|
</a-spin>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 添加小区模态框 -->
|
||||||
|
<a-modal
|
||||||
|
v-model:visible="addCommunityVisible"
|
||||||
|
title="添加小区"
|
||||||
|
:footer="null"
|
||||||
|
>
|
||||||
|
<div class="search-community">
|
||||||
|
<a-input-search
|
||||||
|
v-model:value="searchValue"
|
||||||
|
placeholder="请输入小区名称搜索"
|
||||||
|
enter-button
|
||||||
|
@search="handleSearchCommunity"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-if="searchLoading" class="search-loading">
|
||||||
|
<a-spin />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-else-if="searchResults.length > 0" class="search-results">
|
||||||
|
<div class="search-title">搜索结果:</div>
|
||||||
|
<a-radio-group v-model:value="selectedCommunityId">
|
||||||
|
<div v-for="community in searchResults" :key="community.id" class="search-item">
|
||||||
|
<a-radio :value="community.id">
|
||||||
|
<div class="community-info">
|
||||||
|
<div class="community-name">{{ community.name }}</div>
|
||||||
|
<div class="community-address">{{ community.address }}</div>
|
||||||
|
</div>
|
||||||
|
</a-radio>
|
||||||
|
</div>
|
||||||
|
</a-radio-group>
|
||||||
|
|
||||||
|
<div class="search-actions">
|
||||||
|
<a-button type="primary" :disabled="!selectedCommunityId" :loading="submitting" @click="handleAddCommunity">
|
||||||
|
确认添加
|
||||||
|
</a-button>
|
||||||
|
<a-button style="margin-left: 8px;" @click="handleCancelAdd">
|
||||||
|
取消
|
||||||
|
</a-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-else-if="searchValue && !searchLoading" class="no-results">
|
||||||
|
未找到匹配的小区
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-else class="search-tip">
|
||||||
|
请输入小区名称进行搜索
|
||||||
|
</div>
|
||||||
|
</a-modal>
|
||||||
|
</page-container>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { defineComponent, ref, reactive, onMounted } from 'vue'
|
||||||
|
import { useRoute } from 'vue-router'
|
||||||
|
import { message, Modal, Table, Tag, Spin, Empty, Divider } from 'ant-design-vue'
|
||||||
|
import request from '@/utils/request'
|
||||||
|
import PageContainer from '@/components/PageContainer.vue'
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
components: {
|
||||||
|
PageContainer,
|
||||||
|
ATable: Table,
|
||||||
|
ATag: Tag,
|
||||||
|
ASpin: Spin,
|
||||||
|
AEmpty: Empty,
|
||||||
|
ADivider: Divider
|
||||||
|
},
|
||||||
|
setup() {
|
||||||
|
const route = useRoute()
|
||||||
|
const setId = ref(route.params.id)
|
||||||
|
const loading = ref(false)
|
||||||
|
const setInfo = ref({})
|
||||||
|
const communities = 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
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '小区名称',
|
||||||
|
dataIndex: 'community_name',
|
||||||
|
key: 'community_name',
|
||||||
|
width: 200
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '地址',
|
||||||
|
dataIndex: 'address',
|
||||||
|
key: 'address',
|
||||||
|
ellipsis: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '操作',
|
||||||
|
key: 'action',
|
||||||
|
width: 120,
|
||||||
|
fixed: 'right'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
// 添加小区相关状态
|
||||||
|
const addCommunityVisible = ref(false)
|
||||||
|
const submitting = ref(false)
|
||||||
|
const searchValue = ref('')
|
||||||
|
const searchLoading = ref(false)
|
||||||
|
const searchResults = ref([])
|
||||||
|
const selectedCommunityId = ref(null)
|
||||||
|
|
||||||
|
// 获取集合详情
|
||||||
|
const fetchSetInfo = async () => {
|
||||||
|
try {
|
||||||
|
loading.value = true
|
||||||
|
const res = await request.get(`/api/community-sets/list/all`)
|
||||||
|
if (res.code === 200 && res.data && res.data.items) {
|
||||||
|
const set = res.data.items.find(item => item.id === Number(setId.value))
|
||||||
|
if (set) {
|
||||||
|
setInfo.value = set
|
||||||
|
} else {
|
||||||
|
message.error('未找到小区集合信息')
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
message.error(res.message || '获取集合信息失败')
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('获取小区集合信息失败:', error)
|
||||||
|
message.error('获取集合信息失败')
|
||||||
|
} finally {
|
||||||
|
loading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取关联小区列表
|
||||||
|
const fetchCommunities = async () => {
|
||||||
|
try {
|
||||||
|
loading.value = true
|
||||||
|
const params = {
|
||||||
|
skip: (pagination.value.current - 1) * pagination.value.pageSize,
|
||||||
|
limit: pagination.value.pageSize
|
||||||
|
}
|
||||||
|
|
||||||
|
const res = await request.get(`/api/community-set-mappings/set/${setId.value}/communities`, { params })
|
||||||
|
if (res.code === 200 && res.data) {
|
||||||
|
communities.value = res.data.items || []
|
||||||
|
pagination.value.total = res.data.total || 0
|
||||||
|
} 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
|
||||||
|
fetchCommunities()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取小区状态文本
|
||||||
|
const getStatusText = (status) => {
|
||||||
|
const statusMap = {
|
||||||
|
'OPENING': '营业中',
|
||||||
|
'CLOSED': '已关闭',
|
||||||
|
'PREPARING': '筹备中'
|
||||||
|
}
|
||||||
|
return statusMap[status] || status
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取小区状态颜色
|
||||||
|
const getStatusColor = (status) => {
|
||||||
|
const colorMap = {
|
||||||
|
'OPENING': 'green',
|
||||||
|
'CLOSED': 'red',
|
||||||
|
'PREPARING': 'orange'
|
||||||
|
}
|
||||||
|
return colorMap[status] || 'default'
|
||||||
|
}
|
||||||
|
|
||||||
|
// 显示添加小区模态框
|
||||||
|
const showAddCommunityModal = () => {
|
||||||
|
addCommunityVisible.value = true
|
||||||
|
searchValue.value = ''
|
||||||
|
searchResults.value = []
|
||||||
|
selectedCommunityId.value = null
|
||||||
|
}
|
||||||
|
|
||||||
|
// 搜索小区
|
||||||
|
const handleSearchCommunity = async () => {
|
||||||
|
if (!searchValue.value) {
|
||||||
|
message.warning('请输入小区名称')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
searchLoading.value = true
|
||||||
|
const res = await request.get(`/api/community/search_by_name/${searchValue.value}`)
|
||||||
|
if (res.code === 200) {
|
||||||
|
searchResults.value = res.data || []
|
||||||
|
if (searchResults.value.length > 0) {
|
||||||
|
selectedCommunityId.value = searchResults.value[0].id
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
message.warning(res.message || '搜索小区失败')
|
||||||
|
searchResults.value = []
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('搜索小区失败:', error)
|
||||||
|
message.error('搜索小区失败')
|
||||||
|
searchResults.value = []
|
||||||
|
} finally {
|
||||||
|
searchLoading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 添加小区
|
||||||
|
const handleAddCommunity = async () => {
|
||||||
|
if (!selectedCommunityId.value) {
|
||||||
|
message.warning('请选择要添加的小区')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
submitting.value = true
|
||||||
|
const res = await request.post('/api/community-set-mappings/', {
|
||||||
|
set_id: Number(setId.value),
|
||||||
|
community_id: selectedCommunityId.value
|
||||||
|
})
|
||||||
|
|
||||||
|
if (res.code === 200) {
|
||||||
|
message.success('添加小区成功')
|
||||||
|
addCommunityVisible.value = false
|
||||||
|
fetchCommunities() // 刷新列表
|
||||||
|
} else {
|
||||||
|
message.error(res.message || '添加小区失败')
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('添加小区失败:', error)
|
||||||
|
message.error('添加小区失败')
|
||||||
|
} finally {
|
||||||
|
submitting.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 取消添加
|
||||||
|
const handleCancelAdd = () => {
|
||||||
|
addCommunityVisible.value = false
|
||||||
|
}
|
||||||
|
|
||||||
|
// 移除小区关联
|
||||||
|
const handleRemoveCommunity = (community) => {
|
||||||
|
Modal.confirm({
|
||||||
|
title: '确认移除',
|
||||||
|
content: `确定要移除小区 "${community.community_name}" 的关联吗?`,
|
||||||
|
onOk: async () => {
|
||||||
|
try {
|
||||||
|
const res = await request.delete(`/api/community-set-mappings/${community.id}`)
|
||||||
|
if (res.code === 200) {
|
||||||
|
message.success('移除关联成功')
|
||||||
|
fetchCommunities() // 刷新列表
|
||||||
|
} else {
|
||||||
|
message.error(res.message || '移除关联失败')
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('移除小区关联失败:', error)
|
||||||
|
message.error('移除关联失败')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
fetchSetInfo()
|
||||||
|
fetchCommunities()
|
||||||
|
})
|
||||||
|
|
||||||
|
return {
|
||||||
|
setId,
|
||||||
|
loading,
|
||||||
|
setInfo,
|
||||||
|
communities,
|
||||||
|
columns,
|
||||||
|
pagination,
|
||||||
|
addCommunityVisible,
|
||||||
|
submitting,
|
||||||
|
searchValue,
|
||||||
|
searchLoading,
|
||||||
|
searchResults,
|
||||||
|
selectedCommunityId,
|
||||||
|
getStatusText,
|
||||||
|
getStatusColor,
|
||||||
|
showAddCommunityModal,
|
||||||
|
handleSearchCommunity,
|
||||||
|
handleAddCommunity,
|
||||||
|
handleCancelAdd,
|
||||||
|
handleRemoveCommunity,
|
||||||
|
handleTableChange
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.detail-header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: flex-start;
|
||||||
|
margin-bottom: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-info {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.info-card {
|
||||||
|
background-color: #fafafa;
|
||||||
|
border-radius: 8px;
|
||||||
|
padding: 20px;
|
||||||
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
|
||||||
|
border: 1px solid #f0f0f0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.set-name {
|
||||||
|
margin: 0;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
font-size: 24px;
|
||||||
|
color: #1890ff;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.operator-info, .meta-info {
|
||||||
|
font-size: 14px;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.operator-info .label, .meta-info .label {
|
||||||
|
color: #666;
|
||||||
|
margin-right: 8px;
|
||||||
|
min-width: 70px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.operator-info .value, .meta-info .value {
|
||||||
|
font-weight: 500;
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
|
||||||
|
.communities-list {
|
||||||
|
margin-top: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.list-header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.list-header h2 {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.ant-table-content) {
|
||||||
|
overflow-x: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.ant-table-cell) {
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-community {
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-loading {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
padding: 24px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-results {
|
||||||
|
max-height: 300px;
|
||||||
|
overflow-y: auto;
|
||||||
|
padding: 8px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-item {
|
||||||
|
padding: 8px 0;
|
||||||
|
border-bottom: 1px solid #f0f0f0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-item:last-child {
|
||||||
|
border-bottom: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.community-info {
|
||||||
|
margin-left: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.community-name {
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.community-address {
|
||||||
|
font-size: 12px;
|
||||||
|
color: #666;
|
||||||
|
}
|
||||||
|
|
||||||
|
.no-results {
|
||||||
|
text-align: center;
|
||||||
|
color: #999;
|
||||||
|
padding: 24px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-title {
|
||||||
|
font-weight: bold;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-actions {
|
||||||
|
margin-top: 16px;
|
||||||
|
text-align: right;
|
||||||
|
padding-top: 16px;
|
||||||
|
border-top: 1px solid #f0f0f0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-tip {
|
||||||
|
text-align: center;
|
||||||
|
color: #999;
|
||||||
|
padding: 24px 0;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
441
src/views/community/CommunitySetList.vue
Normal file
441
src/views/community/CommunitySetList.vue
Normal file
@ -0,0 +1,441 @@
|
|||||||
|
<template>
|
||||||
|
<page-container>
|
||||||
|
<div class="community-set-list">
|
||||||
|
<div class="table-header">
|
||||||
|
<h1>小区集合</h1>
|
||||||
|
<a-button type="primary" @click="showCreateModal">
|
||||||
|
创建小区集合
|
||||||
|
</a-button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<a-table
|
||||||
|
:columns="columns"
|
||||||
|
:data-source="tableData"
|
||||||
|
:loading="loading"
|
||||||
|
:pagination="pagination"
|
||||||
|
row-key="id"
|
||||||
|
@change="handleTableChange"
|
||||||
|
>
|
||||||
|
<template #bodyCell="{ column, record }">
|
||||||
|
<template v-if="column.key === 'action'">
|
||||||
|
<a-space>
|
||||||
|
<a-button type="link" @click="handleView(record)">
|
||||||
|
查看详情
|
||||||
|
</a-button>
|
||||||
|
</a-space>
|
||||||
|
</template>
|
||||||
|
</template>
|
||||||
|
</a-table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 创建小区集合模态框 -->
|
||||||
|
<a-modal
|
||||||
|
v-model:visible="createModalVisible"
|
||||||
|
title="创建小区集合"
|
||||||
|
@ok="handleCreateSubmit"
|
||||||
|
@cancel="handleCreateCancel"
|
||||||
|
:confirmLoading="submitting"
|
||||||
|
>
|
||||||
|
<a-form :model="createForm" layout="vertical">
|
||||||
|
<a-form-item
|
||||||
|
label="集合名称"
|
||||||
|
name="set_name"
|
||||||
|
:rules="[{ required: true, message: '请输入集合名称' }]"
|
||||||
|
>
|
||||||
|
<a-input v-model:value="createForm.set_name" placeholder="请输入集合名称" />
|
||||||
|
</a-form-item>
|
||||||
|
|
||||||
|
<a-form-item
|
||||||
|
label="运营商"
|
||||||
|
name="user_id"
|
||||||
|
:rules="[{ required: true, message: '运营商必须选择' }]"
|
||||||
|
>
|
||||||
|
<div class="user-search">
|
||||||
|
<a-input-search
|
||||||
|
v-model:value="phoneSearchValue"
|
||||||
|
placeholder="请输入手机号查询"
|
||||||
|
enter-button
|
||||||
|
@search="handlePhoneSearch"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-if="searchedUser" class="user-result">
|
||||||
|
<div class="user-info">
|
||||||
|
<div class="user-name">{{ searchedUser.nickname || '未设置昵称' }}</div>
|
||||||
|
<div class="user-phone">{{ formatPhone(searchedUser.phone) }}</div>
|
||||||
|
<div class="user-roles">
|
||||||
|
<a-tag v-if="hasPartnerRole(searchedUser)" color="green">运营商</a-tag>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="user-action">
|
||||||
|
<a-button
|
||||||
|
type="primary"
|
||||||
|
size="small"
|
||||||
|
@click="selectUser(searchedUser)"
|
||||||
|
:disabled="isUserSelected(searchedUser)"
|
||||||
|
>
|
||||||
|
{{ isUserSelected(searchedUser) ? '已选择' : '选择' }}
|
||||||
|
</a-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-if="selectedUser" class="selected-user">
|
||||||
|
<div class="selected-info">
|
||||||
|
<div class="user-name">{{ selectedUser.nickname || '未设置昵称' }}</div>
|
||||||
|
<div class="user-phone">{{ formatPhone(selectedUser.phone) }}</div>
|
||||||
|
<a-button type="link" danger size="small" @click="clearSelectedUser">
|
||||||
|
取消选择
|
||||||
|
</a-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</a-form-item>
|
||||||
|
</a-form>
|
||||||
|
</a-modal>
|
||||||
|
</page-container>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { defineComponent, ref, reactive, onMounted, computed } from 'vue'
|
||||||
|
import { message } from 'ant-design-vue'
|
||||||
|
import request from '@/utils/request'
|
||||||
|
import PageContainer from '@/components/PageContainer.vue'
|
||||||
|
import { useRouter } from 'vue-router'
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
components: {
|
||||||
|
PageContainer
|
||||||
|
},
|
||||||
|
setup() {
|
||||||
|
const loading = ref(false)
|
||||||
|
const tableData = ref([])
|
||||||
|
const submitting = ref(false)
|
||||||
|
const router = useRouter()
|
||||||
|
|
||||||
|
// 分页配置
|
||||||
|
const pagination = ref({
|
||||||
|
current: 1,
|
||||||
|
pageSize: 10,
|
||||||
|
total: 0,
|
||||||
|
showSizeChanger: true,
|
||||||
|
showTotal: (total) => `共 ${total} 条记录`
|
||||||
|
})
|
||||||
|
|
||||||
|
// 创建模态框相关状态
|
||||||
|
const createModalVisible = ref(false)
|
||||||
|
const createForm = reactive({
|
||||||
|
set_name: '',
|
||||||
|
user_id: null
|
||||||
|
})
|
||||||
|
|
||||||
|
// 手机号搜索相关状态
|
||||||
|
const phoneSearchValue = ref('')
|
||||||
|
const searchedUser = ref(null)
|
||||||
|
const selectedUser = ref(null)
|
||||||
|
|
||||||
|
// 判断用户是否已选择
|
||||||
|
const isUserSelected = (user) => {
|
||||||
|
return selectedUser.value && selectedUser.value.userid === user.userid
|
||||||
|
}
|
||||||
|
|
||||||
|
// 判断用户是否有运营商角色
|
||||||
|
const hasPartnerRole = (user) => {
|
||||||
|
return user && user.roles && user.roles.includes('partner')
|
||||||
|
}
|
||||||
|
|
||||||
|
// 选择用户
|
||||||
|
const selectUser = (user) => {
|
||||||
|
selectedUser.value = user
|
||||||
|
createForm.user_id = user.userid
|
||||||
|
message.success(`已选择:${user.nickname || user.phone}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 清除已选择的用户
|
||||||
|
const clearSelectedUser = () => {
|
||||||
|
selectedUser.value = null
|
||||||
|
createForm.user_id = null
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取角色名称
|
||||||
|
const getRoleName = (role) => {
|
||||||
|
const roleMap = {
|
||||||
|
'admin': '管理员',
|
||||||
|
'user': '普通用户',
|
||||||
|
'merchant': '商家',
|
||||||
|
'deliveryman': '配送员',
|
||||||
|
'partner': '运营商'
|
||||||
|
}
|
||||||
|
return roleMap[role] || role
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取角色颜色
|
||||||
|
const getRoleColor = (role) => {
|
||||||
|
const colorMap = {
|
||||||
|
'admin': 'red',
|
||||||
|
'user': 'blue',
|
||||||
|
'merchant': 'orange',
|
||||||
|
'deliveryman': 'purple',
|
||||||
|
'partner': 'green'
|
||||||
|
}
|
||||||
|
return colorMap[role] || 'default'
|
||||||
|
}
|
||||||
|
|
||||||
|
const columns = [
|
||||||
|
{
|
||||||
|
title: 'ID',
|
||||||
|
dataIndex: 'id',
|
||||||
|
key: 'id',
|
||||||
|
width: 80,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '集合名称',
|
||||||
|
dataIndex: 'set_name',
|
||||||
|
key: 'set_name',
|
||||||
|
width: 200,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '运营商',
|
||||||
|
dataIndex: 'user_name',
|
||||||
|
key: 'user_name',
|
||||||
|
width: 150,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '小区数量',
|
||||||
|
dataIndex: 'community_count',
|
||||||
|
key: 'community_count',
|
||||||
|
width: 120,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '创建时间',
|
||||||
|
dataIndex: 'create_time',
|
||||||
|
key: 'create_time',
|
||||||
|
width: 180,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '操作',
|
||||||
|
key: 'action',
|
||||||
|
width: 150,
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
// 格式化手机号,中间4位显示*
|
||||||
|
const formatPhone = (phone) => {
|
||||||
|
if (!phone) return ''
|
||||||
|
return phone.replace(/(\d{3})\d{4}(\d{4})/, '$1****$2')
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取小区集合列表
|
||||||
|
const fetchData = async () => {
|
||||||
|
try {
|
||||||
|
loading.value = true
|
||||||
|
const params = {
|
||||||
|
skip: (pagination.value.current - 1) * pagination.value.pageSize,
|
||||||
|
limit: pagination.value.pageSize
|
||||||
|
}
|
||||||
|
|
||||||
|
const res = await request.get('/api/community-sets/list/all', { params })
|
||||||
|
if (res.code === 200 && res.data) {
|
||||||
|
tableData.value = res.data.items || []
|
||||||
|
pagination.value.total = res.data.total || 0
|
||||||
|
} else {
|
||||||
|
message.error(res.message || '获取数据失败')
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('获取小区集合列表失败:', error)
|
||||||
|
message.error('获取数据失败')
|
||||||
|
} finally {
|
||||||
|
loading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 显示创建模态框
|
||||||
|
const showCreateModal = () => {
|
||||||
|
createForm.set_name = ''
|
||||||
|
createForm.user_id = null
|
||||||
|
phoneSearchValue.value = ''
|
||||||
|
searchedUser.value = null
|
||||||
|
selectedUser.value = null
|
||||||
|
createModalVisible.value = true
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理创建提交
|
||||||
|
const handleCreateSubmit = async () => {
|
||||||
|
if (!createForm.set_name) {
|
||||||
|
message.warning('请输入集合名称')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!createForm.user_id) {
|
||||||
|
message.warning('请选择运营商')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
submitting.value = true
|
||||||
|
const res = await request.post('/api/community-sets/', {
|
||||||
|
set_name: createForm.set_name,
|
||||||
|
user_id: createForm.user_id
|
||||||
|
})
|
||||||
|
|
||||||
|
if (res.code === 200) {
|
||||||
|
message.success('创建成功')
|
||||||
|
createModalVisible.value = false
|
||||||
|
fetchData() // 刷新列表
|
||||||
|
} else {
|
||||||
|
message.error(res.message || '创建失败')
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('创建小区集合失败:', error)
|
||||||
|
message.error('创建失败')
|
||||||
|
} finally {
|
||||||
|
submitting.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理创建取消
|
||||||
|
const handleCreateCancel = () => {
|
||||||
|
createModalVisible.value = false
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理手机号搜索
|
||||||
|
const handlePhoneSearch = async () => {
|
||||||
|
if (!phoneSearchValue.value) {
|
||||||
|
message.warning('请输入手机号')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const res = await request.get(`/api/user/search_by_phone/${phoneSearchValue.value}`)
|
||||||
|
if (res.code === 200 && res.data) {
|
||||||
|
searchedUser.value = res.data
|
||||||
|
// 不再自动设置user_id,需要用户手动选择
|
||||||
|
} else {
|
||||||
|
message.warning(res.message || '未找到该用户')
|
||||||
|
searchedUser.value = null
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('搜索用户失败:', error)
|
||||||
|
message.error('搜索失败')
|
||||||
|
searchedUser.value = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查看详情
|
||||||
|
const handleView = (record) => {
|
||||||
|
router.push(`/community/sets/${record.id}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 表格变化处理(分页、排序等)
|
||||||
|
const handleTableChange = (pag) => {
|
||||||
|
pagination.value.current = pag.current
|
||||||
|
pagination.value.pageSize = pag.pageSize
|
||||||
|
fetchData()
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
fetchData()
|
||||||
|
})
|
||||||
|
|
||||||
|
return {
|
||||||
|
loading,
|
||||||
|
tableData,
|
||||||
|
columns,
|
||||||
|
pagination,
|
||||||
|
createModalVisible,
|
||||||
|
createForm,
|
||||||
|
submitting,
|
||||||
|
phoneSearchValue,
|
||||||
|
searchedUser,
|
||||||
|
selectedUser,
|
||||||
|
formatPhone,
|
||||||
|
getRoleName,
|
||||||
|
getRoleColor,
|
||||||
|
isUserSelected,
|
||||||
|
hasPartnerRole,
|
||||||
|
selectUser,
|
||||||
|
clearSelectedUser,
|
||||||
|
showCreateModal,
|
||||||
|
handleCreateSubmit,
|
||||||
|
handleCreateCancel,
|
||||||
|
handlePhoneSearch,
|
||||||
|
handleView,
|
||||||
|
handleTableChange
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</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;
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-search {
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-result {
|
||||||
|
margin-top: 8px;
|
||||||
|
padding: 12px;
|
||||||
|
background-color: #f5f5f5;
|
||||||
|
border-radius: 4px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-info {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-name {
|
||||||
|
font-weight: bold;
|
||||||
|
font-size: 16px;
|
||||||
|
margin-bottom: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-phone {
|
||||||
|
color: #666;
|
||||||
|
margin-bottom: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-roles {
|
||||||
|
margin-top: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-action {
|
||||||
|
margin-left: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.selected-user {
|
||||||
|
margin-top: 16px;
|
||||||
|
padding: 12px;
|
||||||
|
background-color: #e6f7ff;
|
||||||
|
border: 1px solid #91d5ff;
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.selected-info {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.selected-info .user-name {
|
||||||
|
margin-right: 16px;
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.selected-info .user-phone {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
Loading…
Reference in New Issue
Block a user