Files
smartDriveEEUniApp/pages-subpackage/customer/components/ServiceList.vue
2026-01-31 21:10:40 +08:00

421 lines
9.5 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<view class="service-list-container">
<view class="service-status-toolbar">
<text class="toolbar-total">{{ total || list.length }}</text>
<input
class="toolbar-input"
v-model="salesName"
placeholder="所属销售姓名"
placeholder-style="color: #b0b0b0"
confirm-type="search"
@confirm="handleRefresh"
@input="onInputChange"
/>
<input
class="toolbar-input"
v-model="customerName"
placeholder="客户姓名"
placeholder-style="color: #b0b0b0"
confirm-type="search"
@confirm="handleRefresh"
@input="onInputChange"
/>
<view class="toolbar-actions">
<view class="toolbar-btn toolbar-btn--refresh" @click="handleRefresh">
<uni-icons type="refresh" size="18" color="#2A68FF"></uni-icons>
<text>刷新</text>
</view>
</view>
</view>
<scroll-view class="service-list" scroll-y @scrolltolower="onReachBottom">
<view
class="service-item"
v-for="(item, index) in list"
:key="index"
:class="{ 'service-item--active': selectedServiceItem && selectedServiceItem.id === item.id }"
@click="handleItemClick(item)">
<view class="service-header">
<text class="service-title">{{ item.title }}</text>
<view class="service-menu-button" @click.stop="onMenuButtonClick(item)">
<uni-icons type="more-filled" size="20" color="#999"></uni-icons>
</view>
</view>
<view class="service-meta">
<text class="service-date">{{ item.date }}</text>
</view>
<view class="service-content">
<text class="service-desc">{{ item.description }}</text>
</view>
<view class="service-customer">
<view class="customer-avatar">
<text class="avatar-text">{{ item.customerName.charAt(0) }}</text>
</view>
<text class="customer-name">{{ item.customerName }}</text>
</view>
<!-- 操作菜单 -->
<view
class="service-action-menu"
v-if="selectedServiceItem && selectedServiceItem.id === item.id && showServiceActionMenu"
@click.stop>
<view class="service-action-menu-item service-action-menu-item--danger" @click="handleDelete(item)">
<text>删除</text>
</view>
<view class="service-action-menu-divider"></view>
<view class="service-action-menu-item" @click="handleView(item)">
<text>查看</text>
</view>
<view class="service-action-menu-divider"></view>
<view class="service-action-menu-item" @click="handleAnalysis(item)">
<text>AI分析</text>
</view>
<view class="service-action-menu-divider"></view>
<view class="service-action-menu-item" @click="handleAudio(item)">
<text>录音</text>
</view>
</view>
</view>
</scroll-view>
<!-- 遮罩层点击关闭菜单 -->
<view
class="service-action-menu-mask"
v-if="showServiceActionMenu"
@click="closeServiceActionMenu">
</view>
</view>
</template>
<script>
export default {
name: 'ServiceList',
props: {
list: {
type: Array,
default: () => []
},
total: {
type: Number,
default: 0
}
},
data() {
return {
salesName: '',
customerName: '',
selectedServiceItem: null,
showServiceActionMenu: false
}
},
methods: {
onInputChange() {
// 输入框变化时,可以在这里添加实时搜索逻辑(如果需要)
},
handleRefresh() {
// 触发刷新事件,并传递查询参数
this.$emit('filterClick', {
salesName: this.salesName.trim(),
customerName: this.customerName.trim()
});
},
onReachBottom() {
this.$emit('reachBottom');
},
// 菜单按钮点击
onMenuButtonClick(item) {
// 如果已经选中当前项,则关闭菜单
if (this.selectedServiceItem && this.selectedServiceItem.id === item.id && this.showServiceActionMenu) {
this.closeServiceActionMenu();
return;
}
// 显示菜单
this.selectedServiceItem = item;
this.showServiceActionMenu = true;
},
// 关闭菜单
closeServiceActionMenu() {
this.showServiceActionMenu = false;
this.selectedServiceItem = null;
},
// 处理删除
handleDelete(item) {
this.closeServiceActionMenu();
this.$emit('menuAction', {
action: 'delete',
item: item
});
},
// 处理查看
handleView(item) {
this.closeServiceActionMenu();
this.$emit('menuAction', {
action: 'view',
item: item
});
},
// 处理AI分析
handleAnalysis(item) {
this.closeServiceActionMenu();
this.$emit('menuAction', {
action: 'analysis',
item: item
});
},
// 处理录音
handleAudio(item) {
this.closeServiceActionMenu();
this.$emit('menuAction', {
action: 'audio',
item: item
});
},
// 处理列表项点击
handleItemClick(item) {
// 如果菜单正在显示,不触发列表项点击
if (this.showServiceActionMenu) {
return;
}
// 触发列表项点击事件,打开详情页面
this.$emit('itemClick', item);
}
}
}
</script>
<style scoped>
.service-list-container {
/* 使用绝对定位从tab页底部开始到底部导航栏结束 */
position: absolute;
top: 160rpx; /* 导航栏(88rpx) + tab页(72rpx) = 160rpx */
left: 0;
right: 0;
bottom: 96rpx; /* 底部导航栏高度 */
display: flex;
flex-direction: column;
background-color: #F5F5F5;
padding: 24rpx 16rpx;
box-sizing: border-box;
}
.service-status-toolbar {
display: flex;
flex-wrap: nowrap;
align-items: center;
gap: 8rpx; /* 增加间距,避免元素被挤压 */
padding: 12rpx 8rpx; /* 增加内边距,给搜索框更多空间 */
margin-bottom: 24rpx; /* 与列表项间距保持一致24rpx */
background-color: #F8F8FA;
border-radius: 8rpx;
border: 1px solid #EFEFF2;
overflow-x: auto;
min-height: 64rpx; /* 设置最小高度,确保搜索区域不被挤压 */
box-sizing: border-box;
flex-shrink: 0; /* 防止被压缩 */
}
.toolbar-total {
font-size: 24rpx;
color: #666;
white-space: nowrap;
flex-shrink: 0;
margin-right: 8rpx; /* 增加右边距,与搜索框保持距离 */
line-height: 1.2;
padding: 0 4rpx; /* 增加左右内边距 */
}
.toolbar-input {
flex: 1;
min-width: 120rpx; /* 增加最小宽度,避免被挤压变形 */
max-width: 200rpx; /* 设置最大宽度,保持合理比例 */
height: 56rpx; /* 稍微增加高度,提升可用性 */
line-height: 56rpx;
background-color: #F5F6FA;
border-radius: 8rpx;
padding: 0 12rpx; /* 增加左右内边距 */
font-size: 24rpx;
border: 1px solid transparent;
box-sizing: border-box;
flex-shrink: 1; /* 允许适当收缩,但保持最小宽度 */
}
.toolbar-actions {
display: flex;
align-items: center;
margin-left: auto;
flex-shrink: 0;
gap: 8rpx; /* 增加按钮之间的间距 */
}
.toolbar-btn {
padding: 0 12rpx; /* 增加左右内边距 */
height: 56rpx; /* 与输入框高度保持一致 */
min-width: 56rpx;
color: #2A68FF;
display: flex;
align-items: center;
justify-content: center;
gap: 4rpx; /* 增加图标和文字之间的间距 */
font-size: 24rpx;
font-weight: 400;
line-height: 1;
box-sizing: border-box;
}
.toolbar-btn text {
color: #2A68FF;
}
.service-list {
/* 使用flex填充剩余空间 */
flex: 1;
background-color: transparent;
box-sizing: border-box;
overflow-y: auto;
}
.service-item {
width: 100%;
box-sizing: border-box;
background-color: #FFFFFF;
border-radius: 16rpx;
padding: 32rpx;
margin-bottom: 24rpx;
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.04);
position: relative;
}
.service-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 16rpx;
position: relative;
}
.service-title {
font-size: 32rpx;
font-weight: 500;
color: #333;
}
.service-menu-button {
width: 48rpx;
height: 48rpx;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
}
.service-action-menu {
position: absolute;
top: 60rpx;
right: 32rpx;
width: 160rpx;
background-color: #FFFFFF;
border-radius: 12rpx;
box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.15);
z-index: 100;
overflow: hidden;
margin-right: 0;
}
.service-action-menu-item {
padding: 24rpx 32rpx;
font-size: 28rpx;
color: #333;
text-align: center;
background-color: #FFFFFF;
}
.service-action-menu-item:active {
background-color: #F5F5F5;
}
.service-action-menu-item--danger {
color: #FF5722;
}
.service-action-menu-divider {
height: 1rpx;
background-color: #E0E0E0;
margin: 0 16rpx;
}
.service-action-menu-mask {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: transparent;
z-index: 99;
}
.service-meta {
display: flex;
align-items: center;
margin-bottom: 16rpx;
}
.service-date {
font-size: 24rpx;
color: #999;
margin-right: 16rpx;
}
.service-duration {
font-size: 24rpx;
color: #999;
}
.service-content {
margin-bottom: 24rpx;
}
.service-desc {
font-size: 28rpx;
color: #666;
line-height: 1.6;
}
.service-customer {
display: flex;
align-items: center;
margin-bottom: 16rpx;
}
.customer-avatar {
width: 64rpx;
height: 64rpx;
background-color: #2196F3;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
margin-right: 16rpx;
}
.avatar-text {
font-size: 32rpx;
color: #FFFFFF;
font-weight: 500;
}
.customer-name {
font-size: 28rpx;
color: #333;
}
.ai-tag {
padding-top: 16rpx;
border-top: 1px solid #F0F0F0;
}
.ai-tag text {
font-size: 24rpx;
color: #999;
}
</style>