1776 lines
47 KiB
Vue
1776 lines
47 KiB
Vue
<template>
|
||
<page-container>
|
||
<div class="community-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="id"
|
||
>
|
||
<template #bodyCell="{ column, record }">
|
||
<template v-if="column.key === 'status'">
|
||
<a-dropdown>
|
||
<a-tag :color="getStatusColor(record.status)" class="status-tag">
|
||
{{ getStatusText(record.status) }}
|
||
<down-outlined />
|
||
</a-tag>
|
||
<template #overlay>
|
||
<a-menu @click="({ key }) => handleStatusChange(record, key)">
|
||
<a-menu-item key="OPENING">运营中</a-menu-item>
|
||
<a-menu-item key="UNOPEN">未启用</a-menu-item>
|
||
</a-menu>
|
||
</template>
|
||
</a-dropdown>
|
||
</template>
|
||
<template v-if="column.key === 'location'">
|
||
<a @click="showMap(record)">查看位置</a>
|
||
</template>
|
||
<template v-if="column.key === 'create_time'">
|
||
{{ formatDateTime(record.create_time) }}
|
||
</template>
|
||
<template v-if="column.key === 'qrcode'">
|
||
<a v-if="record.qy_group_qrcode" @click="previewQRCode(record.qy_group_qrcode)">查看二维码</a>
|
||
<span v-else>-</span>
|
||
</template>
|
||
<template v-if="column.key === 'delivery_price'">
|
||
<div class="delivery-price-info">
|
||
<div>基础费:<span style="color: #1890ff; font-weight: bold;">{{ record.base_price }}</span> 元/单</div>
|
||
<div>
|
||
超 <span style="color: #1890ff; font-weight: bold;">{{ record.extra_package_threshold }}</span> 件,加收 <span style="color: #1890ff; font-weight: bold;">{{ record.extra_package_price }}</span> 元/件
|
||
</div>
|
||
</div>
|
||
</template>
|
||
<template v-if="column.key === 'profit_sharing'">
|
||
<div v-if="record.profit_sharing" class="profit-sharing-info-table">
|
||
<div class="profit-rate-item">
|
||
<span class="rate-label">平台</span>
|
||
<span class="rate-value">{{ record.profit_sharing.platform_rate }}%</span>
|
||
<span class="rate-label">运营商</span>
|
||
<span class="rate-value">{{ record.profit_sharing.partner_rate }}%</span>
|
||
</div>
|
||
<div class="profit-rate-item">
|
||
<span class="rate-label">服务商</span>
|
||
<span class="rate-value">{{ record.profit_sharing.admin_rate }}%</span>
|
||
<span class="rate-label">配送员</span>
|
||
<span class="rate-value">{{ record.profit_sharing.delivery_rate }}%</span>
|
||
</div>
|
||
</div>
|
||
<a-tag v-else color="orange">未设置</a-tag>
|
||
</template>
|
||
<template v-if="column.key === 'admin'">
|
||
<div v-if="record.admin" class="admin-info-table">
|
||
<div class="admin-info-row">
|
||
<span class="admin-name">{{ record.admin.nickname || '未知' }}</span>
|
||
</div>
|
||
<div class="admin-info-row">
|
||
<span class="admin-phone">{{ record.admin.phone || '-' }}</span>
|
||
</div>
|
||
</div>
|
||
<a-tag v-else color="orange">未设置</a-tag>
|
||
</template>
|
||
<template v-if="column.key === 'action'">
|
||
<div class="action-buttons">
|
||
<a @click="handleEdit(record)">编辑</a>
|
||
<a-divider type="vertical" />
|
||
<a @click="handleEditDeliveryPrice(record)">配送定价</a>
|
||
<a-divider type="vertical" />
|
||
<a @click="handleEditProfitSharing(record)">设置分润</a>
|
||
<a-divider type="vertical" />
|
||
<a @click="handleSetAdmin(record)">{{ record.admin ? '修改服务商' : '设置服务商' }}</a>
|
||
</div>
|
||
</template>
|
||
</template>
|
||
</a-table>
|
||
|
||
|
||
<a-modal
|
||
v-model:visible="mapVisible"
|
||
title="小区位置"
|
||
:footer="null"
|
||
width="800px"
|
||
@cancel="closeMap"
|
||
>
|
||
<div id="map-container" style="height: 500px;"></div>
|
||
</a-modal>
|
||
|
||
<a-modal
|
||
v-model:visible="modalVisible"
|
||
:title="isEdit ? '编辑小区' : '添加小区'"
|
||
@ok="handleSubmit"
|
||
@cancel="handleCancel"
|
||
:confirmLoading="confirmLoading"
|
||
width="680px"
|
||
>
|
||
<template #footer>
|
||
<a-space>
|
||
<a-button @click="handleCancel">取消</a-button>
|
||
<a-button type="primary" :loading="confirmLoading" @click="handleSubmit">
|
||
保存
|
||
</a-button>
|
||
</a-space>
|
||
</template>
|
||
|
||
<a-form
|
||
ref="formRef"
|
||
:model="formState"
|
||
:rules="rules"
|
||
:label-col="{ span: 6 }"
|
||
:wrapper-col="{ span: 16 }"
|
||
class="community-form"
|
||
>
|
||
<a-form-item label="小区名称" name="name" required>
|
||
<a-input v-model:value="formState.name" placeholder="请输入小区名称" />
|
||
</a-form-item>
|
||
|
||
<map-picker
|
||
v-model="formState.location"
|
||
label="地址搜索"
|
||
/>
|
||
|
||
<a-form-item
|
||
label="企业微信Webhook"
|
||
name="webot_webhook"
|
||
required
|
||
:rules="[
|
||
{ required: true, message: '请输入Webhook地址' },
|
||
{ type: 'url', message: '请输入正确的URL地址' }
|
||
]"
|
||
>
|
||
<a-input
|
||
v-model:value="formState.webot_webhook"
|
||
placeholder="请输入企业微信群机器人Webhook地址"
|
||
:maxLength="500"
|
||
/>
|
||
<div class="form-item-tip">
|
||
小区相关通知将推送到此企业微信群
|
||
</div>
|
||
</a-form-item>
|
||
|
||
<a-form-item
|
||
label="群二维码"
|
||
name="qy_group_qrcode"
|
||
required
|
||
:rules="[{ required: true, message: '请上传群二维码' }]"
|
||
>
|
||
<div class="qrcode-upload-wrapper">
|
||
<a-upload
|
||
v-model:file-list="fileList"
|
||
name="file"
|
||
:customRequest="handleQRCodeUpload"
|
||
@remove="handleQRCodeRemove"
|
||
list-type="picture-card"
|
||
accept=".jpg,.jpeg,.png"
|
||
:max-count="1"
|
||
@preview="previewQRCode"
|
||
>
|
||
<div v-if="!fileList.length">
|
||
<plus-outlined />
|
||
<div style="margin-top: 8px">上传群二维码</div>
|
||
</div>
|
||
</a-upload>
|
||
</div>
|
||
</a-form-item>
|
||
</a-form>
|
||
</a-modal>
|
||
|
||
<!-- 配送定价模态框 -->
|
||
<a-modal
|
||
v-model:visible="deliveryPriceModalVisible"
|
||
title="配送定价设置"
|
||
@ok="handleDeliveryPriceSave"
|
||
@cancel="handleDeliveryPriceCancel"
|
||
:confirmLoading="deliveryPriceSaving"
|
||
width="480px"
|
||
>
|
||
<a-form layout="vertical" class="delivery-price-form">
|
||
<a-form-item
|
||
label="基础配送费(元)"
|
||
required
|
||
:rules="[{ required: true, message: '请输入基础配送费' }]"
|
||
>
|
||
<a-input-number
|
||
v-model:value="deliveryPriceForm.base_price"
|
||
:min="0"
|
||
:precision="2"
|
||
:step="0.5"
|
||
style="width: 100%"
|
||
placeholder="请输入基础配送费"
|
||
/>
|
||
<div class="form-item-tip">每单基础配送费</div>
|
||
</a-form-item>
|
||
|
||
<a-form-item
|
||
label="差额临界数(件)"
|
||
required
|
||
:rules="[{ required: true, message: '请输入差额临界数' }]"
|
||
>
|
||
<a-input-number
|
||
v-model:value="deliveryPriceForm.extra_package_threshold"
|
||
:min="1"
|
||
:precision="0"
|
||
style="width: 100%"
|
||
placeholder="请输入差额临界数"
|
||
/>
|
||
<div class="form-item-tip">超过该件数将收取超额配送费</div>
|
||
</a-form-item>
|
||
|
||
<a-form-item
|
||
label="超额配送费(元/件)"
|
||
required
|
||
:rules="[{ required: true, message: '请输入超额配送费' }]"
|
||
>
|
||
<a-input-number
|
||
v-model:value="deliveryPriceForm.extra_package_price"
|
||
:min="0"
|
||
:precision="2"
|
||
:step="0.5"
|
||
style="width: 100%"
|
||
placeholder="请输入超额配送费"
|
||
/>
|
||
<div class="form-item-tip">超过临界数后,每件商品额外收取的费用</div>
|
||
</a-form-item>
|
||
</a-form>
|
||
</a-modal>
|
||
|
||
<!-- 分润设置模态框 -->
|
||
<a-modal
|
||
v-model:visible="profitSharingModalVisible"
|
||
title="分润设置"
|
||
@ok="handleProfitSharingSave"
|
||
@cancel="handleProfitSharingCancel"
|
||
:confirmLoading="profitSharingSaving"
|
||
width="500px"
|
||
>
|
||
<div class="profit-sharing-header">
|
||
<div class="profit-sharing-title">
|
||
<span>小区名称:</span>
|
||
<span class="profit-sharing-community-name">{{ currentCommunityName }}</span>
|
||
</div>
|
||
<div class="profit-sharing-tip">
|
||
注意:平台分润比例将自动计算,确保总比例等于100%
|
||
</div>
|
||
</div>
|
||
|
||
<div class="profit-sharing-form">
|
||
<div class="profit-rate-row">
|
||
<div class="profit-rate-label">平台分润比例 (%)</div>
|
||
<div class="profit-rate-input">
|
||
<a-input-number
|
||
v-model:value="profitSharingForm.platform_rate"
|
||
:min="0"
|
||
:max="100"
|
||
:precision="0"
|
||
style="width: 100%"
|
||
disabled
|
||
class="platform-rate-input"
|
||
/>
|
||
</div>
|
||
<div class="profit-rate-tip">自动计算</div>
|
||
</div>
|
||
|
||
<div class="profit-rate-row">
|
||
<div class="profit-rate-label">运营商分润比例 (%)</div>
|
||
<div class="profit-rate-input">
|
||
<a-input-number
|
||
v-model:value="profitSharingForm.partner_rate"
|
||
:min="0"
|
||
:max="100"
|
||
:precision="0"
|
||
style="width: 100%"
|
||
placeholder="请输入"
|
||
@change="calculatePlatformRate"
|
||
/>
|
||
</div>
|
||
<div class="profit-rate-tip">运营商获得的分润</div>
|
||
</div>
|
||
|
||
<div class="profit-rate-row">
|
||
<div class="profit-rate-label">服务商分润比例 (%)</div>
|
||
<div class="profit-rate-input">
|
||
<a-input-number
|
||
v-model:value="profitSharingForm.admin_rate"
|
||
:min="0"
|
||
:max="100"
|
||
:precision="0"
|
||
style="width: 100%"
|
||
placeholder="请输入"
|
||
@change="calculatePlatformRate"
|
||
/>
|
||
</div>
|
||
<div class="profit-rate-tip">小区服务商获得的分润</div>
|
||
</div>
|
||
|
||
<div class="profit-rate-row">
|
||
<div class="profit-rate-label">配送员分润比例 (%)</div>
|
||
<div class="profit-rate-input">
|
||
<a-input-number
|
||
v-model:value="profitSharingForm.delivery_rate"
|
||
:min="0"
|
||
:max="100"
|
||
:precision="0"
|
||
style="width: 100%"
|
||
placeholder="请输入"
|
||
@change="calculatePlatformRate"
|
||
/>
|
||
</div>
|
||
<div class="profit-rate-tip">配送员获得的分润</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="total-rate-info" :class="{ 'rate-error': !isRateValid }">
|
||
<span>总比例:{{ getTotalRate() }}%</span>
|
||
<span v-if="!isRateValid" class="rate-error-message">(总比例必须等于100%)</span>
|
||
</div>
|
||
</a-modal>
|
||
|
||
<!-- 设置服务商模态框 -->
|
||
<a-modal
|
||
v-model:visible="adminModalVisible"
|
||
:title="currentCommunity && currentCommunity.admin ? '修改服务商' : '设置服务商'"
|
||
@ok="handleAdminSave"
|
||
@cancel="handleAdminCancel"
|
||
:confirmLoading="adminSaving"
|
||
width="480px"
|
||
>
|
||
<div class="admin-search-form">
|
||
<a-form layout="vertical">
|
||
<a-form-item label="搜索用户">
|
||
<a-input
|
||
v-model:value="adminSearchPhone"
|
||
placeholder="请输入手机号搜索,按回车键搜索"
|
||
:loading="adminSearching"
|
||
@pressEnter="handleSearchAdmin"
|
||
/>
|
||
</a-form-item>
|
||
</a-form>
|
||
|
||
<div v-if="adminSearchResult && !currentCommunity.admin" class="admin-search-result">
|
||
<a-card :class="{ 'admin-card-selected': adminSearchResult.selected }" @click="selectSearchResult(adminSearchResult)">
|
||
<div class="admin-info">
|
||
<div class="admin-info-item">
|
||
<span class="admin-info-label">用户ID:</span>
|
||
<span class="admin-info-value">{{ adminSearchResult.userid }}</span>
|
||
</div>
|
||
<div class="admin-info-item">
|
||
<span class="admin-info-label">姓名:</span>
|
||
<span class="admin-info-value">{{ adminSearchResult.nickname }}</span>
|
||
</div>
|
||
<div class="admin-info-item">
|
||
<span class="admin-info-label">手机号:</span>
|
||
<span class="admin-info-value">{{ adminSearchResult.phone }}</span>
|
||
</div>
|
||
</div>
|
||
</a-card>
|
||
</div>
|
||
|
||
<div v-if="currentCommunity" class="current-admin-info">
|
||
<div class="current-admin-title">当前服务商信息</div>
|
||
<div v-if="currentCommunity.admin" class="admin-info">
|
||
<div class="admin-info-item">
|
||
<span class="admin-info-label">用户ID:</span>
|
||
<span class="admin-info-value">{{ currentCommunity.admin.userid || currentCommunity.admin_id }}</span>
|
||
</div>
|
||
<div class="admin-info-item">
|
||
<span class="admin-info-label">姓名:</span>
|
||
<span class="admin-info-value">{{ currentCommunity.admin.nickname || currentCommunity.admin_name || '未知' }}</span>
|
||
</div>
|
||
<div class="admin-info-item">
|
||
<span class="admin-info-label">手机号:</span>
|
||
<span class="admin-info-value">{{ currentCommunity.admin.phone || currentCommunity.admin_phone || '-' }}</span>
|
||
</div>
|
||
</div>
|
||
<div v-else class="no-admin-info">
|
||
<a-empty description="暂无服务商" />
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</a-modal>
|
||
</div>
|
||
|
||
<!-- 二维码预览模态框 -->
|
||
<a-modal
|
||
v-model:visible="previewVisible"
|
||
:title="previewTitle"
|
||
:footer="null"
|
||
@cancel="handlePreviewCancel"
|
||
>
|
||
<img style="width: 100%" :src="previewImage" />
|
||
</a-modal>
|
||
</page-container>
|
||
</template>
|
||
|
||
<script>
|
||
import { defineComponent, ref, onMounted, nextTick } from 'vue'
|
||
import { message, Tag, Menu, Dropdown, Image, Upload } from 'ant-design-vue'
|
||
import { getCommunityList, createCommunity, updateCommunityStatus, updateCommunity, uploadImage } from '@/api/community'
|
||
import { loadAMap, createMap } from '@/utils/amap.js'
|
||
import dayjs from 'dayjs'
|
||
import PageContainer from '@/components/PageContainer.vue'
|
||
import { DownOutlined, PlusOutlined } from '@ant-design/icons-vue'
|
||
import MapPicker from '@/components/MapPicker/index.vue'
|
||
import request from '../../utils/request'
|
||
export default defineComponent({
|
||
components: {
|
||
PageContainer,
|
||
ATag: Tag,
|
||
ADropdown: Dropdown,
|
||
AMenu: Menu,
|
||
AMenuItem: Menu.Item,
|
||
DownOutlined,
|
||
MapPicker,
|
||
AImage: Image,
|
||
AUpload: Upload,
|
||
PlusOutlined
|
||
},
|
||
setup() {
|
||
const loading = ref(false)
|
||
const tableData = ref([])
|
||
const mapVisible = ref(false)
|
||
const currentMap = ref(null)
|
||
const currentMarker = ref(null)
|
||
|
||
const pagination = ref({
|
||
current: 1,
|
||
pageSize: 10,
|
||
total: 0,
|
||
showSizeChanger: true,
|
||
showTotal: (total) => `共 ${total} 条记录`
|
||
})
|
||
|
||
// 获取状态显示文本
|
||
const getStatusText = (status) => {
|
||
const statusMap = {
|
||
'OPENING': '运营中',
|
||
'UNOPEN': '未启用'
|
||
}
|
||
return statusMap[status] || status
|
||
}
|
||
|
||
// 获取状态标签颜色
|
||
const getStatusColor = (status) => {
|
||
const colorMap = {
|
||
'OPENING': 'green',
|
||
'UNOPEN': 'orange'
|
||
}
|
||
return colorMap[status] || 'default'
|
||
}
|
||
|
||
// 格式化日期时间
|
||
const formatDateTime = (value) => {
|
||
if (!value) return ''
|
||
return dayjs(value).format('YYYY-MM-DD HH:mm:ss')
|
||
}
|
||
|
||
const columns = [
|
||
{
|
||
title: 'ID',
|
||
dataIndex: 'id',
|
||
key: 'id',
|
||
width: 80,
|
||
align: 'center',
|
||
},
|
||
{
|
||
title: '小区名称',
|
||
dataIndex: 'name',
|
||
key: 'name',
|
||
width: 200,
|
||
},
|
||
{
|
||
title: '配送定价',
|
||
key: 'delivery_price',
|
||
width: 200,
|
||
},
|
||
{
|
||
title: '分润比例',
|
||
key: 'profit_sharing',
|
||
width: 220,
|
||
},
|
||
{
|
||
title: '服务商',
|
||
key: 'admin',
|
||
width: 150,
|
||
},
|
||
{
|
||
title: '位置',
|
||
key: 'location',
|
||
width: 100,
|
||
align: 'center',
|
||
},
|
||
{
|
||
title: '状态',
|
||
dataIndex: 'status',
|
||
key: 'status',
|
||
width: 100,
|
||
align: 'center',
|
||
},
|
||
{
|
||
title: '群二维码',
|
||
key: 'qrcode',
|
||
width: 100,
|
||
align: 'center',
|
||
},
|
||
{
|
||
title: '操作',
|
||
key: 'action',
|
||
width: 200,
|
||
align: 'center',
|
||
fixed: 'right'
|
||
},
|
||
]
|
||
|
||
// 获取小区列表数据
|
||
const fetchData = async () => {
|
||
try {
|
||
loading.value = true
|
||
const params = {
|
||
skip: (pagination.value.current - 1) * pagination.value.pageSize,
|
||
limit: pagination.value.pageSize
|
||
}
|
||
|
||
const res = await getCommunityList(params)
|
||
if (res.code === 200) {
|
||
tableData.value = res.data.items
|
||
pagination.value.total = res.data.total
|
||
} 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 showMap = async (record) => {
|
||
mapVisible.value = true
|
||
|
||
await nextTick()
|
||
|
||
try {
|
||
await loadAMap()
|
||
|
||
if (!currentMap.value) {
|
||
currentMap.value = createMap('map-container', {
|
||
zoom: 15,
|
||
viewMode: '3D'
|
||
})
|
||
}
|
||
|
||
const position = [record.longitude, record.latitude]
|
||
currentMap.value.setCenter(position)
|
||
|
||
if (currentMarker.value) {
|
||
currentMap.value.remove(currentMarker.value)
|
||
}
|
||
|
||
currentMarker.value = new window.AMap.Marker({
|
||
position,
|
||
title: record.name
|
||
})
|
||
currentMap.value.add(currentMarker.value)
|
||
|
||
} catch (error) {
|
||
console.error('加载地图失败:', error)
|
||
message.error('加载地图失败')
|
||
}
|
||
}
|
||
|
||
// 关闭地图
|
||
const closeMap = () => {
|
||
mapVisible.value = false
|
||
}
|
||
|
||
// 添加小区相关的响应式变量
|
||
const modalVisible = ref(false)
|
||
const confirmLoading = ref(false)
|
||
const isEdit = ref(false)
|
||
const formRef = ref(null)
|
||
const currentId = ref(null)
|
||
|
||
const formState = ref({
|
||
name: '',
|
||
location: {
|
||
address: '',
|
||
longitude: null,
|
||
latitude: null
|
||
},
|
||
qy_group_qrcode: '',
|
||
status: 'UNOPEN',
|
||
webot_webhook: ''
|
||
})
|
||
|
||
const rules = {
|
||
name: [{ required: true, message: '请输入小区名称' }],
|
||
'location.address': [{ required: true, message: '请选择地址' }],
|
||
'location.longitude': [{ required: true, message: '请在地图上选择位置' }],
|
||
'location.latitude': [{ required: true, message: '请在地图上选择位置' }],
|
||
webot_webhook: [
|
||
{ required: true, message: '请输入Webhook地址' },
|
||
{ type: 'url', message: '请输入正确的URL地址' }
|
||
],
|
||
qy_group_qrcode: [
|
||
{ required: true, message: '请上传群二维码' }
|
||
]
|
||
}
|
||
|
||
// 添加上传相关的响应式变量
|
||
const fileList = ref([])
|
||
const previewVisible = ref(false)
|
||
const previewImage = ref('')
|
||
const previewTitle = ref('')
|
||
|
||
// 显示编辑模态框
|
||
const handleEdit = (record) => {
|
||
isEdit.value = true
|
||
currentId.value = record.id
|
||
modalVisible.value = true
|
||
|
||
// 填充表单数据
|
||
formState.value = {
|
||
name: record.name,
|
||
location: {
|
||
address: record.address,
|
||
longitude: record.longitude,
|
||
latitude: record.latitude
|
||
},
|
||
qy_group_qrcode: record.qy_group_qrcode,
|
||
status: record.status,
|
||
webot_webhook: record.webot_webhook || ''
|
||
}
|
||
|
||
// 如果有二维码,设置文件列表
|
||
if (record.qy_group_qrcode) {
|
||
fileList.value = [{
|
||
uid: '-1',
|
||
name: '群二维码',
|
||
status: 'done',
|
||
url: record.qy_group_qrcode
|
||
}]
|
||
} else {
|
||
fileList.value = []
|
||
}
|
||
}
|
||
|
||
// 显示添加模态框
|
||
const showAddModal = () => {
|
||
isEdit.value = false
|
||
currentId.value = null
|
||
modalVisible.value = true
|
||
formState.value = {
|
||
name: '',
|
||
location: {
|
||
address: '',
|
||
longitude: null,
|
||
latitude: null
|
||
},
|
||
qy_group_qrcode: '',
|
||
status: 'UNOPEN',
|
||
webot_webhook: ''
|
||
}
|
||
fileList.value = []
|
||
}
|
||
|
||
// 修改预览图片函数
|
||
const previewQRCode = async (file) => {
|
||
// 如果直接传入URL字符串
|
||
if (typeof file === 'string') {
|
||
previewImage.value = file
|
||
previewVisible.value = true
|
||
previewTitle.value = '群二维码预览'
|
||
return
|
||
}
|
||
|
||
// 如果是已上传的图片,直接使用 url
|
||
if (file.url) {
|
||
previewImage.value = file.url
|
||
previewVisible.value = true
|
||
previewTitle.value = file.name || '群二维码预览'
|
||
return
|
||
}
|
||
|
||
// 如果是新上传的图片,需要处理 File 对象
|
||
if (file.originFileObj) {
|
||
try {
|
||
const preview = await getBase64(file.originFileObj)
|
||
previewImage.value = preview
|
||
previewVisible.value = true
|
||
previewTitle.value = file.name || '群二维码预览'
|
||
} catch (error) {
|
||
console.error('预览图片失败:', error)
|
||
message.error('预览失败')
|
||
}
|
||
}
|
||
}
|
||
|
||
// 关闭预览
|
||
const handlePreviewCancel = () => {
|
||
previewVisible.value = false
|
||
}
|
||
|
||
// 文件转base64
|
||
const getBase64 = (file) => {
|
||
return new Promise((resolve, reject) => {
|
||
const reader = new FileReader()
|
||
reader.readAsDataURL(file)
|
||
reader.onload = () => resolve(reader.result)
|
||
reader.onerror = error => reject(error)
|
||
})
|
||
}
|
||
|
||
// 修改上传处理函数
|
||
const handleQRCodeUpload = async ({ file, onSuccess, onError }) => {
|
||
const formData = new FormData()
|
||
formData.append('file', file)
|
||
|
||
try {
|
||
const res = await request.post('/api/upload/image', formData, {
|
||
headers: {
|
||
'Content-Type': 'multipart/form-data'
|
||
}
|
||
})
|
||
|
||
if (res.code === 200) {
|
||
formState.value.qy_group_qrcode = res.data.url
|
||
// 更新文件列表以支持预览
|
||
fileList.value = [{
|
||
uid: file.uid,
|
||
name: file.name,
|
||
status: 'done',
|
||
url: res.data.url
|
||
}]
|
||
message.success('上传成功')
|
||
onSuccess(res)
|
||
} else {
|
||
message.error(res.message || '上传失败')
|
||
onError(new Error(res.message || '上传失败'))
|
||
}
|
||
} catch (error) {
|
||
console.error('上传图片失败:', error)
|
||
message.error('上传失败')
|
||
onError(error)
|
||
}
|
||
}
|
||
|
||
// 删除二维码
|
||
const handleQRCodeRemove = (file) => {
|
||
formState.value.qy_group_qrcode = ''
|
||
fileList.value = []
|
||
}
|
||
|
||
// 统一提交处理
|
||
const handleSubmit = () => {
|
||
formRef.value.validate().then(async () => {
|
||
try {
|
||
confirmLoading.value = true
|
||
const params = {
|
||
name: formState.value.name,
|
||
address: formState.value.location.address,
|
||
longitude: formState.value.location.longitude,
|
||
latitude: formState.value.location.latitude,
|
||
qy_group_qrcode: formState.value.qy_group_qrcode,
|
||
status: formState.value.status,
|
||
webot_webhook: formState.value.webot_webhook
|
||
}
|
||
|
||
let res
|
||
if (isEdit.value) {
|
||
res = await updateCommunity(currentId.value, params)
|
||
} else {
|
||
res = await createCommunity(params)
|
||
}
|
||
|
||
if (res.code === 200) {
|
||
message.success(isEdit.value ? '更新成功' : '添加成功')
|
||
modalVisible.value = false
|
||
fetchData() // 刷新列表
|
||
} else {
|
||
message.error(res.message || (isEdit.value ? '更新失败' : '添加失败'))
|
||
}
|
||
} catch (error) {
|
||
console.error(isEdit.value ? '更新小区失败:' : '添加小区失败:', error)
|
||
message.error(isEdit.value ? '更新失败' : '添加失败')
|
||
} finally {
|
||
confirmLoading.value = false
|
||
}
|
||
})
|
||
}
|
||
|
||
// 取消处理
|
||
const handleCancel = () => {
|
||
formRef.value?.resetFields()
|
||
fileList.value = []
|
||
modalVisible.value = false
|
||
}
|
||
|
||
// 处理状态变更
|
||
const handleStatusChange = async (record, status) => {
|
||
try {
|
||
const res = await updateCommunityStatus(record.id, status)
|
||
if (res.code === 200) {
|
||
message.success('状态更新成功')
|
||
// 更新本地数据
|
||
const index = tableData.value.findIndex(item => item.id === record.id)
|
||
if (index !== -1) {
|
||
tableData.value[index].status = status
|
||
}
|
||
} else {
|
||
message.error(res.message || '状态更新失败')
|
||
}
|
||
} catch (error) {
|
||
console.error('更新小区状态失败:', error)
|
||
message.error('状态更新失败')
|
||
}
|
||
}
|
||
|
||
// 添加配送定价相关的状态
|
||
const deliveryPriceModalVisible = ref(false)
|
||
const deliveryPriceSaving = ref(false)
|
||
const deliveryPriceForm = ref({
|
||
base_price: 0,
|
||
extra_package_threshold: 1,
|
||
extra_package_price: 0
|
||
})
|
||
const currentCommunityId = ref(null)
|
||
|
||
// 显示配送定价模态框
|
||
const handleEditDeliveryPrice = (record) => {
|
||
currentCommunityId.value = record.id
|
||
deliveryPriceForm.value = {
|
||
base_price: record.base_price || 0,
|
||
extra_package_threshold: record.extra_package_threshold || 1,
|
||
extra_package_price: record.extra_package_price || 0
|
||
}
|
||
deliveryPriceModalVisible.value = true
|
||
}
|
||
|
||
// 保存配送定价
|
||
const handleDeliveryPriceSave = async () => {
|
||
try {
|
||
deliveryPriceSaving.value = true
|
||
const res = await request.put(`/api/community/${currentCommunityId.value}`, {
|
||
base_price: deliveryPriceForm.value.base_price,
|
||
extra_package_threshold: deliveryPriceForm.value.extra_package_threshold,
|
||
extra_package_price: deliveryPriceForm.value.extra_package_price
|
||
})
|
||
|
||
if (res.code === 200) {
|
||
message.success('配送定价设置成功')
|
||
deliveryPriceModalVisible.value = false
|
||
fetchData() // 刷新列表
|
||
} else {
|
||
message.error(res.message || '设置失败')
|
||
}
|
||
} catch (error) {
|
||
console.error('设置配送定价失败:', error)
|
||
message.error('设置失败')
|
||
} finally {
|
||
deliveryPriceSaving.value = false
|
||
}
|
||
}
|
||
|
||
// 取消配送定价设置
|
||
const handleDeliveryPriceCancel = () => {
|
||
deliveryPriceModalVisible.value = false
|
||
currentCommunityId.value = null
|
||
deliveryPriceForm.value = {
|
||
base_price: 0,
|
||
extra_package_threshold: 1,
|
||
extra_package_price: 0
|
||
}
|
||
}
|
||
|
||
// 添加分润设置相关的状态
|
||
const profitSharingModalVisible = ref(false)
|
||
const profitSharingSaving = ref(false)
|
||
const currentCommunityName = ref('')
|
||
const isRateValid = ref(true)
|
||
const profitSharingForm = ref({
|
||
platform_rate: 10,
|
||
partner_rate: 10,
|
||
admin_rate: 10,
|
||
delivery_rate: 70
|
||
})
|
||
|
||
// 显示分润设置模态框
|
||
const handleEditProfitSharing = async (record) => {
|
||
currentCommunityId.value = record.id
|
||
currentCommunityName.value = record.name
|
||
profitSharingSaving.value = true
|
||
|
||
try {
|
||
// 检查是否已有分润设置
|
||
const hasProfitSharing = record.profit_sharing !== null
|
||
|
||
if (hasProfitSharing) {
|
||
// 如果已有分润设置,使用现有数据
|
||
profitSharingForm.value = {
|
||
platform_rate: record.profit_sharing.platform_rate,
|
||
partner_rate: record.profit_sharing.partner_rate,
|
||
admin_rate: record.profit_sharing.admin_rate,
|
||
delivery_rate: record.profit_sharing.delivery_rate
|
||
}
|
||
} else {
|
||
// 如果没有分润设置,使用默认值
|
||
profitSharingForm.value = {
|
||
platform_rate: 10,
|
||
partner_rate: 10,
|
||
admin_rate: 10,
|
||
delivery_rate: 70
|
||
}
|
||
}
|
||
|
||
validateTotalRate()
|
||
profitSharingModalVisible.value = true
|
||
} catch (error) {
|
||
console.error('获取分润设置失败:', error)
|
||
message.error('获取分润设置失败')
|
||
} finally {
|
||
profitSharingSaving.value = false
|
||
}
|
||
}
|
||
|
||
// 计算平台分润比例
|
||
const calculatePlatformRate = () => {
|
||
const otherRatesTotal =
|
||
profitSharingForm.value.partner_rate +
|
||
profitSharingForm.value.admin_rate +
|
||
profitSharingForm.value.delivery_rate
|
||
|
||
// 确保其他比例之和不超过100%
|
||
if (otherRatesTotal > 100) {
|
||
message.warning('其他分润比例之和不能超过100%')
|
||
return
|
||
}
|
||
|
||
// 计算平台分润比例
|
||
profitSharingForm.value.platform_rate = 100 - otherRatesTotal
|
||
|
||
// 验证总比例
|
||
validateTotalRate()
|
||
}
|
||
|
||
// 计算总比例
|
||
const getTotalRate = () => {
|
||
return (
|
||
profitSharingForm.value.platform_rate +
|
||
profitSharingForm.value.partner_rate +
|
||
profitSharingForm.value.admin_rate +
|
||
profitSharingForm.value.delivery_rate
|
||
)
|
||
}
|
||
|
||
// 验证总比例是否为100%
|
||
const validateTotalRate = () => {
|
||
const total = getTotalRate()
|
||
isRateValid.value = total === 100
|
||
return isRateValid.value
|
||
}
|
||
|
||
// 保存分润设置
|
||
const handleProfitSharingSave = async () => {
|
||
if (!validateTotalRate()) {
|
||
message.error('所有比例之和必须等于100%')
|
||
return
|
||
}
|
||
|
||
try {
|
||
profitSharingSaving.value = true
|
||
|
||
const params = {
|
||
platform_rate: profitSharingForm.value.platform_rate,
|
||
partner_rate: profitSharingForm.value.partner_rate,
|
||
admin_rate: profitSharingForm.value.admin_rate,
|
||
delivery_rate: profitSharingForm.value.delivery_rate
|
||
}
|
||
|
||
// 查找当前编辑的小区
|
||
const currentCommunity = tableData.value.find(item => item.id === currentCommunityId.value)
|
||
const hasProfitSharing = currentCommunity && currentCommunity.profit_sharing !== null
|
||
|
||
let res
|
||
if (hasProfitSharing) {
|
||
// 如果已有分润设置,调用修改接口
|
||
res = await request.put(`/api/community-profit-sharings/community/${currentCommunityId.value}`, params)
|
||
} else {
|
||
// 如果没有分润设置,调用创建接口
|
||
res = await request.post('/api/community-profit-sharings/', {
|
||
...params,
|
||
community_id: currentCommunityId.value
|
||
})
|
||
}
|
||
|
||
if (res.code === 200) {
|
||
// 查找当前编辑的小区在表格数据中的索引
|
||
const index = tableData.value.findIndex(item => item.id === currentCommunityId.value)
|
||
|
||
if (index !== -1) {
|
||
// 更新本地数据,避免重新请求整个列表
|
||
if (!tableData.value[index].profit_sharing) {
|
||
tableData.value[index].profit_sharing = {}
|
||
}
|
||
|
||
tableData.value[index].profit_sharing = {
|
||
platform_rate: params.platform_rate,
|
||
partner_rate: params.partner_rate,
|
||
admin_rate: params.admin_rate,
|
||
delivery_rate: params.delivery_rate
|
||
}
|
||
}
|
||
|
||
message.success('分润设置保存成功')
|
||
profitSharingModalVisible.value = false
|
||
} else {
|
||
message.error(res.message || '保存失败')
|
||
}
|
||
} catch (error) {
|
||
console.error('保存分润设置失败:', error)
|
||
message.error('保存失败')
|
||
} finally {
|
||
profitSharingSaving.value = false
|
||
}
|
||
}
|
||
|
||
// 取消分润设置
|
||
const handleProfitSharingCancel = () => {
|
||
profitSharingModalVisible.value = false
|
||
currentCommunityId.value = null
|
||
currentCommunityName.value = ''
|
||
}
|
||
|
||
// 添加服务商相关的状态
|
||
const adminModalVisible = ref(false)
|
||
const adminSaving = ref(false)
|
||
const adminSearching = ref(false)
|
||
const adminSearchPhone = ref('')
|
||
const adminSearchResult = ref(null)
|
||
const currentCommunity = ref(null)
|
||
|
||
// 显示设置服务商模态框
|
||
const handleSetAdmin = (record) => {
|
||
currentCommunity.value = { ...record }
|
||
adminSearchPhone.value = ''
|
||
adminSearchResult.value = null
|
||
|
||
// 如果已有服务商,不需要设置搜索结果
|
||
// 如果没有服务商,则需要通过搜索来选择
|
||
adminModalVisible.value = true
|
||
}
|
||
|
||
// 搜索用户
|
||
const handleSearchAdmin = async () => {
|
||
if (!adminSearchPhone.value || adminSearchPhone.value.length < 5) {
|
||
message.warning('请输入有效的手机号')
|
||
return
|
||
}
|
||
|
||
try {
|
||
adminSearching.value = true
|
||
const res = await request.get(`/api/user/search_by_phone/${adminSearchPhone.value}`)
|
||
if (res.code === 200) {
|
||
if (res.data) {
|
||
adminSearchResult.value = {
|
||
...res.data,
|
||
selected: false
|
||
}
|
||
} else {
|
||
adminSearchResult.value = null
|
||
message.warning('未找到该用户')
|
||
}
|
||
} else {
|
||
message.error(res.message || '搜索失败')
|
||
}
|
||
} catch (error) {
|
||
console.error('搜索用户失败:', error)
|
||
message.error('搜索失败')
|
||
} finally {
|
||
adminSearching.value = false
|
||
}
|
||
}
|
||
|
||
// 选择搜索结果
|
||
const selectSearchResult = (result) => {
|
||
if (adminSearchResult.value) {
|
||
adminSearchResult.value.selected = !adminSearchResult.value.selected
|
||
}
|
||
}
|
||
|
||
// 保存服务商设置
|
||
const handleAdminSave = async () => {
|
||
// 如果已有服务商,则直接关闭模态框,不做任何操作
|
||
if (currentCommunity.value.admin) {
|
||
adminModalVisible.value = false
|
||
return
|
||
}
|
||
|
||
if (!adminSearchResult.value) {
|
||
message.warning('请先搜索并选择服务商')
|
||
return
|
||
}
|
||
|
||
if (!adminSearchResult.value.selected) {
|
||
message.warning('请先选择搜索结果中的用户作为服务商')
|
||
return
|
||
}
|
||
|
||
try {
|
||
adminSaving.value = true
|
||
const params = {
|
||
admin_id: adminSearchResult.value.userid
|
||
}
|
||
|
||
const res = await request.put(`/api/community/${currentCommunity.value.id}`, params)
|
||
if (res.code === 200) {
|
||
message.success('服务商设置成功')
|
||
adminModalVisible.value = false
|
||
|
||
// 刷新列表数据
|
||
fetchData()
|
||
} else {
|
||
message.error(res.message || '设置失败')
|
||
}
|
||
} catch (error) {
|
||
console.error('设置服务商失败:', error)
|
||
message.error('设置失败')
|
||
} finally {
|
||
adminSaving.value = false
|
||
}
|
||
}
|
||
|
||
// 取消服务商设置
|
||
const handleAdminCancel = () => {
|
||
adminModalVisible.value = false
|
||
adminSearchPhone.value = ''
|
||
adminSearchResult.value = null
|
||
currentCommunity.value = null
|
||
}
|
||
|
||
onMounted(() => {
|
||
fetchData()
|
||
})
|
||
|
||
return {
|
||
loading,
|
||
columns,
|
||
tableData,
|
||
pagination,
|
||
mapVisible,
|
||
handleTableChange,
|
||
showMap,
|
||
closeMap,
|
||
getStatusText,
|
||
getStatusColor,
|
||
formatDateTime,
|
||
modalVisible,
|
||
confirmLoading,
|
||
isEdit,
|
||
formState,
|
||
formRef,
|
||
rules,
|
||
showAddModal,
|
||
handleSubmit,
|
||
handleCancel,
|
||
handleStatusChange,
|
||
fileList,
|
||
handleQRCodeUpload,
|
||
handleQRCodeRemove,
|
||
handleEdit,
|
||
previewVisible,
|
||
previewImage,
|
||
previewTitle,
|
||
handlePreviewCancel,
|
||
previewQRCode,
|
||
deliveryPriceModalVisible,
|
||
deliveryPriceSaving,
|
||
deliveryPriceForm,
|
||
handleEditDeliveryPrice,
|
||
handleDeliveryPriceSave,
|
||
handleDeliveryPriceCancel,
|
||
profitSharingModalVisible,
|
||
profitSharingSaving,
|
||
profitSharingForm,
|
||
currentCommunityName,
|
||
isRateValid,
|
||
handleEditProfitSharing,
|
||
handleProfitSharingSave,
|
||
handleProfitSharingCancel,
|
||
getTotalRate,
|
||
validateTotalRate,
|
||
calculatePlatformRate,
|
||
adminModalVisible,
|
||
adminSaving,
|
||
adminSearching,
|
||
adminSearchPhone,
|
||
adminSearchResult,
|
||
currentCommunity,
|
||
handleSetAdmin,
|
||
handleSearchAdmin,
|
||
handleAdminSave,
|
||
handleAdminCancel,
|
||
selectSearchResult
|
||
}
|
||
}
|
||
})
|
||
</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-modal-body) {
|
||
padding: 24px;
|
||
max-width: 100%;
|
||
}
|
||
|
||
:deep(.ant-form) {
|
||
max-width: 600px;
|
||
margin: 0 auto;
|
||
}
|
||
|
||
:deep(.ant-form-item) {
|
||
margin-bottom: 16px;
|
||
}
|
||
|
||
:deep(.ant-input),
|
||
:deep(.ant-input-number),
|
||
:deep(.ant-auto-complete) {
|
||
width: 100% !important;
|
||
}
|
||
|
||
:deep(.ant-input-number-input) {
|
||
height: 32px;
|
||
}
|
||
|
||
:deep(.ant-form-item-control-input) {
|
||
width: 100%;
|
||
}
|
||
|
||
:deep(.ant-col) {
|
||
padding-right: 12px;
|
||
padding-left: 12px;
|
||
}
|
||
|
||
:deep(.ant-select-item-option-content) {
|
||
white-space: normal;
|
||
word-break: break-all;
|
||
}
|
||
|
||
:deep(.ant-row) {
|
||
margin-bottom: 0 !important;
|
||
}
|
||
|
||
:deep(.ant-form-item) {
|
||
margin-bottom: 16px;
|
||
}
|
||
|
||
:deep(.ant-col) {
|
||
padding-right: 8px;
|
||
padding-left: 8px;
|
||
}
|
||
|
||
/* 地图区域样式 */
|
||
.map-section {
|
||
margin-bottom: 24px;
|
||
padding: 16px;
|
||
background: #fafafa;
|
||
border-radius: 4px;
|
||
}
|
||
|
||
.search-item {
|
||
margin-bottom: 16px;
|
||
}
|
||
|
||
.map-container {
|
||
border: 1px solid #f0f0f0;
|
||
border-radius: 2px;
|
||
overflow: hidden;
|
||
}
|
||
|
||
:deep(.ant-form-item-label) {
|
||
height: 32px;
|
||
line-height: 32px;
|
||
text-align: left;
|
||
padding-right: 12px;
|
||
|
||
/* 调整必填星号的样式 */
|
||
> label.ant-form-item-required:not(.ant-form-item-required-mark-optional)::before {
|
||
color: #ff4d4f;
|
||
font-size: 14px;
|
||
margin-right: 4px;
|
||
}
|
||
}
|
||
|
||
:deep(.ant-form-item) {
|
||
margin-bottom: 24px;
|
||
}
|
||
|
||
:deep(.ant-input),
|
||
:deep(.ant-input-number),
|
||
:deep(.ant-auto-complete) {
|
||
width: 100%;
|
||
}
|
||
|
||
:deep(.ant-input-group) {
|
||
display: flex;
|
||
}
|
||
|
||
:deep(.ant-input-group .ant-input-number) {
|
||
border-radius: 0;
|
||
|
||
&:first-child {
|
||
border-top-left-radius: 2px;
|
||
border-bottom-left-radius: 2px;
|
||
}
|
||
|
||
&:last-child {
|
||
border-top-right-radius: 2px;
|
||
border-bottom-right-radius: 2px;
|
||
}
|
||
}
|
||
|
||
:deep(.ant-form) {
|
||
max-width: 600px;
|
||
margin: 0 auto;
|
||
}
|
||
|
||
:deep(.ant-modal-body) {
|
||
padding: 24px;
|
||
}
|
||
|
||
:deep(.ant-modal-footer) {
|
||
text-align: left;
|
||
padding: 16px 24px;
|
||
border-top: 1px solid #f0f0f0;
|
||
}
|
||
|
||
/* 优化表单样式,减少高度 */
|
||
.community-form {
|
||
padding: 4px 0;
|
||
}
|
||
|
||
:deep(.ant-form-item) {
|
||
margin-bottom: 12px !important;
|
||
}
|
||
|
||
:deep(.ant-form-item-label) {
|
||
height: 28px;
|
||
line-height: 28px;
|
||
padding-bottom: 0;
|
||
}
|
||
|
||
:deep(.ant-form-item-control) {
|
||
line-height: 28px;
|
||
}
|
||
|
||
:deep(.ant-input),
|
||
:deep(.ant-select),
|
||
:deep(.ant-auto-complete),
|
||
:deep(.ant-input-number) {
|
||
height: 30px;
|
||
}
|
||
|
||
:deep(.ant-select-selector),
|
||
:deep(.ant-auto-complete .ant-input) {
|
||
height: 30px !important;
|
||
line-height: 30px !important;
|
||
padding: 0 11px !important;
|
||
|
||
.ant-select-selection-search-input {
|
||
height: 28px !important;
|
||
}
|
||
|
||
.ant-select-selection-item {
|
||
line-height: 28px !important;
|
||
}
|
||
}
|
||
|
||
:deep(.ant-input-number-input) {
|
||
height: 28px;
|
||
line-height: 28px;
|
||
}
|
||
|
||
.form-item-tip {
|
||
color: rgba(0, 0, 0, 0.45);
|
||
font-size: 12px;
|
||
margin-top: 2px;
|
||
line-height: 1.2;
|
||
}
|
||
|
||
.qrcode-upload-wrapper {
|
||
:deep(.ant-upload-list-picture-card-container) {
|
||
width: 90px;
|
||
height: 90px;
|
||
margin-right: 8px;
|
||
margin-bottom: 8px;
|
||
}
|
||
|
||
:deep(.ant-upload.ant-upload-select-picture-card) {
|
||
width: 90px;
|
||
height: 90px;
|
||
margin-right: 8px;
|
||
margin-bottom: 8px;
|
||
}
|
||
|
||
:deep(.ant-upload-list-picture-card .ant-upload-list-item) {
|
||
padding: 2px;
|
||
}
|
||
}
|
||
|
||
/* 调整地图组件样式 */
|
||
:deep(.map-picker-container) {
|
||
margin-bottom: 12px;
|
||
}
|
||
|
||
:deep(.map-picker-input) {
|
||
margin-bottom: 8px;
|
||
}
|
||
|
||
:deep(.map-container) {
|
||
height: 200px !important; /* 减少地图高度 */
|
||
}
|
||
|
||
.status-tag {
|
||
cursor: pointer;
|
||
user-select: none;
|
||
display: inline-flex;
|
||
align-items: center;
|
||
gap: 4px;
|
||
}
|
||
|
||
:deep(.anticon) {
|
||
font-size: 12px;
|
||
}
|
||
|
||
/* 调整 Select 组件的样式 */
|
||
:deep(.ant-select-selector) {
|
||
height: 32px !important;
|
||
|
||
.ant-select-selection-item {
|
||
line-height: 30px !important; /* 调整文字行高 */
|
||
padding-top: 0 !important; /* 移除顶部内边距 */
|
||
padding-bottom: 0 !important; /* 移除底部内边距 */
|
||
}
|
||
}
|
||
|
||
/* 调整选项的样式 */
|
||
:deep(.ant-select-dropdown) {
|
||
.ant-select-item {
|
||
padding: 5px 12px; /* 调整选项内边距 */
|
||
line-height: 22px; /* 调整选项行高 */
|
||
}
|
||
}
|
||
|
||
/* 确保输入框内的文字垂直居中 */
|
||
:deep(.ant-select-selection-search-input) {
|
||
height: 30px !important;
|
||
line-height: 30px !important;
|
||
}
|
||
|
||
/* 确保占位符文字垂直居中 */
|
||
:deep(.ant-select-selection-placeholder) {
|
||
line-height: 30px !important;
|
||
}
|
||
|
||
.delivery-price-info {
|
||
line-height: 1.5;
|
||
font-size: 13px;
|
||
|
||
> div {
|
||
margin-bottom: 2px;
|
||
|
||
&:last-child {
|
||
margin-bottom: 0;
|
||
color: rgba(0, 0, 0, 0.65);
|
||
font-size: 12px;
|
||
}
|
||
}
|
||
}
|
||
|
||
/* 添加分润设置相关的样式 */
|
||
.profit-sharing-info {
|
||
margin-bottom: 16px;
|
||
padding: 12px;
|
||
background-color: #f9f9f9;
|
||
border-radius: 4px;
|
||
}
|
||
|
||
.profit-sharing-header {
|
||
margin-bottom: 16px;
|
||
padding: 12px;
|
||
background-color: #f9f9f9;
|
||
border-radius: 4px;
|
||
}
|
||
|
||
.profit-sharing-title {
|
||
margin-bottom: 8px;
|
||
font-size: 14px;
|
||
}
|
||
|
||
.profit-sharing-community-name {
|
||
font-weight: 500;
|
||
color: #1890ff;
|
||
}
|
||
|
||
.profit-sharing-tip {
|
||
font-size: 12px;
|
||
color: #ff4d4f;
|
||
}
|
||
|
||
.profit-sharing-form {
|
||
margin-bottom: 16px;
|
||
}
|
||
|
||
.profit-rate-row {
|
||
display: flex;
|
||
align-items: center;
|
||
margin-bottom: 12px;
|
||
}
|
||
|
||
.profit-rate-label {
|
||
width: 150px;
|
||
font-size: 14px;
|
||
color: rgba(0, 0, 0, 0.85);
|
||
}
|
||
|
||
.profit-rate-input {
|
||
width: 100px;
|
||
margin-right: 12px;
|
||
}
|
||
|
||
.profit-rate-tip {
|
||
flex: 1;
|
||
font-size: 12px;
|
||
color: rgba(0, 0, 0, 0.45);
|
||
}
|
||
|
||
.total-rate-info {
|
||
margin-top: 16px;
|
||
padding: 8px 12px;
|
||
background-color: #f6ffed;
|
||
border-radius: 4px;
|
||
border: 1px solid #b7eb8f;
|
||
color: #52c41a;
|
||
font-weight: 500;
|
||
text-align: center;
|
||
}
|
||
|
||
.rate-error {
|
||
background-color: #fff2f0;
|
||
border-color: #ffccc7;
|
||
color: #ff4d4f;
|
||
}
|
||
|
||
.rate-error-message {
|
||
margin-left: 8px;
|
||
font-weight: normal;
|
||
}
|
||
|
||
/* 表格中分润比例显示样式 */
|
||
.profit-sharing-info-table {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 6px;
|
||
font-size: 12px;
|
||
padding: 4px 0;
|
||
}
|
||
|
||
.profit-rate-item {
|
||
display: flex;
|
||
align-items: center;
|
||
line-height: 1.5;
|
||
}
|
||
|
||
.rate-label {
|
||
color: rgba(0, 0, 0, 0.65);
|
||
margin-right: 4px;
|
||
margin-left: 8px;
|
||
white-space: nowrap;
|
||
}
|
||
|
||
.rate-label:first-child {
|
||
margin-left: 0;
|
||
}
|
||
|
||
.rate-value {
|
||
font-weight: 500;
|
||
color: #1890ff;
|
||
margin-right: 12px;
|
||
white-space: nowrap;
|
||
}
|
||
|
||
/* 操作列按钮样式 */
|
||
.action-buttons {
|
||
display: flex;
|
||
justify-content: center;
|
||
align-items: center;
|
||
white-space: nowrap;
|
||
}
|
||
|
||
.action-buttons a {
|
||
white-space: nowrap;
|
||
padding: 0 4px;
|
||
}
|
||
|
||
:deep(.ant-divider-vertical) {
|
||
margin: 0 8px;
|
||
}
|
||
|
||
/* 平台分润比例输入框样式 */
|
||
.platform-rate-input {
|
||
background-color: #f5f5f5;
|
||
}
|
||
|
||
:deep(.platform-rate-input .ant-input-number-input) {
|
||
color: #1890ff;
|
||
font-weight: 500;
|
||
}
|
||
|
||
/* 配送定价表单样式 */
|
||
.delivery-price-form {
|
||
padding: 0;
|
||
}
|
||
|
||
.delivery-price-form :deep(.ant-form-item) {
|
||
margin-bottom: 12px !important;
|
||
}
|
||
|
||
.delivery-price-form :deep(.ant-form-item:last-child) {
|
||
margin-bottom: 0 !important;
|
||
}
|
||
|
||
.delivery-price-form :deep(.ant-form-item-label) {
|
||
padding-bottom: 4px;
|
||
}
|
||
|
||
.delivery-price-form :deep(.ant-form-item-label > label) {
|
||
font-size: 14px;
|
||
height: 22px;
|
||
}
|
||
|
||
.delivery-price-form :deep(.ant-input-number) {
|
||
width: 100% !important;
|
||
}
|
||
|
||
.delivery-price-form .form-item-tip {
|
||
margin-top: 2px;
|
||
font-size: 12px;
|
||
color: rgba(0, 0, 0, 0.45);
|
||
line-height: 1.2;
|
||
}
|
||
|
||
/* 服务商设置相关样式 */
|
||
.admin-search-form {
|
||
margin-bottom: 16px;
|
||
}
|
||
|
||
.admin-search-result {
|
||
margin-top: 16px;
|
||
margin-bottom: 16px;
|
||
}
|
||
|
||
.admin-card-selected {
|
||
border: 2px solid #1890ff;
|
||
cursor: pointer;
|
||
}
|
||
|
||
.admin-search-result :deep(.ant-card) {
|
||
cursor: pointer;
|
||
transition: all 0.3s;
|
||
}
|
||
|
||
.admin-search-result :deep(.ant-card:hover) {
|
||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
|
||
}
|
||
|
||
.current-admin-info {
|
||
margin-top: 24px;
|
||
border-top: 1px dashed #e8e8e8;
|
||
padding-top: 16px;
|
||
}
|
||
|
||
.current-admin-title {
|
||
font-size: 14px;
|
||
font-weight: 500;
|
||
color: rgba(0, 0, 0, 0.85);
|
||
margin-bottom: 12px;
|
||
}
|
||
|
||
.admin-info {
|
||
background-color: #f9f9f9;
|
||
padding: 12px;
|
||
border-radius: 4px;
|
||
}
|
||
|
||
.admin-info-item {
|
||
margin-bottom: 8px;
|
||
display: flex;
|
||
}
|
||
|
||
.admin-info-item:last-child {
|
||
margin-bottom: 0;
|
||
}
|
||
|
||
.admin-info-label {
|
||
width: 70px;
|
||
color: rgba(0, 0, 0, 0.65);
|
||
}
|
||
|
||
.admin-info-value {
|
||
flex: 1;
|
||
color: rgba(0, 0, 0, 0.85);
|
||
font-weight: 500;
|
||
}
|
||
|
||
.no-admin-info {
|
||
padding: 16px 0;
|
||
}
|
||
|
||
/* 表格中服务商信息显示样式 */
|
||
.admin-info-table {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 4px;
|
||
font-size: 12px;
|
||
padding: 4px 0;
|
||
}
|
||
|
||
.admin-info-row {
|
||
line-height: 1.5;
|
||
}
|
||
|
||
.admin-name {
|
||
font-weight: 500;
|
||
color: rgba(0, 0, 0, 0.85);
|
||
}
|
||
|
||
.admin-phone {
|
||
color: rgba(0, 0, 0, 0.65);
|
||
}
|
||
</style> |