crm 场地信息

pull/853/head
wersd 2025-06-02 18:12:50 +08:00
parent d7aba16e37
commit c9d68e6a1c
14 changed files with 688 additions and 96 deletions

View File

@ -4,10 +4,10 @@ NODE_ENV=production
VITE_DEV=false
# 请求路径
VITE_BASE_URL='http://localhost:48080'
VITE_BASE_URL='http://www.woyaoshouchong.asia:48080'
# 文件上传类型server - 后端上传, client - 前端直连上传仅支持S3服务
VITE_UPLOAD_TYPE=server
VITE_UPLOAD_TYPE=client
# 接口地址
VITE_API_URL=/admin-api

View File

@ -0,0 +1,59 @@
import request from '@/config/axios'
// 场地信息 VO
export interface StationSiteVO {
id: number // 主键ID
name: string // 场地名称
areaId: number // 地区
areaName?: string // 地区
detailAddress?: string // 地址
locationLng: number // 定位经度
locationLat: number // 定位纬度
estimatedPiles: number // 可建充电桩数
siteType: number // 场地类型
siteStatus: number // 场地状态
ownerId: number // 关联的业主方
managementId: number // 关联的物管方
recommenderName: string // 推荐人姓名
recommenderContact: string // 推荐人联系方式
picUrls?: string // 图片
fileUrls?: string // 附件
parkingSpaces: number // 车位数
rentPrice: number // 租金价格
creator: string // 填报人
creatorName?: string // 填报人名称
params: string // 参数
}
// 场地信息 API
export const StationSiteApi = {
// 查询场地信息分页
getStationSitePage: async (params: any) => {
return await request.get({ url: `/crm/station-site/page`, params })
},
// 查询场地信息详情
getStationSite: async (id: number) => {
return await request.get({ url: `/crm/station-site/get?id=` + id })
},
// 新增场地信息
createStationSite: async (data: StationSiteVO) => {
return await request.post({ url: `/crm/station-site/create`, data })
},
// 修改场地信息
updateStationSite: async (data: StationSiteVO) => {
return await request.put({ url: `/crm/station-site/update`, data })
},
// 删除场地信息
deleteStationSite: async (id: number) => {
return await request.delete({ url: `/crm/station-site/delete?id=` + id })
},
// 导出场地信息 Excel
exportStationSite: async (params) => {
return await request.download({ url: `/crm/station-site/export-excel`, params })
},
}

View File

