2025-11-07 09:40:39 +08:00
|
|
|
|
<template>
|
|
|
|
|
|
<view class="customer-management">
|
|
|
|
|
|
<!-- 顶部标题栏 -->
|
|
|
|
|
|
<view class="header">
|
2025-11-21 15:11:26 +08:00
|
|
|
|
<text class="header-title">搜索</text>
|
2025-11-12 17:09:46 +08:00
|
|
|
|
<view v-if="showPrivateSwitch" style="display: flex;align-items: center;gap: 6px">
|
2025-11-12 11:12:02 +08:00
|
|
|
|
<view>私有</view><uv-switch v-model="filterSelf"></uv-switch>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
|
2025-11-07 09:40:39 +08:00
|
|
|
|
<view class="filter-btn" @click="showFilter = !showFilter">
|
|
|
|
|
|
<text class="filter-text">筛选</text>
|
|
|
|
|
|
<text class="filter-icon" :class="{ 'rotate': showFilter }">▼</text>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 筛选区域(可选) -->
|
|
|
|
|
|
<view class="filter-panel" v-if="showFilter">
|
|
|
|
|
|
<view class="filter-item">
|
|
|
|
|
|
<text class="filter-label">状态:</text>
|
|
|
|
|
|
<view class="filter-options">
|
|
|
|
|
|
<text
|
|
|
|
|
|
class="filter-option"
|
2025-11-20 17:54:49 +08:00
|
|
|
|
:class="{ 'active': isAllSelected }"
|
|
|
|
|
|
@click="handleSelectAll"
|
2025-11-07 09:40:39 +08:00
|
|
|
|
>全部</text>
|
|
|
|
|
|
<text
|
|
|
|
|
|
class="filter-option"
|
2025-11-20 17:54:49 +08:00
|
|
|
|
:class="{ 'active': isFilterSelected('potential') }"
|
|
|
|
|
|
@click="toggleFilter('potential')"
|
2025-11-10 14:31:32 +08:00
|
|
|
|
>潜在</text>
|
2025-11-07 09:40:39 +08:00
|
|
|
|
<text
|
|
|
|
|
|
class="filter-option"
|
2025-11-20 17:54:49 +08:00
|
|
|
|
:class="{ 'active': isFilterSelected('intent') }"
|
|
|
|
|
|
@click="toggleFilter('intent')"
|
2025-11-10 14:31:32 +08:00
|
|
|
|
>意向</text>
|
|
|
|
|
|
<text
|
|
|
|
|
|
class="filter-option"
|
2025-11-20 17:54:49 +08:00
|
|
|
|
:class="{ 'active': isFilterSelected('deal') }"
|
|
|
|
|
|
@click="toggleFilter('deal')"
|
2025-11-10 14:31:32 +08:00
|
|
|
|
>成交</text>
|
|
|
|
|
|
<text
|
|
|
|
|
|
class="filter-option"
|
2025-11-20 17:54:49 +08:00
|
|
|
|
:class="{ 'active': isFilterSelected('invalid') }"
|
|
|
|
|
|
@click="toggleFilter('invalid')"
|
2025-11-10 14:31:32 +08:00
|
|
|
|
>失效</text>
|
2025-11-20 17:54:49 +08:00
|
|
|
|
<text
|
|
|
|
|
|
class="filter-option"
|
|
|
|
|
|
:class="{ 'active': isFilterSelected(TODAY_FOLLOW_FILTER) }"
|
|
|
|
|
|
@click="toggleFilter(TODAY_FOLLOW_FILTER)"
|
|
|
|
|
|
>今日跟进</text>
|
2025-11-07 09:40:39 +08:00
|
|
|
|
</view>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 客户列表 -->
|
2025-11-08 13:36:04 +08:00
|
|
|
|
<view
|
2025-11-07 17:41:03 +08:00
|
|
|
|
class="customer-list"
|
|
|
|
|
|
:class="{ 'with-filter': showFilter }"
|
|
|
|
|
|
>
|
|
|
|
|
|
<view style="padding-inline: 8px">
|
2025-11-07 09:40:39 +08:00
|
|
|
|
<view
|
|
|
|
|
|
class="customer-card"
|
2025-11-08 13:36:04 +08:00
|
|
|
|
v-for="customer in list"
|
2025-11-07 09:40:39 +08:00
|
|
|
|
:key="customer.id"
|
|
|
|
|
|
@click="handleCustomerClick(customer)"
|
|
|
|
|
|
>
|
2025-11-11 17:53:16 +08:00
|
|
|
|
<CustomerSummaryBrief
|
|
|
|
|
|
:name="customer.name"
|
|
|
|
|
|
:intents="customer.intents"
|
2025-11-12 11:44:29 +08:00
|
|
|
|
|
2025-11-11 17:53:16 +08:00
|
|
|
|
:status="customer.status"
|
|
|
|
|
|
:show-edit="true"
|
|
|
|
|
|
@edit="handleEdit(customer)"
|
|
|
|
|
|
/>
|
2025-11-11 11:01:50 +08:00
|
|
|
|
|
2025-11-11 14:04:09 +08:00
|
|
|
|
<!-- 客户详细信息区域 -->
|
|
|
|
|
|
<view class="customer-details">
|
2025-11-11 16:05:16 +08:00
|
|
|
|
<!-- 备注 -->
|
2025-11-12 11:44:29 +08:00
|
|
|
|
<view class="detail-row" v-if="customer.remark">
|
2025-11-11 16:05:16 +08:00
|
|
|
|
<text class="detail-label">备注:</text>
|
|
|
|
|
|
<text class="detail-value">{{ customer.remark || '--' }}</text>
|
|
|
|
|
|
</view>
|
2025-11-11 11:01:50 +08:00
|
|
|
|
<!-- 微信号 -->
|
2025-11-12 11:44:29 +08:00
|
|
|
|
<!-- <view class="detail-row">-->
|
|
|
|
|
|
<!-- <text class="detail-label">微信号:</text>-->
|
|
|
|
|
|
<!-- <text class="detail-value">{{ customer.wechat || '--' }}</text>-->
|
|
|
|
|
|
<!-- </view>-->
|
2025-11-11 11:01:50 +08:00
|
|
|
|
|
|
|
|
|
|
<!-- 手机号 -->
|
2025-11-12 11:44:29 +08:00
|
|
|
|
<view class="detail-row" v-if="customer.mobile">
|
2025-11-11 11:01:50 +08:00
|
|
|
|
<text class="detail-label">手机号:</text>
|
|
|
|
|
|
<text class="detail-value">{{ customer.mobile || '--' }}</text>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
|
2025-11-11 14:04:09 +08:00
|
|
|
|
<!-- 跟进内容 -->
|
2025-11-11 11:01:50 +08:00
|
|
|
|
<view class="detail-row" v-if="customer.lastFollowRecord && customer.lastFollowRecord.content">
|
|
|
|
|
|
<text class="detail-label">跟进内容:</text>
|
|
|
|
|
|
<text class="detail-value follow-content">{{ truncateText(customer.lastFollowRecord.content, 30) }}</text>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
|
2025-11-11 16:05:16 +08:00
|
|
|
|
|
2025-11-11 14:23:59 +08:00
|
|
|
|
|
|
|
|
|
|
<!-- 最后跟进时间 -->
|
2025-11-12 11:44:29 +08:00
|
|
|
|
<!-- <view class="detail-row" v-if="customer.lastFollowTime">-->
|
|
|
|
|
|
<!-- <text class="detail-label">最后跟进:</text>-->
|
|
|
|
|
|
<!-- <text class="detail-value">{{ formatDateTime(customer.lastFollowTime) }}</text>-->
|
|
|
|
|
|
<!-- </view>-->
|
2025-11-11 14:23:59 +08:00
|
|
|
|
|
|
|
|
|
|
<!-- 下次跟进时间 -->
|
|
|
|
|
|
<view class="detail-row" v-if="customer.nextFollowTime">
|
|
|
|
|
|
<text class="detail-label">下次跟进:</text>
|
|
|
|
|
|
<text class="detail-value">{{ formatDateTime(customer.nextFollowTime) }}</text>
|
|
|
|
|
|
</view>
|
2025-11-11 16:05:16 +08:00
|
|
|
|
|
|
|
|
|
|
<!-- 分配用户 -->
|
2025-11-12 11:44:29 +08:00
|
|
|
|
<view class="detail-row" v-if="customer.followName">
|
2025-11-12 10:45:54 +08:00
|
|
|
|
<text class="detail-label">跟进人:</text>
|
2025-11-11 16:05:16 +08:00
|
|
|
|
<text class="detail-value">{{ customer.followName || '--' }}</text>
|
|
|
|
|
|
</view>
|
2025-11-07 09:40:39 +08:00
|
|
|
|
</view>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 操作按钮 -->
|
|
|
|
|
|
<view class="action-buttons">
|
|
|
|
|
|
<view class="action-item" @click.stop="handleFollowup(customer)">
|
2025-11-10 14:31:32 +08:00
|
|
|
|
<text class="action-icon">✓</text>
|
2025-11-07 09:40:39 +08:00
|
|
|
|
<text class="action-text">跟进</text>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
<view class="action-item" @click.stop="handleTasks(customer)">
|
|
|
|
|
|
<text class="action-icon">☰</text>
|
|
|
|
|
|
<text class="action-text">任务</text>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
<view class="action-item" @click.stop="handleCall(customer)">
|
2025-11-12 15:42:56 +08:00
|
|
|
|
<text class="action-icon">☏</text>
|
2025-11-07 09:40:39 +08:00
|
|
|
|
<text class="action-text">电话</text>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
<view class="action-item" @click.stop="handleMore(customer)">
|
2025-11-10 14:55:19 +08:00
|
|
|
|
<text class="action-icon">+</text>
|
2025-11-07 09:40:39 +08:00
|
|
|
|
<text class="action-text">更多</text>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 空状态 -->
|
2025-11-08 13:36:04 +08:00
|
|
|
|
<view class="empty-state" v-if="isEmpty">
|
2025-11-07 09:40:39 +08:00
|
|
|
|
<text class="empty-text">暂无客户数据</text>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 加载状态 -->
|
2025-11-08 13:36:04 +08:00
|
|
|
|
<view class="loading-state" v-if="loading && list.length === 0">
|
2025-11-07 09:40:39 +08:00
|
|
|
|
<text class="loading-text">加载中...</text>
|
|
|
|
|
|
</view>
|
2025-11-08 13:36:04 +08:00
|
|
|
|
|
|
|
|
|
|
<!-- 加载更多提示 -->
|
|
|
|
|
|
<view class="load-more" v-if="list.length > 0">
|
|
|
|
|
|
<text class="load-more-text" v-if="loading">加载中...</text>
|
|
|
|
|
|
<text class="load-more-text" v-else-if="noMore">没有更多数据了</text>
|
|
|
|
|
|
<text class="load-more-text" v-else>上拉加载更多</text>
|
|
|
|
|
|
</view>
|
2025-11-07 17:41:03 +08:00
|
|
|
|
</view>
|
2025-11-08 13:36:04 +08:00
|
|
|
|
</view>
|
2025-11-07 09:40:39 +08:00
|
|
|
|
|
|
|
|
|
|
<!-- 悬浮添加按钮 -->
|
|
|
|
|
|
<FabPlus @click="handleAddCustomer" />
|
|
|
|
|
|
</view>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
|
|
<script setup>
|
2025-11-08 15:58:45 +08:00
|
|
|
|
import { ref, computed, onMounted, onUnmounted, watch } from 'vue';
|
2025-11-12 17:09:46 +08:00
|
|
|
|
import { storeToRefs } from 'pinia';
|
2025-11-07 09:40:39 +08:00
|
|
|
|
import FabPlus from '@/components/FabPlus.vue';
|
2025-11-11 17:53:16 +08:00
|
|
|
|
import CustomerSummaryBrief from '@/components/customer/CustomerSummaryBrief.vue';
|
2025-11-08 13:36:04 +08:00
|
|
|
|
import { usePagination } from '@/composables/usePagination';
|
2025-11-12 15:33:53 +08:00
|
|
|
|
import { getCustomerList, deleteCustomer } from '@/api/customer';
|
2025-11-12 10:45:54 +08:00
|
|
|
|
import{useUserStore} from "@/store/user";
|
2025-11-11 11:19:52 +08:00
|
|
|
|
import {
|
|
|
|
|
|
getStatusListByFilter
|
|
|
|
|
|
} from '@/utils/customerMappings';
|
2025-11-07 09:40:39 +08:00
|
|
|
|
|
|
|
|
|
|
// 筛选状态
|
2025-11-12 17:09:46 +08:00
|
|
|
|
const userStore = useUserStore();
|
|
|
|
|
|
const { userInfo, privateView } = storeToRefs(userStore);
|
2025-11-20 17:54:49 +08:00
|
|
|
|
const PAGE_SIZE = 10;
|
|
|
|
|
|
const DEFAULT_SORT = {
|
|
|
|
|
|
orderByColumn: 'next_follow_time',
|
|
|
|
|
|
isAsc: 'descending'
|
|
|
|
|
|
};
|
|
|
|
|
|
const TODAY_FOLLOW_FILTER = 'todayFollow';
|
|
|
|
|
|
|
2025-11-12 17:09:46 +08:00
|
|
|
|
const filterSelf = computed({
|
|
|
|
|
|
get: () => privateView.value,
|
|
|
|
|
|
set: (val) => userStore.setPrivateView(val)
|
|
|
|
|
|
});
|
|
|
|
|
|
const currentUserId = computed(() =>
|
|
|
|
|
|
userInfo.value?.user?.userId || userInfo.value?.userId || null
|
|
|
|
|
|
);
|
|
|
|
|
|
const showPrivateSwitch = computed(() =>
|
|
|
|
|
|
userInfo.value?.roles?.some(r => ['admin','sys_admin'].includes(r))
|
|
|
|
|
|
);
|
2025-11-07 09:40:39 +08:00
|
|
|
|
const showFilter = ref(false);
|
2025-11-20 17:54:49 +08:00
|
|
|
|
const selectedFilters = ref([]);
|
|
|
|
|
|
const isAllSelected = computed(() => selectedFilters.value.length === 0);
|
2025-11-07 09:40:39 +08:00
|
|
|
|
|
2025-11-08 13:36:04 +08:00
|
|
|
|
// 使用分页组合式函数
|
|
|
|
|
|
const {
|
|
|
|
|
|
list,
|
|
|
|
|
|
loading,
|
|
|
|
|
|
noMore,
|
|
|
|
|
|
isEmpty,
|
|
|
|
|
|
getList,
|
|
|
|
|
|
loadMore,
|
|
|
|
|
|
updateParams,
|
2025-11-08 17:13:14 +08:00
|
|
|
|
refresh,
|
|
|
|
|
|
queryParams,
|
|
|
|
|
|
reset
|
2025-11-08 13:36:04 +08:00
|
|
|
|
} = usePagination({
|
|
|
|
|
|
fetchData: getCustomerList,
|
|
|
|
|
|
mode: 'loadMore',
|
2025-11-20 17:54:49 +08:00
|
|
|
|
pageSize: PAGE_SIZE,
|
|
|
|
|
|
defaultParams: {
|
|
|
|
|
|
...DEFAULT_SORT
|
|
|
|
|
|
}
|
2025-11-07 09:40:39 +08:00
|
|
|
|
});
|
|
|
|
|
|
|
2025-11-11 17:53:16 +08:00
|
|
|
|
// 本页状态映射与样式由 CustomerSummaryBrief 统一处理
|
2025-11-11 14:04:09 +08:00
|
|
|
|
|
|
|
|
|
|
// 处理编辑
|
|
|
|
|
|
const handleEdit = (customer) => {
|
|
|
|
|
|
console.log('编辑客户:', customer);
|
|
|
|
|
|
uni.navigateTo({
|
|
|
|
|
|
url: `/pages/customer/edit/index?id=${customer.id}`
|
|
|
|
|
|
});
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2025-11-11 11:01:50 +08:00
|
|
|
|
// 截断文本
|
|
|
|
|
|
const truncateText = (text, maxLength) => {
|
|
|
|
|
|
if (!text) return '--';
|
|
|
|
|
|
if (text.length <= maxLength) return text;
|
|
|
|
|
|
return text.substring(0, maxLength) + '...';
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2025-11-07 09:40:39 +08:00
|
|
|
|
// 格式化日期时间
|
|
|
|
|
|
const formatDateTime = (dateTime) => {
|
|
|
|
|
|
if (!dateTime) return '暂无';
|
|
|
|
|
|
// 将 "2025-10-29 09:00:00" 格式化为 "2025-10-29 09:00"
|
|
|
|
|
|
try {
|
|
|
|
|
|
const date = new Date(dateTime);
|
|
|
|
|
|
const year = date.getFullYear();
|
|
|
|
|
|
const month = String(date.getMonth() + 1).padStart(2, '0');
|
|
|
|
|
|
const day = String(date.getDate()).padStart(2, '0');
|
|
|
|
|
|
const hours = String(date.getHours()).padStart(2, '0');
|
|
|
|
|
|
const minutes = String(date.getMinutes()).padStart(2, '0');
|
|
|
|
|
|
return `${year}-${month}-${day} ${hours}:${minutes}`;
|
|
|
|
|
|
} catch (e) {
|
|
|
|
|
|
return dateTime;
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2025-11-08 13:36:04 +08:00
|
|
|
|
// 构建查询参数(包含筛选条件)
|
2025-11-20 17:54:49 +08:00
|
|
|
|
const getTodayDate = () => {
|
|
|
|
|
|
const today = new Date();
|
|
|
|
|
|
const year = today.getFullYear();
|
|
|
|
|
|
const month = String(today.getMonth() + 1).padStart(2, '0');
|
|
|
|
|
|
const day = String(today.getDate()).padStart(2, '0');
|
|
|
|
|
|
return `${year}-${month}-${day}`;
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2025-11-08 13:36:04 +08:00
|
|
|
|
const buildQueryParams = () => {
|
2025-11-12 17:09:46 +08:00
|
|
|
|
const params = {
|
2025-11-20 17:54:49 +08:00
|
|
|
|
...DEFAULT_SORT,
|
|
|
|
|
|
joinUserId: filterSelf.value && currentUserId.value ? currentUserId.value : null,
|
|
|
|
|
|
nextFollowDateStart: null,
|
2025-11-20 17:58:22 +08:00
|
|
|
|
nextFollowDateEnd: null,
|
|
|
|
|
|
statusList: undefined
|
2025-11-12 17:09:46 +08:00
|
|
|
|
};
|
2025-11-12 10:45:54 +08:00
|
|
|
|
|
2025-11-20 17:54:49 +08:00
|
|
|
|
const hasTodayFollowFilter = selectedFilters.value.includes(TODAY_FOLLOW_FILTER);
|
|
|
|
|
|
const statusFilters = selectedFilters.value.filter(item => item !== TODAY_FOLLOW_FILTER);
|
2025-11-12 10:45:54 +08:00
|
|
|
|
|
2025-11-20 17:54:49 +08:00
|
|
|
|
if (hasTodayFollowFilter) {
|
|
|
|
|
|
const today = getTodayDate();
|
|
|
|
|
|
params.nextFollowDateStart = today;
|
|
|
|
|
|
params.nextFollowDateEnd = today;
|
|
|
|
|
|
console.log('筛选今日跟进,日期:', today);
|
|
|
|
|
|
}
|
2025-11-08 17:13:14 +08:00
|
|
|
|
|
2025-11-20 17:54:49 +08:00
|
|
|
|
if (statusFilters.length > 0) {
|
|
|
|
|
|
const mergedStatusList = Array.from(
|
|
|
|
|
|
new Set(
|
|
|
|
|
|
statusFilters.flatMap(filterKey => getStatusListByFilter(filterKey) || [])
|
|
|
|
|
|
)
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
if (mergedStatusList.length > 0) {
|
|
|
|
|
|
params.statusList = mergedStatusList;
|
|
|
|
|
|
console.log('筛选状态组合:', statusFilters, '-> statusList:', mergedStatusList);
|
2025-11-08 17:13:14 +08:00
|
|
|
|
} else {
|
2025-11-20 17:54:49 +08:00
|
|
|
|
console.log('筛选状态组合未匹配到 statusList,跳过状态筛选');
|
2025-11-08 13:36:04 +08:00
|
|
|
|
}
|
2025-11-20 17:54:49 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (!hasTodayFollowFilter && statusFilters.length === 0) {
|
|
|
|
|
|
console.log('无筛选状态,返回默认参数');
|
2025-11-20 17:58:22 +08:00
|
|
|
|
} else if (hasTodayFollowFilter && statusFilters.length === 0) {
|
|
|
|
|
|
console.log('仅筛选今日跟进,清理状态筛选参数');
|
|
|
|
|
|
params.statusList = undefined;
|
2025-11-07 09:40:39 +08:00
|
|
|
|
}
|
2025-11-08 17:13:14 +08:00
|
|
|
|
|
2025-11-08 13:36:04 +08:00
|
|
|
|
return params;
|
2025-11-07 09:40:39 +08:00
|
|
|
|
};
|
|
|
|
|
|
|
2025-11-20 17:54:49 +08:00
|
|
|
|
const isFilterSelected = (filterKey) => selectedFilters.value.includes(filterKey);
|
|
|
|
|
|
|
|
|
|
|
|
const toggleFilter = (filterKey) => {
|
|
|
|
|
|
if (!filterKey) return;
|
|
|
|
|
|
const exists = selectedFilters.value.includes(filterKey);
|
|
|
|
|
|
if (exists) {
|
|
|
|
|
|
selectedFilters.value = selectedFilters.value.filter(item => item !== filterKey);
|
|
|
|
|
|
} else {
|
|
|
|
|
|
selectedFilters.value = [...selectedFilters.value, filterKey];
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
const handleSelectAll = () => {
|
|
|
|
|
|
if (selectedFilters.value.length === 0) return;
|
|
|
|
|
|
selectedFilters.value = [];
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2025-11-07 09:40:39 +08:00
|
|
|
|
// 处理客户点击
|
|
|
|
|
|
const handleCustomerClick = (customer) => {
|
|
|
|
|
|
console.log('点击客户:', customer);
|
2025-11-07 09:59:46 +08:00
|
|
|
|
// 跳转到客户详情页
|
|
|
|
|
|
uni.navigateTo({
|
2025-11-07 11:40:13 +08:00
|
|
|
|
url: `/pages/customer/detail/index?id=${customer.id}`
|
2025-11-07 09:59:46 +08:00
|
|
|
|
});
|
2025-11-07 09:40:39 +08:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 处理跟进
|
|
|
|
|
|
const handleFollowup = (customer) => {
|
|
|
|
|
|
console.log('跟进客户:', customer);
|
2025-11-11 15:58:00 +08:00
|
|
|
|
// 跳转到跟进新增页
|
2025-11-07 09:40:39 +08:00
|
|
|
|
uni.navigateTo({
|
2025-11-11 15:58:00 +08:00
|
|
|
|
url: `/pages/customer/follow/add/index?customerId=${customer.id}&customerName=${encodeURIComponent(customer.name || '')}`
|
2025-11-07 09:40:39 +08:00
|
|
|
|
});
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 处理任务
|
|
|
|
|
|
const handleTasks = (customer) => {
|
|
|
|
|
|
console.log('查看客户任务:', customer);
|
|
|
|
|
|
// 可以跳转到客户任务列表页
|
|
|
|
|
|
uni.navigateTo({
|
|
|
|
|
|
url: `/pages/customer-tasks/index?customerId=${customer.id}&customerName=${customer.name}`
|
|
|
|
|
|
});
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 处理电话
|
|
|
|
|
|
const handleCall = (customer) => {
|
|
|
|
|
|
console.log('拨打客户电话:', customer);
|
|
|
|
|
|
// 使用 mobile 字段
|
|
|
|
|
|
if (customer.mobile) {
|
|
|
|
|
|
uni.makePhoneCall({
|
|
|
|
|
|
phoneNumber: customer.mobile,
|
|
|
|
|
|
fail: (err) => {
|
|
|
|
|
|
console.error('拨打电话失败:', err);
|
|
|
|
|
|
uni.$uv.toast('拨打电话失败');
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
} else {
|
|
|
|
|
|
uni.$uv.toast('客户未设置电话号码');
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 处理更多
|
|
|
|
|
|
const handleMore = (customer) => {
|
|
|
|
|
|
console.log('更多操作:', customer);
|
2025-11-08 15:29:40 +08:00
|
|
|
|
// 显示操作菜单
|
2025-11-07 09:40:39 +08:00
|
|
|
|
uni.showActionSheet({
|
|
|
|
|
|
itemList: ['编辑客户', '删除客户', '查看详情'],
|
|
|
|
|
|
success: (res) => {
|
2025-11-08 15:29:40 +08:00
|
|
|
|
if (res.tapIndex === 0) {
|
|
|
|
|
|
// 编辑客户
|
|
|
|
|
|
uni.navigateTo({
|
|
|
|
|
|
url: `/pages/customer/edit/index?id=${customer.id}`
|
|
|
|
|
|
});
|
|
|
|
|
|
} else if (res.tapIndex === 1) {
|
|
|
|
|
|
// 删除客户
|
|
|
|
|
|
uni.showModal({
|
|
|
|
|
|
title: '确认删除',
|
|
|
|
|
|
content: `确定要删除客户"${customer.name}"吗?`,
|
2025-11-08 15:58:45 +08:00
|
|
|
|
success: async (modalRes) => {
|
2025-11-08 15:29:40 +08:00
|
|
|
|
if (modalRes.confirm) {
|
2025-11-08 15:58:45 +08:00
|
|
|
|
try {
|
|
|
|
|
|
// 显示加载提示
|
|
|
|
|
|
uni.showLoading({
|
|
|
|
|
|
title: '删除中...',
|
|
|
|
|
|
mask: true
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
// 调用删除API
|
|
|
|
|
|
await deleteCustomer(customer.id);
|
|
|
|
|
|
|
|
|
|
|
|
// 隐藏加载提示
|
|
|
|
|
|
uni.hideLoading();
|
|
|
|
|
|
|
|
|
|
|
|
// 显示成功提示
|
|
|
|
|
|
uni.$uv.toast('删除成功');
|
|
|
|
|
|
|
|
|
|
|
|
// 刷新列表
|
|
|
|
|
|
refresh();
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
// 隐藏加载提示
|
|
|
|
|
|
uni.hideLoading();
|
|
|
|
|
|
|
|
|
|
|
|
// 显示错误提示
|
|
|
|
|
|
console.error('删除客户失败:', error);
|
|
|
|
|
|
uni.$uv.toast(error?.message || '删除失败,请重试');
|
|
|
|
|
|
}
|
2025-11-08 15:29:40 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
} else if (res.tapIndex === 2) {
|
|
|
|
|
|
// 查看详情
|
|
|
|
|
|
uni.navigateTo({
|
|
|
|
|
|
url: `/pages/customer/detail/index?id=${customer.id}`
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
2025-11-07 09:40:39 +08:00
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 处理添加客户
|
|
|
|
|
|
const handleAddCustomer = () => {
|
|
|
|
|
|
console.log('添加新客户');
|
|
|
|
|
|
// 跳转到添加客户页面
|
|
|
|
|
|
uni.navigateTo({
|
2025-11-07 11:40:13 +08:00
|
|
|
|
url: '/pages/customer/add/index'
|
2025-11-07 09:40:39 +08:00
|
|
|
|
});
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2025-11-08 13:36:04 +08:00
|
|
|
|
// 监听筛选状态变化,更新查询参数并重新加载
|
2025-11-20 17:54:49 +08:00
|
|
|
|
watch(selectedFilters, () => {
|
|
|
|
|
|
console.log('筛选状态变化:', selectedFilters.value);
|
2025-11-08 17:13:14 +08:00
|
|
|
|
|
2025-11-20 17:54:49 +08:00
|
|
|
|
if (selectedFilters.value.length === 0) {
|
2025-11-08 17:13:14 +08:00
|
|
|
|
reset();
|
2025-11-20 17:54:49 +08:00
|
|
|
|
queryParams.value = {
|
|
|
|
|
|
...DEFAULT_SORT,
|
2025-11-12 17:09:46 +08:00
|
|
|
|
joinUserId: filterSelf.value && currentUserId.value ? currentUserId.value : null,
|
2025-11-08 17:13:14 +08:00
|
|
|
|
pageNum: 1,
|
2025-11-20 17:54:49 +08:00
|
|
|
|
pageSize: PAGE_SIZE,
|
|
|
|
|
|
nextFollowDateStart: null,
|
2025-11-20 17:58:22 +08:00
|
|
|
|
nextFollowDateEnd: null,
|
|
|
|
|
|
statusList: undefined
|
2025-11-08 17:13:14 +08:00
|
|
|
|
};
|
|
|
|
|
|
refresh();
|
|
|
|
|
|
} else {
|
|
|
|
|
|
const params = buildQueryParams();
|
|
|
|
|
|
updateParams(params);
|
|
|
|
|
|
}
|
2025-11-20 17:54:49 +08:00
|
|
|
|
}, { deep: true });
|
2025-11-07 09:40:39 +08:00
|
|
|
|
|
2025-11-12 10:45:54 +08:00
|
|
|
|
watch(filterSelf, () => {
|
|
|
|
|
|
console.log('筛选是否自己变化:', filterSelf.value);
|
|
|
|
|
|
const params = buildQueryParams();
|
2025-11-12 17:09:46 +08:00
|
|
|
|
console.log('客户列表查询参数', params);
|
2025-11-12 10:45:54 +08:00
|
|
|
|
updateParams(params);
|
|
|
|
|
|
})
|
|
|
|
|
|
|
2025-11-08 15:58:45 +08:00
|
|
|
|
// 监听客户列表刷新事件
|
|
|
|
|
|
const handleCustomerListRefresh = () => {
|
|
|
|
|
|
console.log('收到客户列表刷新事件');
|
|
|
|
|
|
refresh();
|
|
|
|
|
|
// 清除存储标志,避免 onShow 时重复刷新
|
|
|
|
|
|
uni.removeStorageSync('customerListNeedRefresh');
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2025-11-07 09:40:39 +08:00
|
|
|
|
// 组件挂载时加载数据
|
|
|
|
|
|
onMounted(() => {
|
2025-11-08 13:36:04 +08:00
|
|
|
|
const params = buildQueryParams();
|
|
|
|
|
|
// updateParams 内部会调用 getList(),所以不需要重复调用
|
|
|
|
|
|
updateParams(params);
|
2025-11-08 15:58:45 +08:00
|
|
|
|
|
|
|
|
|
|
// 监听客户列表刷新事件
|
|
|
|
|
|
uni.$on('customerListRefresh', handleCustomerListRefresh);
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
// 组件卸载时移除事件监听
|
|
|
|
|
|
onUnmounted(() => {
|
|
|
|
|
|
uni.$off('customerListRefresh', handleCustomerListRefresh);
|
2025-11-07 18:01:19 +08:00
|
|
|
|
});
|
|
|
|
|
|
|
2025-11-08 13:36:04 +08:00
|
|
|
|
// 暴露方法供父组件调用(用于 onReachBottom)
|
2025-11-13 09:48:26 +08:00
|
|
|
|
const winB_LoadMore= () => {
|
2025-11-08 13:36:04 +08:00
|
|
|
|
if (!loading.value && !noMore.value) {
|
|
|
|
|
|
loadMore();
|
2025-11-07 18:01:19 +08:00
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2025-11-08 13:36:04 +08:00
|
|
|
|
// 使用 defineExpose 暴露方法
|
|
|
|
|
|
defineExpose({
|
2025-11-08 15:58:45 +08:00
|
|
|
|
winB_LoadMore,
|
|
|
|
|
|
refresh // 暴露 refresh 方法,供外部调用
|
2025-11-07 09:40:39 +08:00
|
|
|
|
});
|
2025-11-08 13:36:04 +08:00
|
|
|
|
|
2025-11-07 09:40:39 +08:00
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
|
|
<style lang="scss" scoped>
|
|
|
|
|
|
.customer-management {
|
2025-11-13 10:49:10 +08:00
|
|
|
|
margin-top: var(--status-bar-height, 0);
|
2025-11-07 09:40:39 +08:00
|
|
|
|
display: flex;
|
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
|
height: 100%;
|
2025-11-07 17:41:03 +08:00
|
|
|
|
width: 100%;
|
|
|
|
|
|
background-color: #f5f7fa;
|
|
|
|
|
|
position: relative;
|
2025-11-07 09:40:39 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* 顶部标题栏 */
|
|
|
|
|
|
.header {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
justify-content: space-between;
|
|
|
|
|
|
padding: 12px 16px;
|
|
|
|
|
|
background-color: #fff;
|
2025-11-07 17:41:03 +08:00
|
|
|
|
border-bottom: 1px solid #e4e7ed;
|
|
|
|
|
|
position: fixed;
|
2025-11-07 09:40:39 +08:00
|
|
|
|
top: 0;
|
2025-11-07 17:41:03 +08:00
|
|
|
|
right: 0;
|
|
|
|
|
|
left: 0;
|
2025-11-07 09:40:39 +08:00
|
|
|
|
z-index: 100;
|
2025-11-07 17:41:03 +08:00
|
|
|
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.04);
|
2025-11-07 09:40:39 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.header-title {
|
|
|
|
|
|
font-size: 18px;
|
|
|
|
|
|
font-weight: 600;
|
2025-11-07 17:41:03 +08:00
|
|
|
|
color: #303133;
|
|
|
|
|
|
letter-spacing: 0.5px;
|
2025-11-07 09:40:39 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.filter-btn {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
2025-11-07 17:41:03 +08:00
|
|
|
|
gap: 6px;
|
|
|
|
|
|
padding: 6px 12px;
|
|
|
|
|
|
border-radius: 6px;
|
|
|
|
|
|
background-color: #f5f7fa;
|
|
|
|
|
|
transition: all 0.3s ease;
|
2025-11-07 09:40:39 +08:00
|
|
|
|
cursor: pointer;
|
2025-11-07 17:41:03 +08:00
|
|
|
|
|
|
|
|
|
|
&:active {
|
|
|
|
|
|
background-color: #e4e7ed;
|
|
|
|
|
|
transform: scale(0.95);
|
|
|
|
|
|
}
|
2025-11-07 09:40:39 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.filter-text {
|
|
|
|
|
|
font-size: 14px;
|
2025-11-07 17:41:03 +08:00
|
|
|
|
color: #606266;
|
|
|
|
|
|
font-weight: 500;
|
2025-11-07 09:40:39 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.filter-icon {
|
|
|
|
|
|
font-size: 12px;
|
2025-11-07 17:41:03 +08:00
|
|
|
|
color: #909399;
|
|
|
|
|
|
transition: transform 0.3s ease;
|
2025-11-07 09:40:39 +08:00
|
|
|
|
|
|
|
|
|
|
&.rotate {
|
|
|
|
|
|
transform: rotate(180deg);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* 筛选面板 */
|
|
|
|
|
|
.filter-panel {
|
|
|
|
|
|
background-color: #fff;
|
2025-11-07 17:41:03 +08:00
|
|
|
|
padding: 16px;
|
|
|
|
|
|
border-bottom: 1px solid #e4e7ed;
|
|
|
|
|
|
position: fixed;
|
|
|
|
|
|
top: 52px;
|
|
|
|
|
|
right: 0;
|
|
|
|
|
|
left: 0;
|
|
|
|
|
|
z-index: 99;
|
|
|
|
|
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.04);
|
|
|
|
|
|
animation: slideDown 0.3s ease;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@keyframes slideDown {
|
|
|
|
|
|
from {
|
|
|
|
|
|
opacity: 0;
|
|
|
|
|
|
transform: translateY(-10px);
|
|
|
|
|
|
}
|
|
|
|
|
|
to {
|
|
|
|
|
|
opacity: 1;
|
|
|
|
|
|
transform: translateY(0);
|
|
|
|
|
|
}
|
2025-11-07 09:40:39 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.filter-item {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
2025-11-07 17:41:03 +08:00
|
|
|
|
gap: 16px;
|
2025-11-07 09:40:39 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.filter-label {
|
|
|
|
|
|
font-size: 14px;
|
2025-11-07 17:41:03 +08:00
|
|
|
|
color: #606266;
|
2025-11-07 09:40:39 +08:00
|
|
|
|
flex-shrink: 0;
|
2025-11-07 17:41:03 +08:00
|
|
|
|
font-weight: 500;
|
2025-11-07 09:40:39 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.filter-options {
|
|
|
|
|
|
display: flex;
|
2025-11-07 17:41:03 +08:00
|
|
|
|
gap: 10px;
|
2025-11-07 09:40:39 +08:00
|
|
|
|
flex-wrap: wrap;
|
2025-11-07 17:41:03 +08:00
|
|
|
|
flex: 1;
|
2025-11-07 09:40:39 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.filter-option {
|
2025-11-07 17:41:03 +08:00
|
|
|
|
padding: 6px 16px;
|
2025-11-07 09:40:39 +08:00
|
|
|
|
font-size: 14px;
|
2025-11-07 17:41:03 +08:00
|
|
|
|
color: #606266;
|
|
|
|
|
|
background-color: #f5f7fa;
|
|
|
|
|
|
border-radius: 20px;
|
|
|
|
|
|
transition: all 0.3s ease;
|
|
|
|
|
|
cursor: pointer;
|
|
|
|
|
|
border: 1px solid transparent;
|
|
|
|
|
|
|
|
|
|
|
|
&:active {
|
|
|
|
|
|
transform: scale(0.95);
|
|
|
|
|
|
}
|
2025-11-07 09:40:39 +08:00
|
|
|
|
|
|
|
|
|
|
&.active {
|
2025-11-07 17:41:03 +08:00
|
|
|
|
color: #2885ff;
|
|
|
|
|
|
background-color: #e6f2ff;
|
|
|
|
|
|
border-color: #2885ff;
|
|
|
|
|
|
font-weight: 500;
|
2025-11-07 09:40:39 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* 客户列表 */
|
|
|
|
|
|
.customer-list {
|
|
|
|
|
|
flex: 1;
|
2025-11-10 15:23:11 +08:00
|
|
|
|
padding-top: 28px;
|
2025-11-07 17:41:03 +08:00
|
|
|
|
padding-bottom: 100px; /* 为底部导航栏和悬浮按钮留出空间 */
|
|
|
|
|
|
background-color: #f5f7fa;
|
2025-11-08 13:36:04 +08:00
|
|
|
|
/* 移除 overflow-y: auto,让页面本身滚动以支持 onReachBottom */
|
2025-11-07 17:41:03 +08:00
|
|
|
|
transition: padding-top 0.3s ease;
|
|
|
|
|
|
|
|
|
|
|
|
&.with-filter {
|
2025-11-10 15:23:11 +08:00
|
|
|
|
padding-top: 132px; /* header(52px) + filter panel(约56px) */
|
2025-11-07 17:41:03 +08:00
|
|
|
|
}
|
2025-11-07 09:40:39 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.customer-card {
|
|
|
|
|
|
background-color: #fff;
|
2025-11-07 17:41:03 +08:00
|
|
|
|
border-radius: 12px;
|
2025-11-07 09:40:39 +08:00
|
|
|
|
padding: 16px;
|
2025-11-07 17:41:03 +08:00
|
|
|
|
margin: 0 12px 12px 12px;
|
|
|
|
|
|
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.08);
|
|
|
|
|
|
transition: all 0.3s ease;
|
|
|
|
|
|
border: 1px solid #f0f0f0;
|
|
|
|
|
|
|
|
|
|
|
|
&:active {
|
|
|
|
|
|
transform: scale(0.98);
|
|
|
|
|
|
box-shadow: 0 1px 6px rgba(0, 0, 0, 0.12);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
&:last-child {
|
|
|
|
|
|
margin-bottom: 20px;
|
|
|
|
|
|
}
|
2025-11-07 09:40:39 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.customer-header {
|
|
|
|
|
|
display: flex;
|
2025-11-11 14:04:09 +08:00
|
|
|
|
align-items: center;
|
|
|
|
|
|
margin-bottom: 12px;
|
2025-11-07 09:40:39 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-11 14:04:09 +08:00
|
|
|
|
.customer-name-wrapper {
|
2025-11-07 09:40:39 +08:00
|
|
|
|
display: flex;
|
2025-11-11 14:04:09 +08:00
|
|
|
|
align-items: center;
|
2025-11-07 17:41:03 +08:00
|
|
|
|
gap: 8px;
|
2025-11-07 09:40:39 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.customer-name {
|
|
|
|
|
|
font-size: 16px;
|
|
|
|
|
|
font-weight: 600;
|
2025-11-11 14:04:09 +08:00
|
|
|
|
color: #2885ff;
|
2025-11-07 17:41:03 +08:00
|
|
|
|
line-height: 1.4;
|
2025-11-07 09:40:39 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-11 14:04:09 +08:00
|
|
|
|
.edit-icon {
|
2025-11-11 15:58:00 +08:00
|
|
|
|
|
2025-11-07 17:41:03 +08:00
|
|
|
|
color: #909399;
|
2025-11-11 14:04:09 +08:00
|
|
|
|
cursor: pointer;
|
|
|
|
|
|
opacity: 0.6;
|
|
|
|
|
|
transition: opacity 0.3s ease;
|
|
|
|
|
|
|
|
|
|
|
|
&:active {
|
|
|
|
|
|
opacity: 1;
|
|
|
|
|
|
}
|
2025-11-07 09:40:39 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-11 14:04:09 +08:00
|
|
|
|
/* 标签区域 */
|
|
|
|
|
|
.tags-section {
|
2025-11-07 09:40:39 +08:00
|
|
|
|
display: flex;
|
2025-11-11 14:04:09 +08:00
|
|
|
|
flex-wrap: wrap;
|
|
|
|
|
|
gap: 8px;
|
|
|
|
|
|
margin-bottom: 12px;
|
2025-11-07 09:40:39 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-11 14:04:09 +08:00
|
|
|
|
/* 状态标签 */
|
|
|
|
|
|
.status-tag {
|
|
|
|
|
|
display: inline-block;
|
|
|
|
|
|
padding: 4px 12px;
|
|
|
|
|
|
font-size: 13px;
|
|
|
|
|
|
font-weight: 500;
|
|
|
|
|
|
border-radius: 12px;
|
|
|
|
|
|
white-space: nowrap;
|
2025-11-07 09:40:39 +08:00
|
|
|
|
|
2025-11-11 14:04:09 +08:00
|
|
|
|
&.status-tag-potential {
|
|
|
|
|
|
color: #e6a23c;
|
|
|
|
|
|
background-color: #fdf6ec;
|
|
|
|
|
|
border: 1px solid #f5dab1;
|
2025-11-10 14:31:32 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-11 14:04:09 +08:00
|
|
|
|
&.status-tag-intent {
|
|
|
|
|
|
color: #409eff;
|
|
|
|
|
|
background-color: #ecf5ff;
|
|
|
|
|
|
border: 1px solid #b3d8ff;
|
2025-11-10 14:31:32 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-11 14:04:09 +08:00
|
|
|
|
&.status-tag-deal {
|
|
|
|
|
|
color: #67c23a;
|
|
|
|
|
|
background-color: #f0f9ff;
|
|
|
|
|
|
border: 1px solid #b3e19d;
|
2025-11-07 09:40:39 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-11 14:04:09 +08:00
|
|
|
|
&.status-tag-invalid {
|
|
|
|
|
|
color: #f56c6c;
|
|
|
|
|
|
background-color: #fef0f0;
|
|
|
|
|
|
border: 1px solid #fbc4c4;
|
2025-11-07 09:40:39 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-11 14:04:09 +08:00
|
|
|
|
/* 意向强度标签 */
|
|
|
|
|
|
.intent-level-tag {
|
|
|
|
|
|
display: inline-block;
|
|
|
|
|
|
padding: 4px 12px;
|
|
|
|
|
|
font-size: 13px;
|
2025-11-07 17:41:03 +08:00
|
|
|
|
font-weight: 500;
|
2025-11-11 14:04:09 +08:00
|
|
|
|
color: #e6a23c;
|
|
|
|
|
|
background-color: #fef9e7;
|
|
|
|
|
|
border: 1px solid #f5dab1;
|
|
|
|
|
|
border-radius: 12px;
|
|
|
|
|
|
white-space: nowrap;
|
2025-11-07 09:40:39 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-11 14:04:09 +08:00
|
|
|
|
/* 客户意向标签 */
|
|
|
|
|
|
.intent-tag {
|
|
|
|
|
|
display: inline-block;
|
|
|
|
|
|
padding: 4px 12px;
|
2025-11-07 17:41:03 +08:00
|
|
|
|
font-size: 13px;
|
|
|
|
|
|
font-weight: 500;
|
2025-11-11 14:04:09 +08:00
|
|
|
|
color: #67c23a;
|
|
|
|
|
|
background-color: #f0f9ff;
|
|
|
|
|
|
border: 1px solid #b3e19d;
|
|
|
|
|
|
border-radius: 12px;
|
|
|
|
|
|
white-space: nowrap;
|
2025-11-07 09:40:39 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-11 14:04:09 +08:00
|
|
|
|
/* 客户详细信息区域 */
|
2025-11-11 11:01:50 +08:00
|
|
|
|
.customer-details {
|
2025-11-11 14:04:09 +08:00
|
|
|
|
margin-top: 12px;
|
|
|
|
|
|
margin-bottom: 12px;
|
|
|
|
|
|
padding-top: 12px;
|
|
|
|
|
|
border-top: 1px solid #f0f2f5;
|
2025-11-11 11:01:50 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.detail-row {
|
|
|
|
|
|
display: flex;
|
2025-11-11 14:04:09 +08:00
|
|
|
|
align-items: flex-start;
|
|
|
|
|
|
margin-bottom: 8px;
|
|
|
|
|
|
font-size: 14px;
|
|
|
|
|
|
line-height: 1.5;
|
2025-11-11 11:01:50 +08:00
|
|
|
|
|
|
|
|
|
|
&:last-child {
|
|
|
|
|
|
margin-bottom: 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.detail-label {
|
|
|
|
|
|
color: #909399;
|
2025-11-11 14:04:09 +08:00
|
|
|
|
margin-right: 8px;
|
2025-11-11 11:01:50 +08:00
|
|
|
|
flex-shrink: 0;
|
2025-11-11 14:04:09 +08:00
|
|
|
|
min-width: 70px;
|
2025-11-11 11:01:50 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.detail-value {
|
|
|
|
|
|
color: #303133;
|
|
|
|
|
|
flex: 1;
|
2025-11-11 14:04:09 +08:00
|
|
|
|
word-break: break-all;
|
|
|
|
|
|
|
2025-11-12 11:44:29 +08:00
|
|
|
|
|
2025-11-11 11:01:50 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-07 09:40:39 +08:00
|
|
|
|
/* 操作按钮 */
|
|
|
|
|
|
.action-buttons {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
justify-content: space-around;
|
|
|
|
|
|
align-items: center;
|
2025-11-12 11:56:39 +08:00
|
|
|
|
|
2025-11-07 17:41:03 +08:00
|
|
|
|
border-top: 1px solid #f0f2f5;
|
|
|
|
|
|
gap: 8px;
|
2025-11-07 09:40:39 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.action-item {
|
|
|
|
|
|
display: flex;
|
2025-11-07 17:41:03 +08:00
|
|
|
|
flex-direction: column;
|
2025-11-07 09:40:39 +08:00
|
|
|
|
align-items: center;
|
|
|
|
|
|
gap: 4px;
|
2025-11-07 17:41:03 +08:00
|
|
|
|
padding: 8px 12px;
|
|
|
|
|
|
border-radius: 8px;
|
|
|
|
|
|
transition: all 0.3s ease;
|
2025-11-07 09:40:39 +08:00
|
|
|
|
cursor: pointer;
|
2025-11-07 17:41:03 +08:00
|
|
|
|
flex: 1;
|
|
|
|
|
|
min-width: 0;
|
|
|
|
|
|
|
|
|
|
|
|
&:active {
|
|
|
|
|
|
background-color: #f5f7fa;
|
|
|
|
|
|
transform: scale(0.95);
|
|
|
|
|
|
}
|
2025-11-07 09:40:39 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.action-icon {
|
2025-11-07 17:41:03 +08:00
|
|
|
|
font-size: 18px;
|
|
|
|
|
|
color: #606266;
|
2025-11-07 09:40:39 +08:00
|
|
|
|
font-weight: 500;
|
2025-11-07 17:41:03 +08:00
|
|
|
|
line-height: 1;
|
|
|
|
|
|
transition: all 0.3s ease;
|
2025-11-07 09:40:39 +08:00
|
|
|
|
|
|
|
|
|
|
&.checked {
|
2025-11-07 17:41:03 +08:00
|
|
|
|
color: #2885ff;
|
2025-11-07 09:40:39 +08:00
|
|
|
|
font-weight: 600;
|
2025-11-07 17:41:03 +08:00
|
|
|
|
transform: scale(1.1);
|
2025-11-07 09:40:39 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.action-text {
|
2025-11-07 17:41:03 +08:00
|
|
|
|
font-size: 12px;
|
|
|
|
|
|
color: #606266;
|
|
|
|
|
|
font-weight: 500;
|
|
|
|
|
|
white-space: nowrap;
|
2025-11-07 09:40:39 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.action-arrow {
|
2025-11-07 17:41:03 +08:00
|
|
|
|
font-size: 16px;
|
|
|
|
|
|
color: #909399;
|
2025-11-07 09:40:39 +08:00
|
|
|
|
margin-left: 4px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* 空状态 */
|
|
|
|
|
|
.empty-state {
|
|
|
|
|
|
display: flex;
|
2025-11-07 17:41:03 +08:00
|
|
|
|
flex-direction: column;
|
2025-11-07 09:40:39 +08:00
|
|
|
|
justify-content: center;
|
|
|
|
|
|
align-items: center;
|
2025-11-07 17:41:03 +08:00
|
|
|
|
padding: 80px 20px;
|
|
|
|
|
|
min-height: 300px;
|
2025-11-07 09:40:39 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.empty-text {
|
|
|
|
|
|
font-size: 14px;
|
2025-11-07 17:41:03 +08:00
|
|
|
|
color: #909399;
|
|
|
|
|
|
margin-top: 12px;
|
2025-11-07 09:40:39 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* 加载状态 */
|
|
|
|
|
|
.loading-state {
|
|
|
|
|
|
display: flex;
|
2025-11-07 17:41:03 +08:00
|
|
|
|
flex-direction: column;
|
2025-11-07 09:40:39 +08:00
|
|
|
|
justify-content: center;
|
|
|
|
|
|
align-items: center;
|
2025-11-07 17:41:03 +08:00
|
|
|
|
padding: 60px 20px;
|
|
|
|
|
|
min-height: 200px;
|
2025-11-07 09:40:39 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.loading-text {
|
|
|
|
|
|
font-size: 14px;
|
2025-11-07 17:41:03 +08:00
|
|
|
|
color: #909399;
|
|
|
|
|
|
margin-top: 12px;
|
2025-11-07 09:40:39 +08:00
|
|
|
|
}
|
2025-11-08 13:36:04 +08:00
|
|
|
|
|
|
|
|
|
|
/* 加载更多提示 */
|
|
|
|
|
|
.load-more {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
justify-content: center;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
padding: 20px;
|
|
|
|
|
|
margin-bottom: 20px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.load-more-text {
|
|
|
|
|
|
font-size: 13px;
|
|
|
|
|
|
color: #909399;
|
|
|
|
|
|
}
|
2025-11-07 09:40:39 +08:00
|
|
|
|
</style>
|
|
|
|
|
|
|