Browse Source

修改 bug

master
王泽彦 6 months ago
parent
commit
5bb437473b
  1. 31
      niucloud/app/service/api/apiService/PersonnelService.php
  2. 128
      niucloud/app/service/api/apiService/ResourceSharingService.php
  3. 2
      uniapp/common/config.js
  4. 1507
      uniapp/pages-market/clue/index.vue
  5. 174
      uniapp/pages/market/clue/index.vue

31
niucloud/app/service/api/apiService/PersonnelService.php

@ -925,22 +925,25 @@ class PersonnelService extends BaseApiService
try {
$where = [];
// 查询销售部门(dept_id=3)下的所有角色ID
$salesRoleIds = SysRole::where('dept_id', 3)
->where('status', 1)
// 排除的角色key列表
$excludeRoleKeys = ['teacher', 'market', 'market_manager', 'teacher_manager', 'superadmin', 'finance_role'];
// 查询除了排除角色外的所有角色ID
$roleIds = SysRole::where('status', 1)
->where('role_key', 'not in', $excludeRoleKeys)
->column('role_id');
if (empty($salesRoleIds)) {
if (empty($roleIds)) {
return [
'code' => 1,
'msg' => '暂无销售部门角色',
'msg' => '暂无符合条件的角色',
'data' => []
];
}
// 构建校区人员角色关系查询条件
$campusPersonWhere = [
['role_id', 'in', $salesRoleIds]
['role_id', 'in', $roleIds]
];
// 根据传入的校区进行筛选
@ -948,21 +951,21 @@ class PersonnelService extends BaseApiService
$campusPersonWhere[] = ['campus_id', '=', $campus];
}
// 查询符合条件的销售人员ID
$salesPersonIds = CampusPersonRole::where($campusPersonWhere)
// 查询符合条件的人员ID
$personIds = CampusPersonRole::where($campusPersonWhere)
->column('person_id');
if (empty($salesPersonIds)) {
if (empty($personIds)) {
return [
'code' => 1,
'msg' => '暂无销售人员数据',
'msg' => '暂无符合条件的人员数据',
'data' => []
];
}
// 从personnel表中获取人员信息,包含姓名和电话
$salesPersonnel = $this->model
->whereIn('id', $salesPersonIds)
$personnel = $this->model
->whereIn('id', $personIds)
->where('deleted_at', 0) // 只获取未删除的人员
->field('id, name, phone')
->order('create_time DESC')
@ -972,13 +975,13 @@ class PersonnelService extends BaseApiService
return [
'code' => 1,
'msg' => '获取成功',
'data' => $salesPersonnel
'data' => $personnel
];
} catch (\Exception $e) {
return [
'code' => 0,
'msg' => '获取销售人员列表失败:' . $e->getMessage(),
'msg' => '获取人员列表失败:' . $e->getMessage(),
'data' => []
];
}

128
niucloud/app/service/api/apiService/ResourceSharingService.php

@ -282,6 +282,19 @@ class ResourceSharingService extends BaseApiService
// 应用权限过滤
$model = $this->applyPermissionFilter($model, $permissions, $person_id, $shared_scope, $shared_by, $assignee_role_ids);
// 全部资源场景下,固定按最近一次分配记录去重
if ($shared_scope === 'all') {
$latestAssignmentSub = $this->assignmentModel
->alias('sub')
->field('MAX(id) as latest_id, resource_id')
->group('resource_id')
->buildSql();
$model = $model
->join([$latestAssignmentSub => 'latest'], 'ra.id = latest.latest_id')
->field('ra.*');
}
// 处理查询条件 - CustomerResources模型的字段
$resource_conditions = [];
@ -478,6 +491,28 @@ class ResourceSharingService extends BaseApiService
$resource_ids = array_column($list['data'], 'resource_id');
$resource_ids = array_unique(array_filter($resource_ids));
// 映射 legacy 表中的资源共享记录 ID,兼容旧接口依赖
$resource_sharing_map = [];
if (!empty($resource_ids)) {
$legacy_records = $this->model
->whereIn('resource_id', $resource_ids)
->order('id', 'desc')
->field('resource_id, id')
->select()
->toArray();
foreach ($legacy_records as $record) {
$resourceId = (int) ($record['resource_id'] ?? 0);
$recordId = (int) ($record['id'] ?? 0);
if ($resourceId === 0 || $recordId === 0) {
continue;
}
if (!isset($resource_sharing_map[$resourceId])) {
$resource_sharing_map[$resourceId] = $recordId;
}
}
}
// 获取分配人员ID列表
$shared_by_ids = array_column($list['data'], 'assigned_by');
$shared_by_ids = array_unique(array_filter($shared_by_ids));
@ -505,6 +540,45 @@ class ResourceSharingService extends BaseApiService
$consultant_names = $personnel->whereIn('id', $consultant_ids)->column('name', 'id');
}
// 查询销售老师信息(从资源分配表获取)
$sales_teachers = [];
if (!empty($resource_ids)) {
$assignment_model = new \app\model\resource_assignment\ResourceAssignment();
$assignments = $assignment_model
->whereIn('resource_id', $resource_ids)
->where('assignee_type', 'user')
->field('resource_id, assignee_id')
->select()
->toArray();
// 获取所有销售人员ID
$sales_teacher_ids = array_unique(array_column($assignments, 'assignee_id'));
$sales_teacher_names = [];
if (!empty($sales_teacher_ids)) {
$personnel = new \app\model\personnel\Personnel();
$sales_teacher_names = $personnel->whereIn('id', $sales_teacher_ids)->column('name', 'id');
}
// 按resource_id组织销售老师名称
foreach ($assignments as $assignment) {
$resource_id = $assignment['resource_id'];
$assignee_id = $assignment['assignee_id'];
$teacher_name = $sales_teacher_names[$assignee_id] ?? '';
if (!isset($sales_teachers[$resource_id])) {
$sales_teachers[$resource_id] = [];
}
if (!empty($teacher_name)) {
$sales_teachers[$resource_id][] = $teacher_name;
}
}
// 将数组转为字符串
foreach ($sales_teachers as $resource_id => &$teachers) {
$teachers = implode('、', array_unique($teachers));
}
}
// 查询最近沟通记录
$communication_times = [];
if (!empty($resource_ids)) {
@ -601,6 +675,10 @@ class ResourceSharingService extends BaseApiService
// 处理每条数据
foreach ($list['data'] as &$item) {
$resourceId = (int) ($item['resource_id'] ?? 0);
$legacyResourceSharingId = $resource_sharing_map[$resourceId] ?? null;
$item['resource_sharing_id'] = $legacyResourceSharingId;
if (!empty($item['customerResource'])) {
// 确保数据类型转换:数据库中的数值需要转换为字符串
$source_value = (string) $item['customerResource']['source'];
@ -611,12 +689,23 @@ class ResourceSharingService extends BaseApiService
$item['customerResource']['source_channel'] = get_dict_value('SourceChannel', $source_channel_value);
$item['customerResource']['campus_name'] = $campus_names[$item['customerResource']['campus']] ?? '';
if ($legacyResourceSharingId !== null) {
$item['customerResource']['resource_sharing_id'] = $legacyResourceSharingId;
}
if (!empty($item['customerResource']['consultant'])) {
$item['customerResource']['consultant_name'] = $consultant_names[$item['customerResource']['consultant']] ?? '';
} else {
$item['customerResource']['consultant_name'] = '';
}
// 添加市场老师字段(与consultant_name相同)
$item['customerResource']['market_teacher'] = $item['customerResource']['consultant_name'];
// 添加销售老师字段(从资源分配表获取的拼接字符串)
$resource_id = $item['resource_id'];
$item['customerResource']['sales_teacher'] = $sales_teachers[$resource_id] ?? '';
$item['customerResource']['communication_time'] = $communication_times[$item['resource_id']] ?? '';
$resource_id = $item['resource_id'];
@ -970,6 +1059,45 @@ class ResourceSharingService extends BaseApiService
$consultant_names = $personnel->whereIn('id', $consultant_ids)->column('name', 'id');
}
// 查询销售老师信息(从资源分配表获取)
$sales_teachers = [];
if (!empty($resource_ids)) {
$assignment_model = new \app\model\resource_assignment\ResourceAssignment();
$assignments = $assignment_model
->whereIn('resource_id', $resource_ids)
->where('assignee_type', 'user')
->field('resource_id, assignee_id')
->select()
->toArray();
// 获取所有销售人员ID
$sales_teacher_ids = array_unique(array_column($assignments, 'assignee_id'));
$sales_teacher_names = [];
if (!empty($sales_teacher_ids)) {
$personnel = new \app\model\personnel\Personnel();
$sales_teacher_names = $personnel->whereIn('id', $sales_teacher_ids)->column('name', 'id');
}
// 按resource_id组织销售老师名称
foreach ($assignments as $assignment) {
$resource_id = $assignment['resource_id'];
$assignee_id = $assignment['assignee_id'];
$teacher_name = $sales_teacher_names[$assignee_id] ?? '';
if (!isset($sales_teachers[$resource_id])) {
$sales_teachers[$resource_id] = [];
}
if (!empty($teacher_name)) {
$sales_teachers[$resource_id][] = $teacher_name;
}
}
// 将数组转为字符串
foreach ($sales_teachers as $resource_id => &$teachers) {
$teachers = implode('、', array_unique($teachers));
}
}
// 查询最近沟通记录
$communication_times = [];
if (!empty($resource_ids)) {

2
uniapp/common/config.js

@ -1,6 +1,6 @@
// 环境变量配置
// const env = 'development'
const env = 'development'
const env = 'prod'
const isMockEnabled = false // 默认禁用Mock优先模式,仅作为回退
const isDebug = false // 默认启用调试模式
const devurl = 'http://localhost:20080/api'

1507
uniapp/pages-market/clue/index.vue

File diff suppressed because it is too large

174
uniapp/pages/market/clue/index.vue

@ -1,4 +1,4 @@
<template>
<template>
<view class="assemble">
<fui-segmented-control :values="values" type="text" activeColor="#29d3b4" color="#fff"
@click="segmented"></fui-segmented-control>
@ -6,7 +6,7 @@
<!--我的客户-->
<scroll-view v-if="segmented_type == 1" scroll-y="true" :lower-threshold="lowerThreshold"
@scrolltolower="loadMoreData_1" style="height: 100vh;">
<!-- 搜索按钮区域 -->
<view class="search_section">
<view class="item">
@ -34,7 +34,7 @@
来源{{ v.customerResource.source }}
</view>
<view class="card-con">
来源渠道{{ v.customerResource.source_channel }}
来源渠道{{ v.customerResource.source_channel }}
</view>
</view>
<view class="card-right">
@ -186,7 +186,7 @@
<text class="close_text"></text>
</view>
</view>
<scroll-view :scroll-y="true" class="popup_scroll_view">
<!-- 第一筛选区域 -->
<view class="popup_filter_section">
@ -200,7 +200,7 @@
<input class="popup_filter_input" placeholder="姓名" v-model="searchForm.name" />
</view>
</view>
<view class="popup_filter_row">
<view class="popup_filter_item">
<text class="popup_filter_label">电话</text>
@ -213,7 +213,7 @@
</picker>
</view>
</view>
<view class="popup_filter_row" v-if="sourceIndex === 1">
<view class="popup_filter_item full_width">
<text class="popup_filter_label">来源渠道</text>
@ -221,7 +221,7 @@
</view>
</view>
</view>
<!-- 第二筛选区域 -->
<view class="popup_filter_section">
<view class="popup_filter_row">
@ -236,7 +236,7 @@
</picker>
</view>
</view>
<view class="popup_filter_row">
<view class="popup_filter_item">
<text class="popup_filter_label">成交类型</text>
@ -251,7 +251,7 @@
</picker>
</view>
</view>
<view class="popup_filter_row">
<view class="popup_filter_item">
<text class="popup_filter_label">沟通情况</text>
@ -268,7 +268,7 @@
</view>
</view>
</scroll-view>
<view class="popup_filter_buttons">
<view class="popup_filter_btn reset_btn" @click="resetSearchOnly">重置</view>
<view class="popup_filter_btn search_btn" @click="searchDataAndClose">搜索</view>
@ -355,7 +355,7 @@
lowerThreshold: 100, //
isReachedBottom: false, //|true=|false=
selectedDate: this.getCurrentDate(), //
//
showSearchPopup: false, //
tempHideSearchPopup: false, //
@ -372,7 +372,7 @@
communication_status: '',
time_range: ''
},
//
sourceIndex: 0,
sourceOptions: ['全部', '线上', '线下'],
@ -793,7 +793,7 @@
}
console.log('选中', e, select_item)
this.closeAssign() //
//
if (select_item.isBatch && select_item.selectedIds) {
//
@ -827,12 +827,12 @@
}, 1000)
}
},
//
async batchAssignResources(selectedIds, assigneeId) {
let successCount = 0
let failCount = 0
for (let resourceId of selectedIds) {
try {
let param = {
@ -849,7 +849,7 @@
failCount++
}
}
//
if (failCount === 0) {
uni.showToast({
@ -862,7 +862,7 @@
icon: 'none'
})
}
// 退
this.exitBatchMode()
setTimeout(() => {
@ -932,7 +932,7 @@
closeShowDrawer() {
this.showDrawer = false
},
//
//
openSearchPopup() {
@ -940,24 +940,24 @@
this.showSearchPopup = true
console.log('设置后的状态', this.showSearchPopup)
},
//
searchDataAndClose() {
console.log('执行搜索,表单数据:', this.searchForm)
this.searchDataFromPopup()
this.showSearchPopup = false
},
//
async searchDataFromPopup() {
//
const currentFilterData = this.segmented_type == 1 ? this.filteredData_1 : this.filteredData_2
//
currentFilterData.campus_name = this.searchForm.campus_name
currentFilterData.name = this.searchForm.name
currentFilterData.phone_number = this.searchForm.phone_number
// shared_at_arr
if (this.searchForm.time_range && this.searchForm.time_range.includes(' ~ ')) {
const timeArray = this.searchForm.time_range.split(' ~ ')
@ -967,7 +967,7 @@
currentFilterData.shared_at_arr = []
currentFilterData.shared_at_str = ''
}
//
if (this.searchForm.source && this.searchForm.source !== '全部') {
currentFilterData.source = this.searchForm.source
@ -984,9 +984,9 @@
if (this.searchForm.valid_type && this.searchForm.valid_type !== '全部') {
currentFilterData.valid_type = this.searchForm.valid_type
}
console.log('映射后的筛选数据:', currentFilterData)
//
if (this.segmented_type == 1) {
//
@ -998,23 +998,23 @@
await this.getList_2()
}
},
//
resetSearchAndClose() {
this.resetSearch()
this.showSearchPopup = false
},
//
resetSearchOnly() {
this.resetSearch()
},
//
closeSearchPopup() {
this.showSearchPopup = false
},
//
onSourceChange(e) {
this.sourceIndex = e.detail.value
@ -1024,31 +1024,31 @@
this.searchForm.source_channel = ''
}
},
//
onAttendanceChange(e) {
this.attendanceIndex = e.detail.value
this.searchForm.attendance_type = this.attendanceOptions[this.attendanceIndex]
},
//
onDealChange(e) {
this.dealIndex = e.detail.value
this.searchForm.deal_type = this.dealOptions[this.dealIndex]
},
//
onValidChange(e) {
this.validIndex = e.detail.value
this.searchForm.valid_type = this.validOptions[this.validIndex]
},
//
onCommunicationChange(e) {
this.communicationIndex = e.detail.value
this.searchForm.communication_status = this.communicationOptions[this.communicationIndex]
},
//
async resetSearch() {
this.searchForm = {
@ -1069,7 +1069,7 @@
this.dealIndex = 0
this.validIndex = 0
this.communicationIndex = 0
//
if (this.segmented_type == 1) {
//
@ -1081,17 +1081,17 @@
await this.getList_2()
}
},
//
getOrderStatusClass(status) {
return status === '已开单' ? 'status-closed' : 'status-open'
},
// 访
getVisitStatusClass(status) {
return status === '已到' ? 'visit-arrived' : 'visit-not-arrived'
},
//
//
enterBatchMode() {
@ -1099,14 +1099,14 @@
this.selectedItems = []
this.isAllSelected = false
},
// 退
exitBatchMode() {
this.batchMode = false
this.selectedItems = []
this.isAllSelected = false
},
//
toggleItemSelection(item) {
const index = this.selectedItems.indexOf(item.id)
@ -1117,7 +1117,7 @@
}
this.updateAllSelectedState()
},
//
toggleSelectAll() {
if (this.isAllSelected) {
@ -1128,12 +1128,12 @@
this.isAllSelected = true
}
},
//
updateAllSelectedState() {
this.isAllSelected = this.selectedItems.length === this.tableList_2.length && this.tableList_2.length > 0
},
//
batchAssign() {
if (this.selectedItems.length === 0) {
@ -1188,7 +1188,7 @@
}
}
}
//
.search_popup_mask {
position: fixed;
@ -1201,7 +1201,7 @@
display: flex;
flex-direction: column;
}
.search_popup_content {
background: #fff;
border-bottom-left-radius: 24rpx;
@ -1213,7 +1213,7 @@
display: flex;
flex-direction: column;
}
@keyframes slideDown {
from {
transform: translateY(-100%);
@ -1222,7 +1222,7 @@
transform: translateY(0);
}
}
//
.popup_search_content {
padding: 0;
@ -1235,7 +1235,7 @@
border-bottom-right-radius: 24rpx;
overflow: hidden;
}
.popup_header {
display: flex;
justify-content: space-between;
@ -1243,66 +1243,66 @@
padding: 32rpx;
border-bottom: 1px solid #f0f0f0;
}
.popup_title {
font-size: 32rpx;
font-weight: 600;
color: #333;
}
.popup_close {
width: 60rpx;
height: 60rpx;
display: flex;
align-items: center;
justify-content: center;
.close_text {
font-size: 32rpx;
color: #999;
}
}
.popup_scroll_view {
flex: 1;
padding: 32rpx;
overflow-y: auto;
}
.popup_filter_section {
margin-bottom: 32rpx;
&:last-child {
margin-bottom: 0;
}
}
.popup_filter_row {
display: flex;
gap: 20rpx;
margin-bottom: 24rpx;
&:last-child {
margin-bottom: 0;
}
}
.popup_filter_item {
flex: 1;
display: flex;
flex-direction: column;
gap: 12rpx;
&.full_width {
flex: 1;
}
.popup_filter_label {
font-size: 26rpx;
color: #666;
font-weight: 500;
}
.popup_filter_input {
height: 72rpx;
line-height: 72rpx;
@ -1312,12 +1312,12 @@
font-size: 28rpx;
color: #333;
background: #fff;
&::placeholder {
color: #999;
}
}
.popup_filter_picker {
height: 72rpx;
line-height: 72rpx;
@ -1328,7 +1328,7 @@
color: #333;
background: #fff;
position: relative;
&::after {
content: '▼';
position: absolute;
@ -1338,7 +1338,7 @@
}
}
}
.popup_filter_buttons {
display: flex;
gap: 20rpx;
@ -1349,7 +1349,7 @@
border-bottom-left-radius: 24rpx;
border-bottom-right-radius: 24rpx;
}
.popup_filter_btn {
flex: 1;
height: 72rpx;
@ -1358,18 +1358,18 @@
border-radius: 8rpx;
font-size: 28rpx;
font-weight: 600;
&.search_btn {
background: #29d3b4;
color: #fff;
}
&.reset_btn {
background: #f5f5f5;
color: #666;
border: 1px solid #ddd;
}
&.close_btn {
background: #666;
color: #fff;
@ -1408,16 +1408,16 @@
border-radius: 16rpx;
display: flex;
flex-direction: column;
.card-content {
display: flex;
justify-content: space-between;
.card-left {
flex: 1;
padding-right: 10rpx;
}
.card-right {
min-width: 120rpx;
display: flex;
@ -1425,7 +1425,7 @@
align-items: center;
justify-content: flex-start;
padding: 12rpx;
//
.status-tag {
font-size: 20rpx;
@ -1435,23 +1435,23 @@
margin-bottom: 8rpx;
text-align: center;
min-width: 60rpx;
&.status-closed {
background-color: #52c41a; // 绿-
}
&.status-open {
background-color: #ff4d4f; // -
}
}
// 访
.visit-status {
display: flex;
flex-direction: column;
gap: 6rpx;
margin-bottom: 12rpx;
.visit-tag {
font-size: 18rpx;
padding: 6rpx 12rpx;
@ -1459,17 +1459,17 @@
color: #fff;
text-align: center;
min-width: 60rpx;
&.visit-arrived {
background-color: #1890ff; // -
}
&.visit-not-arrived {
background-color: #8c8c8c; // -
}
}
}
.btn-item {
margin-bottom: 12rpx;
display: flex;
@ -1479,11 +1479,11 @@
height: 80rpx;
background-color: rgba(255, 255, 255, 0.1);
border-radius: 50%;
&:last-child {
margin-bottom: 0;
}
.image {
width: 60rpx;
height: 60rpx;
@ -1491,7 +1491,7 @@
}
}
}
.card-footer {
width: 100%;
border-top: 1rpx solid rgba(255, 255, 255, 0.1);
@ -1672,7 +1672,7 @@
color: #fff;
box-shadow: 0 4rpx 12rpx rgba(41, 211, 180, 0.3);
transition: all 0.3s ease;
&.cancel {
background: linear-gradient(135deg, #666, #555);
box-shadow: 0 4rpx 12rpx rgba(102, 102, 102, 0.3);
@ -1698,7 +1698,7 @@
color: transparent;
background: #404040;
transition: all 0.3s ease;
&.checked {
background: linear-gradient(135deg, #29d3b4, #26c3a4);
border-color: #29d3b4;
@ -1737,13 +1737,13 @@
/* 分配状态样式 */
.assigned-to {
font-weight: 600;
&.unassigned {
color: #ff6b35;
}
&.assigned {
color: #29d3b4;
}
}
</style>
</style>

Loading…
Cancel
Save