@ -212,6 +212,8 @@ export enum DICT_TYPE {
CRM_PERMISSION_LEVEL = 'crm_permission_level', // CRM 数据权限的级别
CRM_PRODUCT_UNIT = 'crm_product_unit', // CRM 产品单位
CRM_FOLLOW_UP_TYPE = 'crm_follow_up_type', // CRM 跟进方式
CRM_STATION_SITE_STATUS = 'crm_station_site_status', // CRM 场地状态
CRM_STATION_SITE_TYPE = 'crm_station_site_type', // CRM 场地类型
// ========== ERP - 企业资源计划模块 ==========
ERP_AUDIT_STATUS = 'erp_audit_status', // ERP 审批状态

View File

@ -48,6 +48,12 @@
<dict-tag :type="DICT_TYPE.INFRA_BOOLEAN_STRING" :value="scope.row.master" />
</template>
</el-table-column>
<el-table-column align="center" label="操作" fixed="right" min-width="120">
<template #default="scope">
<el-button link type="primary" @click="openFormEdit(scope.row.id)"></el-button>
<el-button link type="danger" @click="handleDelete(scope.row.id)"></el-button>
</template>
</el-table-column>
</el-table>
<!-- 分页 -->
<Pagination
@ -174,6 +180,21 @@ const deleteContactBusinessList = async () => {
handleQuery()
}
/** 编辑操作 */
const openFormEdit = (id: number) => {
formRef.value.open('update', id, props.customerId, props.businessId)
}
/** 删除操作 */
const handleDelete = async (id: number) => {
try {
await message.delConfirm()
await ContactApi.deleteContact(id)
message.success('删除成功')
getList()
} catch {}
}
/** 监听打开的 bizId + bizType从而加载最新的列表 */
watch(
() => [props.bizId, props.bizType],

View File

@ -15,19 +15,32 @@
</div>
</div>
<ContentWrap class="mt-10px">
<el-descriptions :column="5" direction="vertical">
<el-descriptions-item label="客户名称">{{ contact.customerName }}</el-descriptions-item>
<el-descriptions-item label="职务">{{ contact.post }}</el-descriptions-item>
<el-descriptions-item label="手机">{{ contact.mobile }}</el-descriptions-item>
<el-descriptions-item label="创建时间">
{{ formatDate(contact.createTime) }}
<el-descriptions :column="4" direction="horizontal" class="mb-10px">
<el-descriptions-item label="客户名称:">{{ contact.customerName }}</el-descriptions-item>
<el-descriptions-item label="职务:">{{ contact.post }}</el-descriptions-item>
<el-descriptions-item label="手机:">{{ contact.mobile }}</el-descriptions-item>
<el-descriptions-item label="电话:">{{ contact.telephone }}</el-descriptions-item>
<el-descriptions-item label="邮箱:">{{ contact.email }}</el-descriptions-item>
<el-descriptions-item label="QQ:">{{ contact.qq }}</el-descriptions-item>
<el-descriptions-item label="微信:">{{ contact.wechat }}</el-descriptions-item>
<el-descriptions-item label="地址:">
{{ contact.areaName }} {{ contact.detailAddress }}
</el-descriptions-item>
<el-descriptions-item label="职务:">{{ contact.post }}</el-descriptions-item>
<el-descriptions-item label="主要联系人:">
<dict-tag :type="DICT_TYPE.INFRA_BOOLEAN_STRING" :value="contact.master" />
</el-descriptions-item>
<el-descriptions-item label="性别:">
<dict-tag :type="DICT_TYPE.SYSTEM_USER_SEX" :value="contact.sex" />
</el-descriptions-item>
<el-descriptions-item label="备注:">{{ contact.remark }}</el-descriptions-item>
</el-descriptions>
</ContentWrap>
</template>
<script lang="ts" setup>
import * as ContactApi from '@/api/crm/contact'
import { formatDate } from '@/utils/formatTime'
import { DICT_TYPE } from '@/utils/dict'
const { contact } = defineProps<{ contact: ContactApi.ContactVO }>()
</script>

View File

@ -6,28 +6,25 @@
<span class="text-base font-bold">基本信息</span>
</template>
<el-descriptions :column="4">
<el-descriptions-item label="姓名">{{ contact.name }}</el-descriptions-item>
<el-descriptions-item label="客户名称">{{ contact.customerName }}</el-descriptions-item>
<el-descriptions-item label="手机">{{ contact.mobile }}</el-descriptions-item>
<el-descriptions-item label="电话">{{ contact.telephone }}</el-descriptions-item>
<el-descriptions-item label="邮箱">{{ contact.email }}</el-descriptions-item>
<el-descriptions-item label="QQ">{{ contact.qq }}</el-descriptions-item>
<el-descriptions-item label="微信">{{ contact.wechat }}</el-descriptions-item>
<el-descriptions-item label="地址">
<el-descriptions-item label="姓名:">{{ contact.name }}</el-descriptions-item>
<el-descriptions-item label="客户名称:">{{ contact.customerName }}</el-descriptions-item>
<el-descriptions-item label="手机:">{{ contact.mobile }}</el-descriptions-item>
<el-descriptions-item label="电话:">{{ contact.telephone }}</el-descriptions-item>
<el-descriptions-item label="邮箱:">{{ contact.email }}</el-descriptions-item>
<el-descriptions-item label="QQ:">{{ contact.qq }}</el-descriptions-item>
<el-descriptions-item label="微信:">{{ contact.wechat }}</el-descriptions-item>
<el-descriptions-item label="地址:">
{{ contact.areaName }} {{ contact.detailAddress }}
</el-descriptions-item>
<el-descriptions-item label="职务">{{ contact.post }}</el-descriptions-item>
<el-descriptions-item label="直属上级">{{ contact.parentName }}</el-descriptions-item>
<el-descriptions-item label="关键决策人">
<el-descriptions-item label="职务:">{{ contact.post }}</el-descriptions-item>
<el-descriptions-item label="直属上级:">{{ contact.parentName }}</el-descriptions-item>
<el-descriptions-item label="主要联系人:">
<dict-tag :type="DICT_TYPE.INFRA_BOOLEAN_STRING" :value="contact.master" />
</el-descriptions-item>
<el-descriptions-item label="性别">
<el-descriptions-item label="性别:">
<dict-tag :type="DICT_TYPE.SYSTEM_USER_SEX" :value="contact.sex" />
</el-descriptions-item>
<el-descriptions-item label="下次联系时间">
{{ formatDate(contact.contactNextTime) }}
</el-descriptions-item>
<el-descriptions-item label="备注">{{ contact.remark }}</el-descriptions-item>
<el-descriptions-item label="备注:">{{ contact.remark }}</el-descriptions-item>
</el-descriptions>
</el-collapse-item>
<el-collapse-item name="systemInfo">

View File

@ -9,12 +9,12 @@
</ContactDetailsHeader>
<el-col>
<el-tabs>
<el-tab-pane label="跟进记录">
<!-- <el-tab-pane label="跟进记录">
<FollowUpList :biz-id="contactId" :biz-type="BizTypeEnum.CRM_CONTACT" />
</el-tab-pane>
<el-tab-pane label="详细资料">
</el-tab-pane> -->
<!-- <el-tab-pane label="详细资料">
<ContactDetailsInfo :contact="contact" />
</el-tab-pane>
</el-tab-pane> -->
<el-tab-pane label="操作日志">
<OperateLogV2 :log-list="logList" />
</el-tab-pane>

View File

@ -13,14 +13,14 @@
:on-exceed="handleExceed"
:on-success="submitFormSuccess"
:http-request="httpRequest"
accept=".jpg, .png, .gif, .txt, .doc, .docx, .xls"
accept=".jpg, .png, .gif, .pdf, .txt, .doc, .docx, .xls"
drag
>
<i class="el-icon-upload"></i>
<div class="el-upload__text">将文件拖到此处 <em>点击上传</em></div>
<template #tip>
<div class="el-upload__tip" style="color: red">
提示仅允许导入 jpgpnggiftxtdocdocxxls格式文件
提示仅允许导入 jpgpnggifpdftxtdocdocxxls格式文件
</div>
</template>
</el-upload>

View File

@ -5,7 +5,7 @@
<!-- 左上客户基本信息 -->
<el-col>
<el-row>
<span class="text-xl font-bold">{{ customer.name }}</span>
<span class="text-md font-bold">{{ customer.name }}</span>
</el-row>
</el-col>
</div>
@ -16,27 +16,24 @@
</div>
</div>
<ContentWrap class="mt-10px">
<el-descriptions :column="5" direction="vertical">
<el-descriptions-item label="成交状态">
{{ customer.dealStatus ? '已成交' : '未成交' }}
<el-descriptions :column="4" direction="horizontal" class="mb-10px">
<el-descriptions-item label="成交状态:">
<dict-tag :type="DICT_TYPE.CRM_CUSTOMER_DEAL_STATUS" :value="customer.dealStatus" />
</el-descriptions-item>
<el-descriptions-item label="负责人">{{ customer.ownerUserName }}</el-descriptions-item>
<el-descriptions-item label="创建时间">
<el-descriptions-item label="负责人:">{{ customer.ownerUserName }}</el-descriptions-item>
<el-descriptions-item label="创建时间:">
{{ formatDate(customer.createTime) }}
</el-descriptions-item>
<el-descriptions-item label="客户名称">
{{ customer.name }}
</el-descriptions-item>
<el-descriptions-item label="地址">
<el-descriptions-item label="地址:">
{{ customer.areaName }} {{ customer.detailAddress }}
</el-descriptions-item>
<el-descriptions-item label="客户类别">
<el-descriptions-item label="客户类别:">
<dict-tag :type="DICT_TYPE.CRM_CUSTOMER_INDUSTRY" :value="customer.industryId" />
</el-descriptions-item>
<el-descriptions-item label="下次联系时间">
{{ formatDate(customer.contactNextTime) }}
<el-descriptions-item label="下次联系时间:">
{{ formatDate(customer.contactNextTime, 'YYYY-MM-DD') }}
</el-descriptions-item>
<el-descriptions-item label="备注">{{ customer.remark }}</el-descriptions-item>
<el-descriptions-item label="备注:">{{ customer.remark }}</el-descriptions-item>
</el-descriptions>
</ContentWrap>
</template>

View File

@ -36,9 +36,9 @@
<el-tab-pane label="跟进记录">
<FollowUpList :biz-id="customerId" :biz-type="BizTypeEnum.CRM_CUSTOMER" />
</el-tab-pane>
<el-tab-pane label="基本信息">
<!-- <el-tab-pane label="基本信息">
<CustomerDetailsInfo :customer="customer" />
</el-tab-pane>
</el-tab-pane> -->
<el-tab-pane label="联系人" lazy>
<ContactList :biz-id="customer.id!" :biz-type="BizTypeEnum.CRM_CUSTOMER" :customer-id="customerId"/>
</el-tab-pane>
@ -54,12 +54,13 @@
<el-tab-pane label="合同" lazy>
<ContractList :biz-id="customer.id!" :biz-type="BizTypeEnum.CRM_CUSTOMER" />
</el-tab-pane>
<el-tab-pane label="操作日志">
<OperateLogV2 :log-list="logList" />
</el-tab-pane>
<el-tab-pane label="附件">
<FileList :customerId="customerId" />
</el-tab-pane>
<el-tab-pane label="操作日志">
<OperateLogV2 :log-list="logList" />
</el-tab-pane>
</el-tabs>
</el-col>

View File

@ -11,16 +11,27 @@
<el-form-item label="客户名称" prop="name">
<el-input
v-model="queryParams.name"
class="!w-240px"
class="!w-200px"
clearable
placeholder="请输入客户名称"
@keyup.enter="handleQuery"
/>
<el-form-item label="地区" prop="areaId">
<el-cascader
v-model="queryParams.areaId"
:options="areaList"
:props="defaultProps"
class="!w-200px"
clearable
filterable
placeholder="请选择地区"
/>
</el-form-item>
</el-form-item>
<el-form-item label="客户类别" prop="industryId">
<el-select
v-model="queryParams.industryId"
class="!w-240px"
class="!w-200px"
clearable
placeholder="请选择客户类别"
>
@ -32,21 +43,10 @@
/>
</el-select>
</el-form-item>
<el-form-item label="地区" prop="areaId">
<el-cascader
v-model="queryParams.areaId"
:options="areaList"
:props="defaultProps"
class="!w-240px"
clearable
filterable
placeholder="请选择地区"
/>
</el-form-item>
<el-form-item label="成交状态" prop="dealStatus">
<el-select
v-model="queryParams.dealStatus"
class="!w-240px"
class="!w-200px"
clearable
placeholder="请选择成交状态"
>
@ -101,38 +101,33 @@
:show-overflow-tooltip="true"
:stripe="true"
>
<el-table-column align="center" fixed="left" label="地区" prop="areaId" width="200px" >
<template #default="scope">
<span>{{ scope.row.areaName || '暂无' }}</span>
</template>
</el-table-column>
<el-table-column align="center" label="客户名称" prop="name" width="400">
<el-table-column align="center" fixed="left" label="客户名称" prop="name" width="350px">
<template #default="scope">
<el-link :underline="false" type="primary" @click="openDetail(scope.row.id)">
{{ scope.row.name }}
</el-link>
</template>
</el-table-column>
<el-table-column align="center" label="主要联系人" prop="primaryContactName" width="150">
<el-table-column align="center" label="地区" prop="areaId" width="200px" >
<template #default="scope">
<el-link
:underline="false"
:type="scope.row.primaryContactName ? 'primary' : 'danger'"
@click="scopeRowIdForCustomerDetail = scope.row.id; openPrimaryContactDetail(scope.row.primaryContactId)"
>
{{ scope.row.primaryContactName || '暂无' }}
</el-link>
<span>{{ scope.row.areaName || '暂无' }}</span>
</template>
</el-table-column>
<el-table-column align="center" label="主要联系人" prop="primaryContactName" width="150px">
<template #default="scope">
<span v-if="scope.row.primaryContactName">{{ scope.row.primaryContactName }}</span>
<span v-else style="color:#f56c6c;">暂无</span>
</template>
</el-table-column>
<el-table-column align="center" label="客户类别" prop="industryId" width="150">
<el-table-column align="center" label="客户类别" prop="industryId" width="150px">
<template #default="scope">
<dict-tag :type="DICT_TYPE.CRM_CUSTOMER_INDUSTRY" :value="scope.row.industryId" />
</template>
</el-table-column>
<el-table-column align="center" label="成交状态" prop="dealStatus" width="100px">
<el-table-column align="center" label="成交状态" prop="dealStatus" width="150px">
<template #default="scope">
<dict-tag :type="DICT_TYPE.CRM_CUSTOMER_DEAL_STATUS" :value="scope.row.dealStatus" />
</template>
@ -146,13 +141,13 @@
width="180px"
>
<template #default="scope">
<span :style="scope.row.contactNextTime && Number(scope.row.contactNextTime) < Date.now() ? 'color: #f56c6c; font-weight: bold;' : ''">
<span :style="scope.row.contactNextTime && Number(scope.row.contactNextTime) < Date.now() ? 'color: #f56c6c;' : ''">
{{ dateFormatter2(scope.row, scope.column, scope.row.contactNextTime) }}
</span>
</template>
</el-table-column>
<el-table-column align="center" label="责任人" prop="ownerUserName" width="100px" />
<el-table-column align="center" label="责任人" prop="ownerUserName" width="150px" />
<el-table-column align="center" fixed="right" label="操作" min-width="150">
<template #default="scope">

View File

@ -21,24 +21,25 @@
</template>
<div class="el-timeline-right-content">
<div class="followup-meta mb-5px">
<span class="meta-label">跟进人</span><el-tag class="mr-10px" type="success">{{ item.creatorName }}</el-tag>
<template v-if="item.contacts && item.contacts.length">
<span class="meta-label">联系人</span>
<el-link
v-for="contact in item.contacts"
:key="contact.id"
:underline="false"
type="primary"
@click="openContactDetail(contact.id)"
class="ml-5px"
>
{{ contact.name }}
</el-link>
<span style="margin: 0 8px;"> </span>
</template>
<span class="meta-label">跟进方式</span><dict-tag :type="DICT_TYPE.CRM_FOLLOW_UP_TYPE" :value="item.type" class="mr-10px" />
</div>
<span class="follow-row" v-if="!/<[a-z][\s\S]*>/i.test(item.content)">{{ item.content }}</span>
<div class="follow-row" v-else v-html="'跟进内容:' + item.content"></div>
<!-- <span v-if="bizType === BizTypeEnum.CRM_CUSTOMER && item.contacts && item.contacts.length" class="ml-10px">
关联联系人
<el-link
v-for="contact in item.contacts"
:key="`key-${contact.id}`"
:underline="false"
type="primary"
@click="openContactDetail(contact.id)"
class="ml-5px"
>
{{ contact.name }}
</el-link>
</span> -->
<!-- 图片直接展示 -->
<div v-if="item.picUrls && item.picUrls.length" class="followup-img-list follow-row mt-10px">
<el-image
@ -64,6 +65,8 @@
</el-link>
</div>
</div>
<span>跟进人</span>{{ item.creatorName }}
<br />
<el-button link type="danger" class="mr-20px followup-delete-btn" @click="handleDelete(item.id)">
<Icon icon="ep:delete" class="mr-3px" /> 删除
</el-button>

View File

@ -0,0 +1,282 @@
<template>
<Dialog :title="dialogTitle" v-model="dialogVisible">
<el-form
ref="formRef"
:model="formData"
:rules="formRules"
label-width="130px"
v-loading="formLoading"
>
<el-row>
<el-col :span="12">
<el-form-item label="场地名称" prop="name">
<el-input v-model="formData.name" placeholder="请输入场地名称" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="场地状态" prop="siteStatus">
<el-select v-model="formData.siteStatus" placeholder="请选择场地状态" class="w-1/1">
<el-option
v-for="dict in getIntDictOptions(DICT_TYPE.CRM_STATION_SITE_STATUS)"
:key="dict.value"
:label="dict.label"
:value="dict.value"
/>
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="场地类型" prop="type">
<el-select v-model="formData.siteType" placeholder="请选择场地类型" class="w-1/1">
<el-option
v-for="dict in getIntDictOptions(DICT_TYPE.CRM_STATION_SITE_TYPE)"
:key="dict.value"
:label="dict.label"
:value="dict.value"
/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="10">
<el-form-item label="可建充电桩数" prop="estimatedPiles" >
<el-input-number v-model="formData.estimatedPiles" :min="0" :max="255" :step="1"/>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="地区" prop="areaId">
<el-cascader
v-model="formData.areaId"
:options="areaList"
:props="defaultProps"
class="w-1/1"
clearable
filterable
placeholder="请选择地区"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="详细地址" prop="detailAddress">
<el-input v-model="formData.detailAddress" placeholder="请输入详细地址" />
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="停车位数" prop="parkingSpaces">
<el-input-number v-model="formData.parkingSpaces" :min="0" :max="255" :step="1" placeholder="0" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="租金或分成" prop="rentPrice">
<el-input v-model="formData.rentPrice" placeholder="请输入租金或分成" />
</el-form-item>
</el-col>
</el-row>
<el-form-item label="定位经度" prop="locationLng">
<el-input v-model="formData.locationLng" placeholder="请输入定位经度" />
</el-form-item>
<el-form-item label="定位纬度" prop="locationLat">
<el-input v-model="formData.locationLat" placeholder="请输入定位纬度" />
</el-form-item>
<el-row>
<el-col :span="12">
<el-form-item label="关联的业主方" prop="ownerId">
<el-input v-model="formData.ownerId" placeholder="请输入关联的业主方" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="关联的物管方" prop="managementId">
<el-input v-model="formData.managementId" placeholder="请输入关联的物管方" />
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="推荐人姓名" prop="recommenderName">
<el-input v-model="formData.recommenderName" placeholder="请输入推荐人姓名" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="推荐人联系方式" prop="recommenderContact">
<el-input v-model="formData.recommenderContact" placeholder="请输入推荐人联系方式" />
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="24">
<el-form-item label="交通情况" prop="params.traffic">
<el-input v-model="formData.params.traffic" type="textarea" placeholder="请输入交通情况" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="电力距离" prop="params.powerDistance">
<el-input v-model="formData.params.powerDistance" placeholder="请输入电力距离" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="道闸情况" prop="params.barrierGate">
<el-input v-model="formData.params.barrierGate" placeholder="请输入道闸情况" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="周边竞品" prop="params.competitor">
<el-input v-model="formData.params.competitor" placeholder="请输入周边竞品" />
</el-form-item>
</el-col>
</el-row>
<el-form-item label="附加图片" prop="picUrls">
<UploadImgs v-model="formData.picUrls" />
</el-form-item>
<el-form-item label="附件" prop="fileUrls">
<UploadFile v-model="formData.fileUrls" />
</el-form-item>
</el-form>
<template #footer>
<el-button @click="submitForm" type="primary" :disabled="formLoading"> </el-button>
<el-button @click="dialogVisible = false"> </el-button>
</template>
</Dialog>
</template>
<script setup lang="ts">
import { getIntDictOptions, DICT_TYPE } from '@/utils/dict'
import { StationSiteApi, StationSiteVO } from '@/api/crm/stationsite'
import { defaultProps } from '@/utils/tree'
import * as AreaApi from '@/api/system/area'
import { ro } from 'element-plus/es/locale'
/** 场地信息 表单 */
defineOptions({ name: 'StationSiteForm' })
const { t } = useI18n() //
const message = useMessage() //
const dialogVisible = ref(false) //
const dialogTitle = ref('') //
const formLoading = ref(false) // 12
const formType = ref('') // create - update -
const formData = ref({
id: undefined,
name: undefined,
areaId: undefined,
detailAddress: undefined,
locationLng: undefined,
locationLat: undefined,
estimatedPiles: 0,
siteStatus: undefined,
siteType: undefined,
ownerId: undefined,
managementId: undefined,
recommenderName: undefined,
recommenderContact: undefined,
picUrls: undefined,
fileUrls: undefined,
parkingSpaces: 0,
rentPrice: '',
params: {
traffic: '',
powerDistance: '',
barrierGate: '',
competitor: ''
},
})
const areaList = ref([]) //
const formRules = reactive({
name: [{ required: true, message: '场地名称不能为空', trigger: 'blur' }],
areaId: [{ required: true, message: '地区不能为空', trigger: 'blur' }],
locationLng: [{ required: true, message: '定位经度不能为空', trigger: 'blur' }],
locationLat: [{ required: true, message: '定位纬度不能为空', trigger: 'blur' }],
estimatedPiles: [{ required: true, message: '可建充电桩数不能为空', trigger: 'blur' }],
siteStatus: [{ required: true, message: '场地状态不能为空', trigger: 'blur' }],
recommenderName: [{ required: true, message: '推荐人姓名不能为空', trigger: 'blur' }],
recommenderContact: [{ required: true, message: '推荐人联系方式不能为空', trigger: 'blur' }],
})
const formRef = ref() // Ref
/** 打开弹窗 */
const open = async (type: string, id?: number) => {
dialogVisible.value = true
dialogTitle.value = t('action.' + type)
formType.value = type
resetForm()
//
if (id) {
formLoading.value = true
try {
formData.value = await StationSiteApi.getStationSite(id)
} finally {
formLoading.value = false
}
}
}
defineExpose({ open }) // open
/** 提交表单 */
const emit = defineEmits(['success']) // success
const submitForm = async () => {
//
await formRef.value.validate()
//
formLoading.value = true
try {
const data = {
...formData.value,
params: JSON.stringify(formData.value.params)
} as unknown as StationSiteVO
if (formType.value === 'create') {
await StationSiteApi.createStationSite(data)
message.success(t('common.createSuccess'))
} else {
await StationSiteApi.updateStationSite(data)
message.success(t('common.updateSuccess'))
}
dialogVisible.value = false
//
emit('success')
} finally {
formLoading.value = false
}
}
/** 重置表单 */
const resetForm = () => {
formData.value = {
id: undefined,
name: undefined,
areaId: undefined,
detailAddress: undefined,
locationLng: undefined,
locationLat: undefined,
estimatedPiles: 0,
siteStatus: undefined,
type: undefined,
ownerId: undefined,
managementId: undefined,
recommenderName: undefined,
recommenderContact: undefined,
planPicUrls: undefined,
picUrls: undefined,
fileUrls: undefined,
parkingSpaces: 0,
rentPrice: 0,
params: {
traffic: '',
powerDistance: '',
barrierGate: '',
competitor: ''
}
}
formRef.value?.resetFields()
}
/** 初始化 **/
onMounted(() => {
AreaApi.getAreaTree().then(res => {
areaList.value = res
})
})
</script>

View File

@ -0,0 +1,222 @@
<template>
<ContentWrap>
<!-- 搜索工作栏 -->
<el-form
class="-mb-15px"
:model="queryParams"
ref="queryFormRef"
:inline="true"
label-width="68px"
>
<el-form-item label="场地名称" prop="name">
<el-input
v-model="queryParams.name"
placeholder="请输入场地名称"
clearable
@keyup.enter="handleQuery"
class="!w-240px"
/>
</el-form-item>
<el-form-item label="地区" prop="areaId">
<el-cascader
v-model="queryParams.areaId"
:options="areaList"
:props="defaultProps"
class="!w-200px"
clearable
filterable
placeholder="请选择地区"
/>
</el-form-item>
<el-form-item label="场地状态" prop="siteStatus">
<el-select
v-model="queryParams.siteStatus"
placeholder="请选择场地状态"
clearable
class="!w-240px"
>
<el-option
v-for="dict in getIntDictOptions(DICT_TYPE.CRM_STATION_SITE_STATUS)"
:key="dict.value"
:label="dict.label"
:value="dict.value"
/>
</el-select>
</el-form-item>
<el-form-item>
<el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 搜索</el-button>
<el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 重置</el-button>
<el-button
type="primary"
plain
@click="openForm('create')"
v-hasPermi="['crm:station-site:create']"
>
<Icon icon="ep:plus" class="mr-5px" /> 新增
</el-button>
<el-button
type="success"
plain
@click="handleExport"
:loading="exportLoading"
v-hasPermi="['crm:station-site:export']"
>
<Icon icon="ep:download" class="mr-5px" /> 导出
</el-button>
</el-form-item>
</el-form>
</ContentWrap>
<!-- 列表 -->
<ContentWrap>
<el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true">
<el-table-column label="场地名称" fixed="left" align="center" prop="name" />
<el-table-column align="center" label="地区" prop="areaId" width="200px" >
<template #default="scope">
<span>{{ scope.row.areaName || '暂无' }} {{ scope.row.detailAddress }}</span>
</template>
</el-table-column>
<el-table-column label="定位经度" align="center" prop="locationLng" />
<el-table-column label="定位纬度" align="center" prop="locationLat" />
<el-table-column label="可建充电桩数" align="center" prop="estimatedPiles" />
<el-table-column label="场地状态" align="center" prop="siteStatus">
<template #default="scope">
<dict-tag :type="DICT_TYPE.CRM_STATION_SITE_STATUS" :value="scope.row.siteStatus" />
</template>
</el-table-column>
<el-table-column label="场地类型" align="center" prop="siteType">
<template #default="scope">
<dict-tag :type="DICT_TYPE.CRM_STATION_SITE_TYPE" :value="scope.row.siteType" />
</template>
</el-table-column>
<el-table-column label="填报人" align="center" prop="creatorName" />
<el-table-column label="操作" fixed="right" align="center" min-width="120px">
<template #default="scope">
<el-button
link
type="primary"
@click="openForm('update', scope.row.id)"
v-hasPermi="['crm:station-site:update']"
>
编辑
</el-button>
<el-button
link
type="danger"
@click="handleDelete(scope.row.id)"
v-hasPermi="['crm:station-site:delete']"
>
删除
</el-button>
</template>
</el-table-column>
</el-table>
<!-- 分页 -->
<Pagination
:total="total"
v-model:page="queryParams.pageNo"
v-model:limit="queryParams.pageSize"
@pagination="getList"
/>
</ContentWrap>
<!-- 表单弹窗添加/修改 -->
<StationSiteForm ref="formRef" @success="getList" />
</template>
<script setup lang="ts">
import { getIntDictOptions, DICT_TYPE } from '@/utils/dict'
import { dateFormatter } from '@/utils/formatTime'
import download from '@/utils/download'
import { StationSiteApi, StationSiteVO } from '@/api/crm/stationsite'
import StationSiteForm from './StationSiteForm.vue'
import * as AreaApi from '@/api/system/area'
import { defaultProps } from '@/utils/tree'
/** 场地信息 列表 */
defineOptions({ name: 'CrmStationSite' })
const message = useMessage() //
const { t } = useI18n() //
const loading = ref(true) //
const list = ref<StationSiteVO[]>([]) //
const total = ref(0) //
const queryParams = reactive({
pageNo: 1,
pageSize: 10,
name: undefined,
areaId: undefined,
siteStatus: undefined,
createTime: [],
})
const queryFormRef = ref() //
const exportLoading = ref(false) //
const areaList = ref([])
/** 查询列表 */
const getList = async () => {
loading.value = true
try {
const data = await StationSiteApi.getStationSitePage(queryParams)
list.value = data.list
total.value = data.total
} finally {
loading.value = false
}
}
/** 搜索按钮操作 */
const handleQuery = () => {
queryParams.pageNo = 1
getList()
}
/** 重置按钮操作 */
const resetQuery = () => {
queryFormRef.value.resetFields()
handleQuery()
}
/** 添加/修改操作 */
const formRef = ref()
const openForm = (type: string, id?: number) => {
formRef.value.open(type, id)
}
/** 删除按钮操作 */
const handleDelete = async (id: number) => {
try {
//
await message.delConfirm()
//
await StationSiteApi.deleteStationSite(id)
message.success(t('common.delSuccess'))
//
await getList()
} catch {}
}
/** 导出按钮操作 */
const handleExport = async () => {
try {
//
await message.exportConfirm()
//
exportLoading.value = true
const data = await StationSiteApi.exportStationSite(queryParams)
download.excel(data, '场地信息.xls')
} catch {
} finally {
exportLoading.value = false
}
}
/** 初始化 **/
onMounted(() => {
getList()
AreaApi.getAreaTree().then(res => {
areaList.value = res
})
})
</script>