沐梦. vor 3 Wochen
Ursprung
Commit
0c8246566a

+ 71 - 23
src/views/common/businessActivity.vue

@@ -16,7 +16,7 @@
             clearable
           />
           <div v-if="filteredTeam.length" class="team-list">
-            <div v-for="item in filteredTeam" :key="item.id" class="team-item">
+            <div v-for="(item, index) in filteredTeam" :key="item.id" class="team-item">
               <el-avatar :size="36" :src="item.avatar" class="user-avatar">
                 <img v-if="item.avatar" :src="item.avatar" />
                 <el-icon v-else><User /></el-icon>
@@ -25,8 +25,8 @@
                 <div class="user-main">
                   <span class="user-name">{{ item.realName || item.userName || '成员' }}</span>
                   <div class="user-tags">
-                    <span v-if="item.izManager === 1" class="leader-tag-simple">负责人</span>
-                    <span class="user-role-text">{{ item.roleName || '业务负责人' }}</span>
+                    <span v-if="item.izManager === 1 || index === 0" class="leader-tag-simple">负责人</span>
+                    <span class="user-role-text">{{ item.roleName }}</span>
                     <span class="permission-text-simple">{{ item.updateAccredit === 1 ? '修改权限' : '仅查看' }}</span>
                   </div>
                 </div>
@@ -57,8 +57,8 @@
             </div>
           </div>
           
-          <div v-if="recordList.length" class="record-list">
-            <div v-for="(record, index) in recordList" :key="index" class="record-item">
+          <div v-if="filteredRecords.length" class="record-list">
+            <div v-for="(record, index) in filteredRecords" :key="index" class="record-item">
                  <div class="record-card">
                    <div class="record-header">
                      <span class="record-user">{{ getRecordUser(record) }}</span>
@@ -97,15 +97,10 @@
             <div v-for="log in logList" :key="log.id" class="log-row">
               <span class="log-time">{{ log.operTime || log.time }}</span>
               <span class="log-user">{{ log.operName || log.userName }}</span>
-              <span class="log-content" :class="{ 'link-style': log.isLink }">
-                {{ 
-                  (log.operAction === 1 ? '创建了 ' : 
-                   log.operAction === 2 ? '编辑了 : ' : 
-                   log.operAction === 3 ? '删除了 ' : '') + 
-                  (log.operContent || log.content || '执行了操作')
-                }}
+              <span class="log-content">
+                {{ formatLogContent(log) }}{{ (log.subContent || log.operAction) ? ':' : '' }}
               </span>
-              <span v-if="log.subContent" class="log-sub-content" :class="{ 'link-style': log.subIsLink }">{{ log.subContent }}</span>
+              <span v-if="log.subContent" class="log-sub-content blue-style">{{ log.subContent }}</span>
             </div>
           </div>
           <div v-else class="empty-status">暂无操作日志</div>
@@ -294,11 +289,12 @@
         </el-form-item>
 
         <el-form-item label="权限:">
-          <el-radio-group v-if="isEditMember" v-model="memberForm.updateAccredit">
-            <el-radio :label="0">仅查看</el-radio>
-            <el-radio :label="1">修改权限</el-radio>
-          </el-radio-group>
-          <el-checkbox v-else v-model="memberForm.updateAccredit" :true-value="1" :false-value="0">分配修改权限</el-checkbox>
+          <div class="member-form">
+            <el-radio-group v-model="memberForm.updateAccredit">
+              <el-radio :label="0">仅查看</el-radio>
+              <el-radio :label="1">修改权限</el-radio>
+            </el-radio-group>
+          </div>
         </el-form-item>
       </el-form>
 
@@ -319,7 +315,7 @@ import { listTeamMember, delTeamMember, addTeamMember, updateTeamMember } from "
 import { listRecord, addRecord } from "@/api/visit/record";
 import { listOperateLog } from "@/api/visit/operateLog";
 import { listUser } from "@/api/system/user/index";
-import { selectStaffOptionList } from "@/api/customer/crmStaff";
+import { listComStaff } from "@/api/system/comStaff/index";
 import { globalHeaders } from "@/utils/request";
 
 const proxy = getCurrentInstance().proxy;
@@ -389,6 +385,7 @@ const memberForm = reactive({
   realName: '',
   roleCode: '',
   updateAccredit: 0,
+  izManager: 0,
   objectNo: ''
 });
 
@@ -401,6 +398,14 @@ const filteredTeam = computed(() => {
   return teamList.value.filter(m => (m.realName || '').includes(memberSearch.value));
 });
 
+const filteredRecords = computed(() => {
+  return recordList.value.filter(record => {
+    const no = String(record.recordsNo || record.scheduleNo || '');
+    // 如果没有编号,默认显示(可能是脏数据),如果有编号,则要求是纯数字
+    return !no || /^\d+$/.test(no);
+  });
+});
+
 // 统一计算当前业务的数据类型
 const computedDataType = computed(() => {
   const typeMap = {
@@ -494,8 +499,8 @@ const loadUsers = async () => {
 };
 
 const loadStaffs = async () => {
-  selectStaffOptionList().then(res => {
-    staffOptions.value = res.data || [];
+  listComStaff({ pageSize: 1000 }).then(res => {
+    staffOptions.value = res.rows || res.data || [];
   });
 };
 
@@ -520,6 +525,7 @@ const handleAddMember = () => {
     realName: '',
     roleCode: '',
     updateAccredit: 0,
+    izManager: 0,
     objectNo: computedObjectNo.value,
     dataType: computedDataType.value
   });
@@ -534,6 +540,7 @@ const handleEditMember = (item) => {
     realName: item.realName,
     roleCode: item.roleCode,
     updateAccredit: item.updateAccredit || 0,
+    izManager: item.izManager || 0,
     objectNo: computedObjectNo.value,
     dataType: computedDataType.value
   });
@@ -679,6 +686,47 @@ const getRecordUser = (record) => {
 };
 
 
+// 格式化日志内容,移除“了”字并避免重复
+const formatLogContent = (log) => {
+  const actionMap = {
+    1: '添加',
+    2: '编辑',
+    3: '删除'
+  };
+  
+  const prefix = actionMap[log.operAction];
+  let content = (log.operContent || log.content || '执行操作').trim();
+  
+  // 移除开头可能存在的冒号
+  content = content.replace(/^[::\s]+/, '');
+
+  if (prefix) {
+    // 定义常见同义词(包含带“了”和不带“了”的情况)
+    const synonyms = {
+      '添加': ['创建了', '创建', '新增了', '新增', '添加了', '添加', '录入了', '录入'],
+      '编辑': ['编辑了', '编辑', '修改了', '修改', '更新了', '更新', '完善了', '完善'],
+      '删除': ['删除了', '删除', '移除了', '移除']
+    };
+    
+    const currentSynonyms = synonyms[prefix] || [prefix];
+    // 优先匹配长度较长的词(如“修改了”优先于“修改”)
+    currentSynonyms.sort((a, b) => b.length - a.length);
+    
+    for (const syn of currentSynonyms) {
+      if (content.startsWith(syn)) {
+        const rest = content.substring(syn.length).trim().replace(/^[::\s]+/, '');
+        return rest ? `${prefix} ${rest}` : prefix;
+      }
+    }
+    
+    return `${prefix} ${content}`;
+  }
+
+  // 对于其他没有 action 映射的内容,也尝试移除“了”
+  return content.replace('了', '');
+};
+
+
 onMounted(() => {
   loadUsers();
   loadStaffs();
@@ -842,9 +890,9 @@ onMounted(() => {
     }
   }
 }
-.log-list-new { .log-row { font-size: 13px; line-height: 2.2; color: #666; display: flex; flex-wrap: wrap; align-items: center; .log-time { color: #999; margin-right: 12px; width: 140px; } .log-user { color: #409eff; margin-right: 8px; cursor: pointer; } .link-style { color: #409eff; cursor: pointer; &:hover { text-decoration: underline; } } } }
+.log-list-new { .log-row { font-size: 13px; line-height: 2.2; color: #666; display: flex; flex-wrap: wrap; align-items: center; .log-time { color: #999; margin-right: 15px; width: 140px; } .log-user { color: #409eff; margin-right: 12px; cursor: pointer; } .log-content { color: #666; margin-right: 4px; } .blue-style { color: #409eff; cursor: pointer; } .link-style { color: #409eff; cursor: pointer; &:hover { text-decoration: underline; } } } }
 .manage-info-list { padding-top: 10px; .m-item { display: flex; align-items: center; margin-bottom: 20px; font-size: 13px; .m-label { color: #999; width: 80px; } .m-value { color: #333; } } }
 .image-uploader { .uploader-icon { font-size: 28px; color: #8c939d; width: 80px; height: 80px; text-align: center; line-height: 80px; border: 1px dashed #d9d9d9; border-radius: 4px; } .uploaded-image { width: 80px; height: 80px; display: block; border-radius: 4px; object-fit: cover; } }
-.link-style { color: #409eff; cursor: pointer; }
+.link-style, .blue-style { color: #409eff; cursor: pointer; }
 .empty-status { text-align: center; color: #999; font-size: 13px; padding: 60px 0; }
 </style>

+ 2 - 2
src/views/customer/care/add.vue

@@ -167,7 +167,7 @@ import { addCare } from "@/api/customer/crmCare";
 import { listCustomerInfo, getCustomerInfo } from "@/api/customer/customerInfo/";
 import { listContact } from "@/api/customer/crmContact";
 import { listIndustryCategory } from "@/api/customer/industryCategory";
-import { selectStaffOptionList } from "@/api/customer/crmStaff";
+import { listComStaff } from "@/api/system/comStaff/index";
 import { deptTreeSelect } from "@/api/system/user/index";
 
 const proxy = getCurrentInstance().proxy;
@@ -341,7 +341,7 @@ function handleClose() {
 /** 加载基础选项 */
 const initBaseOptions = () => {
   listIndustryCategory().then(res => { industryOptions.value = res.data || []; });
-  selectStaffOptionList().then(res => { staffOptions.value = res.data || []; });
+  listComStaff({ pageSize: 1000 }).then(res => { staffOptions.value = res.rows || res.data || []; });
   deptTreeSelect().then(res => {
     const data = res.data || [];
     deptOptions.value = proxy.handleTree(data, "id");

+ 2 - 2
src/views/customer/care/detail.vue

@@ -161,7 +161,7 @@
 import { ref, onMounted, getCurrentInstance, toRefs } from 'vue';
 import { Close } from '@element-plus/icons-vue';
 import { getCare } from "@/api/customer/crmCare";
-import { selectStaffOptionList } from "@/api/customer/crmStaff";
+import { listComStaff } from "@/api/system/comStaff/index";
 import { deptTreeSelect } from "@/api/system/user/index";
 import BusinessActivity from '../../common/businessActivity.vue';
 
@@ -245,7 +245,7 @@ const getStaffName = (staffId) => {
 
 /** 加载基础选项 */
 const initBaseOptions = () => {
-  selectStaffOptionList().then(res => { staffOptions.value = res.data || []; });
+  listComStaff({ pageSize: 1000 }).then(res => { staffOptions.value = res.rows || res.data || []; });
   deptTreeSelect().then(res => {
     const data = res.data || [];
     deptOptions.value = proxy.handleTree(data, "id");

+ 2 - 2
src/views/customer/care/edit.vue

@@ -155,7 +155,7 @@ import { getCare, updateCare } from "@/api/customer/crmCare";
 import { listCustomerInfo, getCustomerInfo } from "@/api/customer/customerInfo/";
 import { listContact } from "@/api/customer/crmContact";
 import { listIndustryCategory } from "@/api/customer/industryCategory";
-import { selectStaffOptionList } from "@/api/customer/crmStaff";
+import { listComStaff } from "@/api/system/comStaff/index";
 import { deptTreeSelect } from "@/api/system/user/index";
 
 const proxy = getCurrentInstance().proxy;
@@ -322,7 +322,7 @@ function handleClose(refresh = false) {
 /** 加载基础选项 */
 const initBaseOptions = () => {
   listIndustryCategory().then(res => { industryOptions.value = res.data || []; });
-  selectStaffOptionList().then(res => { staffOptions.value = res.data || []; });
+  listComStaff({ pageSize: 1000 }).then(res => { staffOptions.value = res.rows || res.data || []; });
   deptTreeSelect().then(res => {
     const data = res.data || [];
     deptOptions.value = proxy.handleTree(data, "id");

+ 3 - 3
src/views/customer/care/index.vue

@@ -169,7 +169,7 @@ import { useRouter, useRoute } from 'vue-router';
 import { Setting, User } from '@element-plus/icons-vue';
 import { listCare, delCare, getCare } from "@/api/customer/crmCare";
 import { listContact } from "@/api/customer/crmContact";
-import { selectStaffOptionList } from "@/api/customer/crmStaff";
+import { listComStaff } from "@/api/system/comStaff/index";
 import CareDetail from './detail.vue';
 import CareAdd from './add.vue';
 
@@ -284,8 +284,8 @@ const getStaffName = (staffId) => {
 
 /** 加载员工列表 */
 const loadStaffOptions = () => {
-  selectStaffOptionList().then(res => {
-    staffOptions.value = res.data || [];
+  listComStaff({ pageSize: 1000 }).then(res => {
+    staffOptions.value = res.rows || res.data || [];
   });
 };
 

+ 2 - 2
src/views/customer/highseas/edit.vue

@@ -260,7 +260,7 @@
 <script setup>
 import { ref, reactive, onMounted, getCurrentInstance, isRef } from 'vue';
 import { getCustomerInfo, updateCustomerInfo, listCompanyOption, listLevelOption } from "@/api/customer/customerInfo";
-import { selectStaffOptionList } from "@/api/customer/crmStaff";
+import { listComStaff } from "@/api/system/comStaff/index";
 import { listProvinceWithCities } from "@/api/customer/addressArea";
 import ImageUpload from "@/components/ImageUpload";
 
@@ -494,7 +494,7 @@ const handleSubmit = () => {
 onMounted(() => {
   listCompanyOption().then(res => companyOptions.value = res.data || []);
   listLevelOption().then(res => levelOptions.value = res.data || []);
-  selectStaffOptionList().then(res => staffOptions.value = res.data || []);
+  listComStaff({ pageSize: 1000 }).then(res => staffOptions.value = res.rows || res.data || []);
   listProvinceWithCities().then(res => areaOptions.value = res.data || []);
 });
 

+ 3 - 3
src/views/customer/highseas/index.vue

@@ -156,7 +156,7 @@ import { useRouter } from 'vue-router';
 import { listPool, claimPool } from "@/api/customer/customerPool";
 import { listIndustryCategory } from "@/api/customer/industryCategory";
 import { listLevel } from "@/api/customer/customerLevel";
-import { selectStaffOptionList } from "@/api/customer/crmStaff";
+import { listComStaff } from "@/api/system/comStaff/index";
 import { debounce } from 'lodash-es';
 import CustomerDetail from "./detail.vue";
 
@@ -219,8 +219,8 @@ const getOptions = async () => {
     const levelRes = await listLevel();
     levelOptions.value = levelRes.rows || [];
     
-    const staffRes = await selectStaffOptionList();
-    staffOptions.value = staffRes.data || [];
+    const staffRes = await listComStaff({ pageSize: 1000 });
+    staffOptions.value = staffRes.rows || staffRes.data || [];
   } catch (err) {
     console.error('获取选项失败:', err);
   }

+ 2 - 2
src/views/customer/valid/edit.vue

@@ -273,7 +273,7 @@ import { useRoute, useRouter } from 'vue-router';
 import { listCompanyOption, getCustomerInfo, updateCustomerInfo } from "@/api/customer/customerInfo/index";
 import { listIndustryCategory } from "@/api/customer/industryCategory";
 import { listLevel } from "@/api/customer/customerLevel";
-import { selectStaffOptionList } from "@/api/customer/crmStaff";
+import { listComStaff } from "@/api/system/comStaff/index";
 import { listCustomerTypeOption } from "@/api/customer/customerDict";
 import { listEnterpriseScale } from "@/api/customer/enterpriseScale";
 import { listProvinceWithCities } from "@/api/customer/addressArea";
@@ -353,7 +353,7 @@ const initOptions = async () => {
   listCompanyOption().then(res => companyOptions.value = res.data || []).catch(e => console.error("公司选项接口404或出错", e));
   listIndustryCategory().then(res => industryOptions.value = res.data || []).catch(e => console.error("行业类别接口404或出错", e));
   listLevel().then(res => levelOptions.value = res.rows || []).catch(e => console.error("客户等级接口404或出错", e));
-  selectStaffOptionList().then(res => staffOptions.value = res.data || []).catch(e => console.error("员工选项接口404或出错", e));
+  listComStaff({ pageSize: 1000 }).then(res => staffOptions.value = res.rows || res.data || []).catch(e => console.error("员工选项接口404或出错", e));
   listEnterpriseScale().then(res => scaleOptions.value = res.data || []).catch(e => console.error("企业规模接口404或出错", e));
   listCustomerTypeOption().then(res => {
     categoryOptions.value = res.data || res.rows || [];

+ 2 - 2
src/views/customer/valid/index.vue

@@ -179,7 +179,7 @@ import { useRouter } from 'vue-router';
 import { listValidCustomer, releaseToPool, listCompanyOption, transferSalesPerson, transferServiceStaff } from "@/api/customer/customerInfo/index";
 import { listIndustryCategory } from "@/api/customer/industryCategory";
 import { listLevel } from "@/api/customer/customerLevel";
-import { selectStaffOptionList } from "@/api/customer/crmStaff";
+import { listComStaff } from "@/api/system/comStaff/index";
 import { debounce } from 'lodash-es';
 import CustomerDetail from "./detail.vue";
 
@@ -340,7 +340,7 @@ const initOptions = async () => {
   listCompanyOption().then(res => companyOptions.value = res.data || []);
   listIndustryCategory().then(res => industryOptions.value = res.data || []);
   listLevel().then(res => levelOptions.value = res.rows || []);
-  selectStaffOptionList().then(res => staffOptions.value = res.data || []);
+  listComStaff({ pageSize: 1000 }).then(res => staffOptions.value = res.rows || res.data || []);
 };
 
 onMounted(() => {

+ 3 - 3
src/views/saleManage/accountsReceivable/index.vue

@@ -180,7 +180,7 @@
 <script setup name="AccountsReceivable">
 import { ref, reactive, onMounted, getCurrentInstance } from 'vue';
 import { listAccountsReceivable, addAccountsReceivable, updateAccountsReceivable, delAccountsReceivable } from '@/api/saleManage/accountsReceivable/index';
-import { selectStaffOptionList } from "@/api/system/comStaff/index";
+import { listComStaff } from "@/api/system/comStaff/index";
 
 const proxy = getCurrentInstance().proxy;
 
@@ -313,8 +313,8 @@ const handleDelete = (row) => {
 
 /** 获取用户列表 */
 const getUserList = () => {
-  selectStaffOptionList().then(res => {
-    userOptions.value = res.data || [];
+  listComStaff({ pageSize: 1000 }).then(res => {
+    userOptions.value = res.rows || res.data || [];
   });
 };
 

+ 7 - 0
src/views/saleManage/leads/add.vue

@@ -332,6 +332,13 @@ const handleLeaderChange = (id) => {
   }
 };
 
+const handleProductSupportChange = (id) => {
+  const staff = props.userOptions.find(i => i.staffId === id);
+  if (staff) {
+    form.productSupportName = staff.staffName;
+  }
+};
+
 const handleUploadSuccess = (res) => {
   if (res.code === 200) {
     fileList.value.push({ name: res.data.fileName, url: res.data.url, ossId: res.data.ossId, type: res.data.fileName.split('.').pop().toUpperCase(), uploadTime: proxy.parseTime(new Date()) });

+ 13 - 1
src/views/saleManage/leads/detail.vue

@@ -58,6 +58,11 @@
                 <div class="info-item"><span class="info-label">项目状态</span><span class="info-value"><dict-tag :options="saleStatusOptions" :value="form.status" /></span></div>
                 <div class="info-item"></div>
               </div>
+              <div class="info-grid">
+                <div class="info-item"><span class="info-label">项目负责人</span><span class="info-value">{{ form.leaderName || findUserName(form.leader) }}</span></div>
+                <div class="info-item"><span class="info-label">产品支持</span><span class="info-value">{{ form.productSupportName || findUserName(form.productSupport) }}</span></div>
+                <div class="info-item"></div>
+              </div>
             </div>
 
             <div class="info-section">
@@ -526,7 +531,8 @@ const props = defineProps({
   industryOptions: Array,
   projectLevelOptions: Array,
   procurementMethodOptions: Array,
-  infoSourceOptions: Array
+  infoSourceOptions: Array,
+  userOptions: Array
 });
 
 const emit = defineEmits(['update:modelValue', 'edit']);
@@ -605,6 +611,12 @@ const getDetail = (id) => {
   });
 };
 
+const findUserName = (id) => {
+  if (!id) return '';
+  const user = (props.userOptions || []).find(u => String(u.staffId || u.userId) === String(id));
+  return user ? (user.staffName || user.nickName) : id;
+};
+
 const loadProjectContacts = () => {
   if (!form.value.id) return;
   contactLoading.value = true;

+ 42 - 7
src/views/saleManage/leads/index.vue

@@ -161,10 +161,18 @@
         </el-table-column>
 
         <!-- 10. 项目负责人 -->
-        <el-table-column label="项目负责人" align="center" prop="leaderName" width="110" />
-
+        <el-table-column label="项目负责人" align="center" prop="leaderName" width="110">
+          <template #default="scope">
+            <span>{{ scope.row.leaderName || findUserName(scope.row.leader) }}</span>
+          </template>
+        </el-table-column>
+        
         <!-- 11. 产品支持 -->
-        <el-table-column label="产品支持" align="center" prop="productSupportName" width="110" />
+        <el-table-column label="产品支持" align="center" prop="productSupportName" width="110">
+          <template #default="scope">
+            <span>{{ scope.row.productSupportName || findUserName(scope.row.productSupport) }}</span>
+          </template>
+        </el-table-column>
 
         <!-- 12. 创建时间 -->
         <el-table-column label="创建时间" align="center" prop="createTime" width="110">
@@ -239,6 +247,7 @@
       :project-level-options="projectLevelOptions"
       :procurement-method-options="procurementMethodOptions"
       :info-source-options="infoSourceOptions"
+      :user-options="userOptions"
       @edit="onDetailEdit"
     />
 
@@ -270,6 +279,7 @@
             <el-option v-for="item in computedClaimUserOptions" :key="item.staffId" :label="item.staffName" :value="item.staffId" />
           </el-select>
         </el-form-item>
+
         <el-form-item label="保留已有项目负责人" required>
           <el-radio-group v-model="claimForm.keepOldManager">
             <el-radio :value="true">是</el-radio>
@@ -294,7 +304,7 @@
 <script setup name="SalesLeads">
 import { ref, reactive, onMounted, computed, getCurrentInstance, toRefs } from 'vue';
 import { listLeads, delLeads, transferLeads, claimLeads } from '@/api/saleManage/leads/index';
-import { selectStaffOptionList } from "@/api/system/comStaff/index";
+import { listComStaff } from "@/api/system/comStaff/index";
 import { listCompanyOption, listCustomerOption } from "@/api/customer/customerInfo/index";
 import { listIndustryCategory } from "@/api/customer/industryCategory";
 import { deptTreeSelect } from "@/api/system/user";
@@ -403,7 +413,10 @@ onMounted(() => {
 
 const getDicts = () => {
   listCompanyOption().then(res => companyOptions.value = res.data.map(i => ({ ...i, companyCode: String(i.companyCode) })));
-  selectStaffOptionList().then(res => userOptions.value = res.data.map(i => ({ ...i, staffId: String(i.staffId) })));
+  listComStaff({ pageSize: 1000 }).then(res => {
+    const list = res.rows || res.data || [];
+    userOptions.value = list.map(i => ({ ...i, staffId: String(i.staffId) }));
+  });
   listIndustryCategory().then(res => industryOptions.value = res.data);
   deptTreeSelect().then(res => deptOptions.value = res.data);
 };
@@ -497,14 +510,36 @@ const submitClaim = () => {
     proxy.$modal.msgError("请选择项目负责人");
     return;
   }
-  // 【关键修复】从计算属性(包含临时合成项)中查找姓名,确保 leaderName 不为空
   const leaderName = computedClaimUserOptions.value.find(i => String(i.staffId) === String(claimForm.leader))?.staffName;
-  claimLeads({ ...claimForm, leaderName }).then(() => {
+  const params = {
+    ...claimForm,
+    leaderName,
+    // 兼容性字段补全
+    leaderId: claimForm.leader,
+    managerId: claimForm.leader,
+    salesPersonId: claimForm.leader, // 增加备选名
+    clueIds: claimForm.ids,
+    idList: claimForm.ids,
+    // 如果是单条认领,带上单条 id
+    id: claimForm.ids.length === 1 ? claimForm.ids[0] : undefined,
+    clueId: claimForm.ids.length === 1 ? claimForm.ids[0] : undefined,
+    // 转换布尔值为数值型或字符串,Ruoyi 后端通常接收 0/1 或 '0'/'1'
+    keepOldManager: claimForm.keepOldManager ? 1 : 0,
+    keepOwner: claimForm.keepOldManager ? '1' : '0'
+  };
+  
+  claimLeads(params).then(() => {
     proxy.$modal.msgSuccess("认领成功");
     claimOpen.value = false;
     getList();
   });
 };
+
+const findUserName = (id) => {
+  if (!id) return '';
+  const user = userOptions.value.find(u => String(u.staffId || u.userId) === String(id));
+  return user ? (user.staffName || user.nickName) : id;
+};
 </script>
 
 <style scoped lang="scss">

+ 24 - 2
src/views/saleManage/opportunity/detail.vue

@@ -57,7 +57,12 @@
                   <el-descriptions-item label="截止时间:">{{ proxy.parseTime(detailData.expectedCompletionTime, '{y}-{m}-{d}') }}</el-descriptions-item>
                   
                   <el-descriptions-item label="项目状态:">{{ getSaleStatusLabel(detailData.status) }}</el-descriptions-item>
-                  <el-descriptions-item label="营销活动:" :span="2">{{ detailData.marketingActivityName || detailData.activityNo }}</el-descriptions-item>
+                  <el-descriptions-item label="营销活动:">{{ detailData.marketingActivityName || detailData.activityNo }}</el-descriptions-item>
+                  <el-descriptions-item label=" "></el-descriptions-item>
+
+                  <el-descriptions-item label="项目负责人:">{{ detailData.leaderName || findUserName(detailData.leader) }}</el-descriptions-item>
+                  <el-descriptions-item label="产品支持:">{{ detailData.productSupportName || findUserName(detailData.productSupport) }}</el-descriptions-item>
+                  <el-descriptions-item label=" "></el-descriptions-item>
                 </el-descriptions>
               </div>
 
@@ -434,7 +439,8 @@ const props = defineProps({
   saleStatusOptions: { type: Array, default: () => [] },
   projectLevelOptions: { type: Array, default: () => [] },
   infoSourceOptions: { type: Array, default: () => [] },
-  procurementMethodOptions: { type: Array, default: () => [] }
+  procurementMethodOptions: { type: Array, default: () => [] },
+  userOptions: { type: Array, default: () => [] }
 });
 
 const emit = defineEmits(['update:modelValue', 'edit', 'success']);
@@ -452,6 +458,14 @@ const leftActiveTab = ref('info');
 const industryOptions = ref([]);
 const proxy = getCurrentInstance().proxy;
 
+
+
+const findUserName = (id) => {
+  if (!id) return '';
+  const user = props.userOptions.find(u => String(u.staffId || u.userId) === String(id));
+  return user ? (user.staffName || user.nickName) : id;
+};
+
 // 状态同步
 watch(() => props.modelValue, (val) => { visible.value = val; });
 watch(() => visible.value, (val) => { emit('update:modelValue', val); });
@@ -859,6 +873,14 @@ const findProcurementMethodName = (method) => {
 };
 
 const findIndustryName = (val) => {
+  if (!val) return '';
+  // 处理可能的多个 ID(以逗号分隔)
+  const ids = String(val).split(',').filter(Boolean);
+  if (ids.length > 1) {
+    return ids.map(id => {
+      return industryOptions.value.find(i => String(i.id) === String(id))?.industryCategoryName || id;
+    }).join('、');
+  }
   return industryOptions.value.find(i => String(i.id) === String(val))?.industryCategoryName || val;
 };
 

+ 14 - 3
src/views/saleManage/opportunity/index.vue

@@ -155,7 +155,11 @@
             <span>{{ findUserName(row.leader) }}</span>
           </template>
         </el-table-column>
-        <el-table-column label="产品支持" align="center" prop="productSupportName" min-width="100" />
+        <el-table-column label="产品支持" align="center" prop="productSupportName" min-width="100">
+          <template #default="{ row }">
+            <span>{{ row.productSupportName || findUserName(row.productSupport) }}</span>
+          </template>
+        </el-table-column>
         <el-table-column label="创建时间" align="center" prop="createTime" width="110">
           <template #default="scope">
             <span>{{ parseTime(scope.row.createTime, '{y}-{m}-{d}') }}</span>
@@ -304,7 +308,7 @@
 import { ref, reactive, onMounted, getCurrentInstance, toRefs } from 'vue';
 import { useDebounceFn } from '@vueuse/core';
 import { listOpportunity, delOpportunity, transferOpportunity } from '@/api/saleManage/opportunity/index';
-import { selectStaffOptionList } from "@/api/system/comStaff/index";
+import { listComStaff } from "@/api/system/comStaff/index";
 import { listCompanyOption, listCustomerOption } from "@/api/customer/customerInfo/index";
 import { listDept } from "@/api/system/dept/index";
 import { listIndustryCategory } from "@/api/customer/industryCategory";
@@ -547,11 +551,18 @@ const findProjectLevelName = (id) => {
 
 /* ========== 加载选项列表 ========== */
 function getCompanyList() { listCompanyOption().then(r => companyOptions.value = r.data); }
-function getUserList() { selectStaffOptionList().then(r => userOptions.value = r.data); }
+function getUserList() { listComStaff({ pageSize: 1000 }).then(r => userOptions.value = r.rows || r.data || []); }
 function getDeptList() { listDept().then(r => deptOptions.value = proxy.handleTree(r.data, 'deptId')); }
 
 const findIndustryName = (val) => {
   if (!val) return '';
+  // 处理可能的多个 ID(以逗号分隔)
+  const ids = String(val).split(',').filter(Boolean);
+  if (ids.length > 1) {
+    return ids.map(id => {
+      return industryOptions.value.find(i => String(i.id) === String(id))?.industryCategoryName || id;
+    }).join('、');
+  }
   return industryOptions.value.find(i => String(i.id) === String(val))?.industryCategoryName || val;
 };
 

+ 14 - 4
src/views/saleManage/platformSelection/index.vue

@@ -180,8 +180,8 @@
           </template>
         </el-table-column>
         <el-table-column label="产品支持" align="center" prop="productSupportName" width="100">
-          <template #default="scope">
-            {{ scope.row.productSupportName || userOptions.find(u => String(u.staffId || u.userId) === String(scope.row.productSupport))?.staffName || '' }}
+          <template #default="{ row }">
+            <span>{{ row.productSupportName || findUserName(row.productSupport) }}</span>
           </template>
         </el-table-column>
         <el-table-column label="赢单率(%)" align="center" width="100">
@@ -327,7 +327,7 @@ import {
   transferPlatformSelection
 } from '@/api/saleManage/platformSelection/index';
 import { listRecord, addRecord } from "@/api/visit/record";
-import { selectStaffOptionList } from "@/api/system/comStaff/index";
+import { listComStaff } from "@/api/system/comStaff/index";
 import { listCompanyOption, listCustomerInfo } from "@/api/customer/customerInfo/index";
 import { listIndustryCategory } from "@/api/customer/industryCategory";
 import { listSalesResultAnalyze } from '@/api/saleManage/leads/salesResultAnalyze';
@@ -614,11 +614,21 @@ const initData = () => {
     industryOptions.value = flatData;
     drawerOptionsBase.industryList = res.data; 
   });
-  selectStaffOptionList().then(res => { userOptions.value = res.data; drawerOptionsBase.user = res.data; });
+  listComStaff({ pageSize: 1000 }).then(res => { 
+    const list = res.rows || res.data || [];
+    userOptions.value = list; 
+    drawerOptionsBase.user = list; 
+  });
   listCompanyOption().then(res => { companyOptions.value = res.data; drawerOptionsBase.company = res.data; });
   deptTreeSelect().then(res => deptOptions.value = res.data);
 };
 
+const findUserName = (id) => {
+  if (!id) return '';
+  const user = userOptions.value.find(u => String(u.staffId || u.userId) === String(id));
+  return user ? (user.staffName || user.nickName) : id;
+};
+
 onMounted(() => {
   initData();
   getList();

+ 18 - 4
src/views/saleManage/projectSelection/index.vue

@@ -185,8 +185,16 @@
           </template>
         </el-table-column>
         <el-table-column label="部门" align="center" prop="deptName" min-width="120" show-overflow-tooltip />
-        <el-table-column label="负责人" align="center" prop="leaderName" width="100" />
-        <el-table-column label="产品支持" align="center" prop="productSupportName" width="100" />
+        <el-table-column label="负责人" align="center" prop="leaderName" width="100">
+          <template #default="{ row }">
+            <span>{{ row.leaderName || findUserName(row.managerId || row.leader) }}</span>
+          </template>
+        </el-table-column>
+        <el-table-column label="产品支持" align="center" prop="productSupportName" width="100">
+          <template #default="{ row }">
+            <span>{{ row.productSupportName || findUserName(row.productSupport) }}</span>
+          </template>
+        </el-table-column>
         <el-table-column label="赢单率" align="center" width="80">
           <template #default="{ row }">
             <span>{{ (row.winRate || row.winningRate) ? (row.winRate || row.winningRate) + '%' : '--' }}</span>
@@ -356,7 +364,7 @@ import { listProjectSelection, delProjectSelection, transferProjectSelection, pu
 import { listSalesResultAnalyze } from '@/api/saleManage/leads/salesResultAnalyze';
 import { listRecord, addRecord } from "@/api/visit/record";
 import { listIndustryCategory } from "@/api/customer/industryCategory";
-import { selectStaffOptionList } from "@/api/customer/crmStaff";
+import { listComStaff } from "@/api/system/comStaff/index";
 import { listCompanyOption, getCustomerInfo } from "@/api/customer/customerInfo/index";
 import { deptTreeSelect } from "@/api/system/user";
 
@@ -590,13 +598,19 @@ const initOptions = () => {
   listIndustryCategory().then(res => {
     industryOptions.value = res.data || [];
   });
-  selectStaffOptionList().then(r => userOptions.value = r.data);
+  listComStaff({ pageSize: 1000 }).then(r => userOptions.value = r.rows || r.data || []);
   listCompanyOption().then(r => companyOptions.value = r.data);
   deptTreeSelect().then(res => {
     deptOptions.value = res.data;
   });
 };
 
+const findUserName = (id) => {
+  if (!id) return '';
+  const user = userOptions.value.find(u => String(u.staffId || u.userId) === String(id));
+  return user ? (user.staffName || user.nickName) : id;
+};
+
 onMounted(() => {
   getList();
   initOptions();

+ 23 - 17
src/views/visit/plan/add.vue

@@ -11,7 +11,7 @@
               <el-col :span="8">
                 <el-form-item label="拜访人:" prop="visitorId">
                   <el-select v-model="form.visitorId" placeholder="请选择" style="width: 100%" clearable filterable @change="handleStaffChange">
-                    <el-option v-for="item in staffOptions" :key="item.staffId" :label="item.staffName + (item.staffCode ? ' (' + item.staffCode + ')' : '')" :value="item.staffId" />
+                <el-option v-for="item in staffOptions" :key="item.staffId" :label="item.staffName" :value="item.staffId" />
                   </el-select>
                 </el-form-item>
               </el-col>
@@ -75,9 +75,9 @@
     </template>
 
     <!-- 新建日程对话框 -->
-    <el-dialog :title="scheduleTitle" v-model="scheduleOpen" width="700px" append-to-body destroy-on-close class="schedule-dialog">
-      <el-form ref="scheduleFormRef" :model="scheduleForm" :rules="scheduleRules" label-width="110px">
-        <el-form-item label="关类型" prop="relevanceType">
+    <el-dialog :title="scheduleTitle" v-model="scheduleOpen" width="600px" append-to-body destroy-on-close class="custom-dialog">
+      <el-form ref="scheduleFormRef" :model="scheduleForm" :rules="scheduleRules" label-width="100px" label-position="right">
+        <el-form-item label="关类型" prop="relevanceType">
           <el-radio-group v-model="scheduleForm.relevanceType">
             <el-radio :label="0">客户</el-radio>
             <el-radio :label="1">项目商机</el-radio>
@@ -85,20 +85,20 @@
           </el-radio-group>
         </el-form-item>
         
-        <el-form-item :label="(scheduleForm.relevanceType === 1 ? '项目商机' : (scheduleForm.relevanceType === 2 ? '年度入围' : '客户')) + ':'" prop="customerName">
+        <el-form-item :label="scheduleTypeLabel" prop="customerName">
           <el-select v-model="scheduleForm.customerName" placeholder="请选择" style="width: 100%" filterable>
-            <el-option v-for="item in currentOptions" :key="item.id" :label="item.projectName || item.customerName" :value="item.projectName || item.customerName" />
+            <el-option v-for="item in currentOptions" :key="item.id || item.customerNo" :label="item.projectName || item.customerName" :value="item.projectName || item.customerName" />
           </el-select>
         </el-form-item>
 
-        <el-row>
+        <el-row :gutter="20">
           <el-col :span="12">
-            <el-form-item label="拜访日期" prop="callDate">
+            <el-form-item label="拜访日期" prop="callDate">
               <el-date-picker v-model="scheduleForm.callDate" type="date" placeholder="请选择" style="width: 100%" value-format="YYYY-MM-DD" />
             </el-form-item>
           </el-col>
           <el-col :span="12">
-            <el-form-item label="紧要程度:" prop="importantLevel">
+            <el-form-item label="重要级别" prop="importantLevel">
               <el-select v-model="scheduleForm.importantLevel" placeholder="请选择" style="width: 100%">
                 <el-option v-for="dict in urgencyOptions" :key="dict.value" :label="dict.label" :value="dict.value" />
               </el-select>
@@ -106,14 +106,14 @@
           </el-col>
         </el-row>
 
-        <el-form-item label="随访人" prop="followPeopleName">
-          <el-select v-model="scheduleForm.followPeopleName" placeholder="请选择" style="width: 100%" multiple clearable filterable>
-            <el-option v-for="item in staffOptions" :key="item.staffId" :label="item.staffName + (item.staffCode ? ' (' + item.staffCode + ')' : '')" :value="item.staffName" />
+        <el-form-item label="随访人" prop="followPeopleName">
+          <el-select v-model="scheduleForm.followPeopleName" placeholder="请选择" style="width: 100%" multiple clearable filterable collapse-tags>
+            <el-option v-for="item in staffOptions" :key="item.staffId" :label="item.staffName" :value="item.staffName" />
           </el-select>
         </el-form-item>
 
-        <el-form-item label="拜访目的" prop="purposeVisit">
-          <el-input v-model="scheduleForm.purposeVisit" type="textarea" :rows="5" placeholder="请输入内容" />
+        <el-form-item label="拜访目的" prop="purposeVisit">
+          <el-input v-model="scheduleForm.purposeVisit" type="textarea" :rows="4" placeholder="请输入内容" />
         </el-form-item>
       </el-form>
       <template #footer>
@@ -129,7 +129,7 @@
 <script setup>
 import { ref, reactive, computed, watch, getCurrentInstance, onMounted, toRefs } from 'vue';
 import { addPlan } from "@/api/visit/plan";
-import { selectStaffOptionList } from "@/api/customer/crmStaff";
+import { listComStaff } from "@/api/system/comStaff/index";
 import { listCustomerInfo } from "@/api/customer/customerInfo/index";
 import { listOpportunity } from "@/api/saleManage/opportunity";
 import { listProjectSelection } from "@/api/saleManage/projectSelection";
@@ -170,6 +170,12 @@ const currentOptions = computed(() => {
   return customerOptions.value;
 });
 
+const scheduleTypeLabel = computed(() => {
+  if (scheduleForm.value.relevanceType === 1) return '项目商机';
+  if (scheduleForm.value.relevanceType === 2) return '年度入围';
+  return '客户';
+});
+
 watch(() => scheduleForm.value.relevanceType, () => {
   scheduleForm.value.customerName = '';
   scheduleForm.value.objectName = '';
@@ -315,8 +321,8 @@ const resetForm = () => {
 };
 
 onMounted(() => {
-  selectStaffOptionList().then(response => {
-    staffOptions.value = response.data || [];
+  listComStaff({ pageSize: 1000 }).then(response => {
+    staffOptions.value = response.rows || response.data || [];
   });
   listCustomerInfo({ pageSize: 500 }).then(response => {
     customerOptions.value = response.rows || [];

+ 12 - 6
src/views/visit/plan/detail.vue

@@ -263,7 +263,7 @@ onMounted(() => {
   .content-scroll { flex: 1; overflow-y: auto; padding: 20px; }
 }
 .side-panel {
-  width: 380px; background-color: #fff; display: flex; flex-direction: column;
+  width: 30%; background-color: #fff; display: flex; flex-direction: column;
   .side-tabs-header {
     display: flex; border-bottom: 1px solid #f1f5f9;
     .side-tab-item {
@@ -280,11 +280,17 @@ onMounted(() => {
   display: grid; grid-template-columns: repeat(2, 1fr); gap: 20px 40px; padding: 15px;
   .info-item { display: flex; font-size: 13px; .label { color: #8c8c8c; width: 80px; flex-shrink: 0; } .value { color: #262626; } }
 }
-.admin-tab-content {
-  padding: 10px 5px;
-  .admin-grid {
-    display: grid; grid-template-columns: 1fr 1fr; gap: 16px 24px;
-    .admin-cell { display: flex; align-items: center; .label { color: #86909c; font-size: 13px; width: 85px; flex-shrink: 0; } .value { color: #1d2129; font-size: 13px; } }
+.admin-grid {
+  display: grid; 
+  grid-template-columns: repeat(2, 1fr); 
+  gap: 12px 8px; 
+  padding: 15px 5px;
+  .admin-cell { 
+    display: flex; 
+    align-items: center;
+    font-size: 13px;
+    .label { color: #86909c; margin-right: 6px; flex-shrink: 0; } 
+    .value { color: #1d2129; word-break: break-all; } 
   }
 }
 </style>

+ 3 - 3
src/views/visit/plan/edit.vue

@@ -129,7 +129,7 @@
 <script setup>
 import { ref, reactive, computed, watch, getCurrentInstance, onMounted, toRefs } from 'vue';
 import { getPlan, updatePlan } from "@/api/visit/plan";
-import { selectStaffOptionList } from "@/api/customer/crmStaff";
+import { listComStaff } from "@/api/system/comStaff/index";
 import { listCustomerInfo } from "@/api/customer/customerInfo/index";
 import { listOpportunity } from "@/api/saleManage/opportunity";
 import { listProjectSelection } from "@/api/saleManage/projectSelection";
@@ -308,8 +308,8 @@ const cancel = () => {
 };
 
 onMounted(() => {
-  selectStaffOptionList().then(response => {
-    staffOptions.value = response.data || [];
+  listComStaff({ pageSize: 1000 }).then(response => {
+    staffOptions.value = response.rows || response.data || [];
   });
   listCustomerInfo({ pageSize: 500 }).then(response => {
     customerOptions.value = response.rows || [];

+ 4 - 4
src/views/visit/plan/index.vue

@@ -8,7 +8,7 @@
         </el-form-item>
         <el-form-item label="拜访人" prop="visitorId" class="custom-form-item">
           <el-select v-model="queryParams.visitorId" placeholder="请选择" clearable filterable style="width: 200px">
-            <el-option v-for="item in staffOptions" :key="item.staffId" :label="item.staffName + (item.staffCode ? ' (' + item.staffCode + ')' : '')" :value="item.staffId" />
+            <el-option v-for="item in staffOptions" :key="item.staffId" :label="item.staffName" :value="item.staffId" />
           </el-select>
         </el-form-item>
         <el-form-item label="计划状态" prop="status" class="custom-form-item">
@@ -101,7 +101,7 @@
 <script setup name="VisitPlan">
 import { ref, reactive, onMounted, getCurrentInstance } from 'vue';
 import { listPlan, delPlan } from "@/api/visit/plan";
-import { selectStaffOptionList } from "@/api/customer/crmStaff";
+import { listComStaff } from "@/api/system/comStaff/index";
 import AddPlan from './add.vue';
 import DetailPlan from './detail.vue';
 
@@ -175,8 +175,8 @@ const handleDelete = (row) => {
 
 onMounted(() => {
   getList();
-  selectStaffOptionList().then(response => {
-    staffOptions.value = response.data || [];
+  listComStaff({ pageSize: 1000 }).then(response => {
+    staffOptions.value = response.rows || response.data || [];
   });
 });
 </script>

+ 7 - 6
src/views/visit/record/detail.vue

@@ -274,7 +274,7 @@
 import { ref, watch, getCurrentInstance, toRefs } from 'vue';
 import { Close, ChatLineRound, Upload } from '@element-plus/icons-vue';
 import { getRecord, listRecord } from "@/api/visit/record";
-import { selectStaffOptionList } from "@/api/customer/crmStaff";
+import { listComStaff } from "@/api/system/comStaff/index";
 import { globalHeaders } from "@/utils/request";
 import BusinessActivity from '../../common/businessActivity.vue';
 
@@ -319,8 +319,8 @@ function getData(id) {
 
 
 
-selectStaffOptionList().then(res => {
-  staffOptions.value = res.data || [];
+listComStaff({ pageSize: 1000 }).then(res => {
+  staffOptions.value = res.rows || res.data || [];
 });
 
 const getVisitTypeName = (code) => {
@@ -370,7 +370,7 @@ const handleDownloadFile = (row) => {
 }
 
 .drawer-header {
-  height: 56px;
+  height: 64px;
   display: flex;
   align-items: center;
   justify-content: space-between;
@@ -378,8 +378,9 @@ const handleDownloadFile = (row) => {
   background-color: #fff;
   border-bottom: 1px solid #f0f0f0;
   z-index: 10;
-  .header-title { font-size: 16px; color: #333; font-weight: normal; line-height: 56px; }
-  .close-icon { font-size: 18px; cursor: pointer; color: #999; &:hover { color: #409eff; } }
+  box-sizing: border-box;
+  .header-title { font-size: 16px; color: #333; font-weight: normal; line-height: 64px; }
+  .close-icon { font-size: 20px; cursor: pointer; color: #999; &:hover { color: #409eff; } }
 }
 
 .detail-wrap {

+ 52 - 40
src/views/visit/record/index.vue

@@ -20,10 +20,10 @@
             style="width: 240px"
           />
         </el-form-item>
-        <div class="search-btns-area">
+        <el-form-item>
           <el-button icon="Search" @click="handleQuery" class="btn-search">搜索</el-button>
           <el-button icon="Refresh" @click="resetQuery" class="btn-reset">重置</el-button>
-        </div>
+        </el-form-item>
       </el-form>
     </el-card>
 
@@ -35,13 +35,13 @@
     <!-- 表格区域 -->
     <el-card shadow="never" class="table-card">
       <el-table ref="tableRef" v-loading="loading" :data="dataList" border class="standard-table">
-        <el-table-column label="记录编号" align="center" prop="recordsNo" width="140" fixed>
+        <el-table-column label="编号" align="center" prop="recordsNo" width="140" fixed>
           <template #default="scope">
             <span class="link-text" @click="handleDetail(scope.row)">{{ scope.row.recordsNo }}</span>
           </template>
         </el-table-column>
         <el-table-column label="客户名称" align="center" prop="customerName" min-width="250" show-overflow-tooltip />
-        <el-table-column label="部门" align="center" prop="department" width="120">
+        <el-table-column label="部门" align="center" width="120">
           <template #default="scope">
             <span>{{ scope.row.visitorDeptName || scope.row.deptName || scope.row.department || '' }}</span>
           </template>
@@ -51,23 +51,23 @@
             <span>{{ industryOptions.find(o => String(o.id) === String(scope.row.profession))?.industryCategoryName || scope.row.profession || '' }}</span>
           </template>
         </el-table-column>
-        <el-table-column label="业务员" align="center" prop="salesman" width="100" show-overflow-tooltip />
-        <el-table-column label="对象类型" align="center" prop="dataType" width="120">
+        <el-table-column label="负责人" align="center" prop="salesman" width="100" show-overflow-tooltip />
+        <el-table-column label="对象类型" align="center" width="120">
            <template #default="scope">
-             <el-tag v-if="String(scope.row.dataType) === '1'" type="primary">项目商机</el-tag>
-             <el-tag v-else-if="String(scope.row.dataType) === '2'" type="success">项目筛选</el-tag>
-             <el-tag v-else-if="String(scope.row.dataType) === '3'" type="warning">年度入围</el-tag>
-             <el-tag v-else type="info">通用</el-tag>
+             <el-tag v-if="String(scope.row.dataType) === '1'" type="primary" size="small">项目商机</el-tag>
+             <el-tag v-else-if="String(scope.row.dataType) === '2'" type="success" size="small">项目筛选</el-tag>
+             <el-tag v-else-if="String(scope.row.dataType) === '3'" type="warning" size="small">年度入围</el-tag>
+             <el-tag v-else type="info" size="small">通用</el-tag>
            </template>
         </el-table-column>
         <el-table-column label="拜访对象" align="center" prop="goalObject" width="160" show-overflow-tooltip />
-        <el-table-column label="拜访人" align="center" prop="visitorName" width="100">
+        <el-table-column label="拜访人" align="center" width="100">
           <template #default="scope">
-            <span>{{ staffOptions.find(s => String(s.staffId) === String(scope.row.visitor || scope.row.visitorNo))?.staffName || scope.row.visitorName || scope.row.visitor || '' }}</span>
+            <span>{{ findStaffName(scope.row.visitor || scope.row.visitorNo || scope.row.visitorName) }}</span>
           </template>
         </el-table-column>
         <el-table-column label="随访人" align="center" prop="followPeopleName" width="100" />
-        <el-table-column label="拜访日期" align="center" prop="callDate" width="120">
+        <el-table-column label="拜访日期" align="center" prop="callDate" width="110">
           <template #default="scope">
             <span>{{ parseTime(scope.row.callDate, '{y}-{m}-{d}') }}</span>
           </template>
@@ -75,7 +75,7 @@
         <el-table-column label="操作" align="center" width="120" fixed="right">
           <template #default="scope">
             <el-button link class="op-btn" @click="handleDetail(scope.row)">详情</el-button>
-            <el-button link class="op-btn" @click="handleDelete(scope.row)">删除</el-button>
+            <el-button link class="op-btn-danger" @click="handleDelete(scope.row)">删除</el-button>
           </template>
         </el-table-column>
       </el-table>
@@ -92,7 +92,7 @@
 <script setup name="VisitRecord">
 import { ref, reactive, onMounted, getCurrentInstance } from 'vue';
 import { listRecord, delRecord } from "@/api/visit/record";
-import { selectStaffOptionList } from "@/api/customer/crmStaff";
+import { listComStaff } from "@/api/system/comStaff/index";
 import { listIndustryCategory } from "@/api/customer/industryCategory";
 import Detail from './detail.vue';
 
@@ -125,14 +125,24 @@ const getList = () => {
     params.endTime = dateRange.value[1];
   }
   listRecord(params).then(response => {
-    dataList.value = response.rows;
-    total.value = response.total;
+    // 仅保留纯数字编号的记录,过滤掉带有 RC 前缀的日程同步数据
+    dataList.value = (response.rows || []).filter(r => {
+      const no = String(r.recordsNo || '');
+      return !no || /^\d+$/.test(no);
+    });
+    total.value = dataList.value.length; // 注意:前端过滤后总数会变,如果后端不支持过滤建议这样处理或联系后端
     loading.value = false;
   }).catch(() => {
     loading.value = false;
   });
 };
 
+const findStaffName = (val) => {
+  if (!val) return '';
+  const staff = staffOptions.value.find(s => String(s.staffId) === String(val) || String(s.userId) === String(val) || String(s.staffName) === String(val));
+  return staff ? staff.staffName : val;
+};
+
 const handleQuery = () => {
   queryParams.pageNum = 1;
   getList();
@@ -159,8 +169,8 @@ const handleDelete = (row) => {
 
 onMounted(() => { 
   getList(); 
-  selectStaffOptionList().then(res => {
-    staffOptions.value = res.data || [];
+  listComStaff({ pageSize: 1000 }).then(res => {
+    staffOptions.value = res.rows || res.data || [];
   });
   
   listIndustryCategory().then(res => {
@@ -189,7 +199,7 @@ onMounted(() => {
   border: none;
   background-color: #fff;
   :deep(.el-card__body) {
-    padding: 10px 0;
+    padding: 15px 20px;
   }
   border-bottom: 1px solid #efefef;
   margin-bottom: 0;
@@ -210,22 +220,17 @@ onMounted(() => {
   }
 }
 
-.search-btns-area {
-  display: inline-flex;
-  gap: 10px;
-  margin-bottom: 10px;
-  .btn-search {
-    background: #409eff;
-    border: 1px solid #409eff;
-    color: #fff;
-    &:hover { background: #66b1ff; border-color: #66b1ff; }
-  }
-  .btn-reset {
-    background: #fff;
-    color: #333;
-    border: 1px solid #dcdfe6;
-    &:hover { background: #f5f7fa; }
-  }
+.btn-search {
+  background: #409eff;
+  border: 1px solid #409eff;
+  color: #fff;
+  &:hover { background: #66b1ff; border-color: #66b1ff; }
+}
+.btn-reset {
+  background: #fff;
+  color: #333;
+  border: 1px solid #dcdfe6;
+  &:hover { background: #f5f7fa; }
 }
 
 /* 操作栏样式 */
@@ -233,7 +238,7 @@ onMounted(() => {
   display: flex;
   align-items: center;
   background-color: #fff;
-  padding: 12px 0;
+  padding: 15px 20px;
   margin-bottom: 0;
 
   .page-title {
@@ -277,9 +282,16 @@ onMounted(() => {
 }
 
 .op-btn {
-  color: #909399;
-  font-weight: normal; /* 不加粗 */
-  &:hover { color: #409eff; }
+  color: #409eff;
+  font-weight: normal;
+  &:hover { opacity: 0.8; }
+}
+
+.op-btn-danger {
+  color: #f56c6c;
+  font-weight: normal;
+  margin-left: 12px;
+  &:hover { opacity: 0.8; }
 }
 
 .table-card {

+ 62 - 57
src/views/visit/routine/add.vue

@@ -1,65 +1,70 @@
 <template>
-  <el-drawer title="新增拜访日程" :model-value="modelValue" @update:model-value="val => $emit('update:modelValue', val)" size="80%" direction="rtl" destroy-on-close class="routine-drawer">
-    <div class="dialog-content-area">
-      <el-form ref="formRef" :model="form" :rules="rules" label-width="100px">
-        <div class="section-title">基本信息</div>
-        <el-form-item label="关联计划:" prop="planNo">
-          <el-select v-model="form.planNo" placeholder="请选择" style="width: 100%" clearable filterable>
-            <el-option v-for="item in planOptions" :key="item.id" :label="item.planNo + (item.customerName ? ' - ' + item.customerName : '')" :value="item.planNo" />
-          </el-select>
-        </el-form-item>
-        <el-form-item label="关联类型:" prop="relevanceType">
-          <el-radio-group v-model="form.relevanceType" @change="handleTypeChange">
-            <el-radio value="0">客户</el-radio>
-            <el-radio value="1">项目商机</el-radio>
-            <el-radio value="2">年度入围</el-radio>
-          </el-radio-group>
-        </el-form-item>
-        <el-form-item :label="typeLabel + ':'" prop="objectName">
-          <el-select v-model="form.objectName" placeholder="请选择" style="width: 100%" clearable filterable @change="handleObjectChange">
-            <el-option v-for="item in currentOptions" :key="item.id || item.customerNo" :label="item.projectName || item.customerName" :value="item.projectName || item.customerName" />
-          </el-select>
-        </el-form-item>
-
-        <el-form-item label="拜访人:" prop="callPeopleNo">
-          <el-select v-model="form.callPeopleNo" placeholder="请选择拜访人" style="width: 100%" clearable filterable @change="handleStaffChange">
-            <el-option v-for="item in staffOptions" :key="item.staffId" :label="`${item.staffName}${item.staffCode ? ' (' + item.staffCode + ')' : ''}`" :value="item.staffId" />
-          </el-select>
-        </el-form-item>
-
-        <el-row :gutter="20">
-          <el-col :span="12">
-            <el-form-item label="拜访日期:" prop="callDate">
-              <el-date-picker v-model="form.callDate" type="date" placeholder="请选择" style="width: 100%" value-format="YYYY-MM-DD" />
+  <el-drawer title="新增拜访日程" :model-value="modelValue" @update:model-value="val => $emit('update:modelValue', val)" size="600px" direction="rtl" destroy-on-close class="custom-drawer" :with-header="false">
+    <div class="drawer-header">
+      <span class="header-title">新增拜访日程</span>
+      <el-icon class="close-icon" @click="cancel"><Close /></el-icon>
+    </div>
+    <div class="drawer-body-custom">
+      <el-form ref="formRef" :model="form" :rules="rules" label-width="100px" label-position="right" class="standard-form">
+        <div class="section-group">
+          <div class="section-title-bar">基本信息</div>
+          <div class="section-content">
+            <el-form-item label="关联计划" prop="planNo">
+              <el-select v-model="form.planNo" placeholder="请选择" style="width: 100%" clearable filterable>
+                <el-option v-for="item in planOptions" :key="item.id" :label="item.planNo + (item.customerName ? ' - ' + item.customerName : '')" :value="item.planNo" />
+              </el-select>
+            </el-form-item>
+            
+            <el-form-item label="关联类型" prop="relevanceType">
+              <el-radio-group v-model="form.relevanceType" @change="handleTypeChange">
+                <el-radio value="0">客户</el-radio>
+                <el-radio value="1">项目商机</el-radio>
+                <el-radio value="2">年度入围</el-radio>
+              </el-radio-group>
             </el-form-item>
-          </el-col>
-          <el-col :span="12">
-            <el-form-item label="重要级别:" prop="importantLevel">
-              <el-select v-model="form.importantLevel" placeholder="请选择" style="width: 100%">
-                <el-option
-                  v-for="dict in importanceOptions"
-                  :key="dict.value"
-                  :label="dict.label"
-                  :value="dict.value"
-                />
+            
+            <el-form-item :label="typeLabel" prop="objectName">
+              <el-select v-model="form.objectName" placeholder="请选择" style="width: 100%" clearable filterable @change="handleObjectChange">
+                <el-option v-for="item in currentOptions" :key="item.id || item.customerNo" :label="item.projectName || item.customerName" :value="item.projectName || item.customerName" />
+              </el-select>
+            </el-form-item>
+
+            <el-form-item label="拜访人" prop="callPeopleNo">
+              <el-select v-model="form.callPeopleNo" placeholder="请选择" style="width: 100%" clearable filterable @change="handleStaffChange">
+                <el-option v-for="item in staffOptions" :key="item.staffId" :label="item.staffName" :value="item.staffId" />
               </el-select>
             </el-form-item>
-          </el-col>
-        </el-row>
-
-        <el-form-item label="随访人:" prop="followPeopleName">
-          <el-select v-model="form.followPeopleName" placeholder="请选择" style="width: 100%" clearable filterable>
-            <el-option v-for="item in staffOptions" :key="item.staffId" :label="`${item.staffName}${item.staffCode ? ' (' + item.staffCode + ')' : ''}`" :value="item.staffName" />
-          </el-select>
-        </el-form-item>
-
-        <el-form-item label="拜访目的:" prop="purposeVisit">
-          <el-input type="textarea" :rows="4" v-model="form.purposeVisit" placeholder="请输入内容" />
-        </el-form-item>
+
+            <el-row :gutter="20">
+              <el-col :span="12">
+                <el-form-item label="拜访日期" prop="callDate">
+                  <el-date-picker v-model="form.callDate" type="date" placeholder="请选择" style="width: 100%" value-format="YYYY-MM-DD" />
+                </el-form-item>
+              </el-col>
+              <el-col :span="12">
+                <el-form-item label="重要级别" prop="importantLevel">
+                  <el-select v-model="form.importantLevel" placeholder="请选择" style="width: 100%">
+                    <el-option v-for="dict in importanceOptions" :key="dict.value" :label="dict.label" :value="dict.value" />
+                  </el-select>
+                </el-form-item>
+              </el-col>
+            </el-row>
+
+            <el-form-item label="随访人" prop="followPeopleName">
+              <el-select v-model="form.followPeopleName" placeholder="请选择" style="width: 100%" clearable filterable multiple collapse-tags>
+                <el-option v-for="item in staffOptions" :key="item.staffId" :label="item.staffName" :value="item.staffName" />
+              </el-select>
+            </el-form-item>
+
+            <el-form-item label="拜访目的" prop="purposeVisit">
+              <el-input type="textarea" :rows="4" v-model="form.purposeVisit" placeholder="请输入内容" />
+            </el-form-item>
+          </div>
+        </div>
       </el-form>
     </div>
     <template #footer>
-      <div class="dialog-footer">
+      <div class="drawer-footer-standard">
         <el-button type="primary" @click="submitForm">确 认</el-button>
         <el-button @click="cancel">取 消</el-button>
       </div>
@@ -72,7 +77,7 @@ import { ref, reactive, onMounted, getCurrentInstance, computed, toRefs } from '
 import { addRoutine } from "@/api/visit/routine";
 import { listPlan } from "@/api/visit/plan";
 import { listCustomerInfo } from "@/api/customer/customerInfo/index";
-import { selectStaffOptionList } from "@/api/customer/crmStaff";
+import { listComStaff } from "@/api/system/comStaff/index";
 import { listOpportunity } from "@/api/saleManage/opportunity";
 import { listProjectSelection } from "@/api/saleManage/projectSelection";
 import { useUserStore } from "@/store/modules/user";
@@ -208,7 +213,7 @@ onMounted(() => {
   listCustomerInfo({ pageSize: 1000 }).then(res => { customerOptions.value = res.rows || []; });
   listOpportunity({ pageSize: 1000 }).then(res => { opportunityOptions.value = res.rows || []; });
   listProjectSelection({ pageSize: 1000 }).then(res => { annualOptions.value = res.rows || []; });
-  selectStaffOptionList().then(res => { staffOptions.value = res.data || []; });
+  listComStaff({ pageSize: 1000 }).then(res => { staffOptions.value = res.rows || res.data || []; });
 });
 </script>
 

+ 37 - 20
src/views/visit/routine/detail.vue

@@ -1,8 +1,9 @@
 <template>
-  <el-drawer v-model="visible" @update:model-value="val => $emit('update:modelValue', val)" size="80%" destroy-on-close class="custom-drawer">
-    <template #header>
-      <div class="drawer-title">{{ detailData.customerName || '详情信息' }}</div>
-    </template>
+  <el-drawer v-model="visible" @update:model-value="val => $emit('update:modelValue', val)" size="80%" destroy-on-close class="custom-drawer" :with-header="false">
+    <div class="drawer-header">
+      <span class="header-title">{{ detailData.customerName || '详情信息' }}</span>
+      <el-icon class="close-icon" @click="$emit('update:modelValue', false)"><Close /></el-icon>
+    </div>
     <div class="detail-wrap">
       <div class="left-panel">
         <el-tabs v-model="leftTab">
@@ -12,7 +13,7 @@
               <el-row class="info-row">
                 <el-col :span="12" class="info-col">
                   <span class="info-label">日程编号</span>
-                  <span class="info-value">{{ detailData.scheduleNo }}</span>
+                  <span class="info-value">{{ detailData.scheduleNo?.replace('RC', '') }}</span>
                 </el-col>
                 <el-col :span="12" class="info-col">
                   <span class="info-label">客户名称</span>
@@ -73,7 +74,7 @@
                 </el-col>
                 <el-col :span="12" class="manage-col">
                   <span class="label">创建人</span>
-                  <span class="value">{{ detailData.createByName || detailData.createUserName || detailData.nickName || detailData.callPeopleName || detailData.createBy || '' }}</span>
+                  <span class="value">{{ findStaffName(detailData.createByName || detailData.createUserName || detailData.nickName || detailData.createBy) || '' }}</span>
                 </el-col>
               </el-row>
               <el-row class="manage-row">
@@ -83,7 +84,7 @@
                 </el-col>
                 <el-col :span="12" class="manage-col">
                   <span class="label">最后修改人</span>
-                  <span class="value">{{ detailData.updateByName || detailData.updateUserName || detailData.followPeopleName || detailData.updateBy || '' }}</span>
+                  <span class="value">{{ findStaffName(detailData.updateByName || detailData.updateUserName || detailData.updateBy) || '' }}</span>
                 </el-col>
               </el-row>
             </div>
@@ -157,7 +158,7 @@
 import { ref, reactive, watch, getCurrentInstance, toRefs } from 'vue';
 import { Plus } from '@element-plus/icons-vue';
 import { getRoutine } from "@/api/visit/routine";
-import { selectStaffOptionList } from "@/api/customer/crmStaff";
+import { listComStaff } from "@/api/system/comStaff/index";
 import { addRecord, listRecord } from "@/api/visit/record";
 import { listOperateLog } from "@/api/visit/operateLog";
 import BusinessActivity from '../../common/businessActivity.vue';
@@ -239,9 +240,18 @@ function getOperateLogs(id) {
 }
 
 function getOptions() {
-  selectStaffOptionList().then(res => { staffOptions.value = res.data || []; });
+  listComStaff({ pageSize: 1000 }).then(res => { staffOptions.value = res.rows || res.data || []; });
 }
 
+const findStaffName = (val) => {
+  if (!val) return '';
+  if (!isNaN(Number(val))) {
+    const staff = staffOptions.value.find(s => String(s.staffId) === String(val) || String(s.userId) === String(val) || String(s.userNo) === String(val));
+    return staff ? (staff.staffName || staff.realName || staff.userName) : val;
+  }
+  return val;
+};
+
 const handleNewRecord = () => {
   recordForm.value = {
     accompanyPerson: undefined,
@@ -298,11 +308,15 @@ const submitRecord = () => {
     color: #333;
     font-weight: normal;
   }
-  .drawer-title {
-    font-size: 18px;
-    font-weight: normal;
-  }
-  .el-drawer__body {
+}
+.drawer-header {
+  height: 64px; display: flex; justify-content: space-between; align-items: center;
+  padding: 0 20px; border-bottom: 1px solid #f0f0f0; background-color: #fff; width: 100%; box-sizing: border-box;
+  .header-title { font-size: 18px; font-weight: normal; color: #333; }
+  .close-icon { cursor: pointer; color: #999; font-size: 20px; &:hover { color: #409eff; } }
+}
+.custom-drawer {
+  :deep(.el-drawer__body) {
     padding: 0;
     background-color: #f5f7fa;
   }
@@ -376,10 +390,12 @@ const submitRecord = () => {
   }
   
   .right-panel {
-    width: 450px;
+    width: 30%;
     background: #fff;
-    padding: 15px 20px;
-    overflow-y: auto;
+    padding: 0;
+    overflow-y: hidden; // 让内部的 tabs 自己处理滚动
+    display: flex;
+    flex-direction: column;
     &::-webkit-scrollbar { display: none; }
     -ms-overflow-style: none;
     scrollbar-width: none;
@@ -470,9 +486,10 @@ const submitRecord = () => {
         margin-bottom: 20px;
         .manage-col {
           display: flex;
-          flex-direction: column;
-          .label { font-size: 12px; color: #909399; margin-bottom: 5px; }
-          .value { font-size: 13px; color: #333; }
+          align-items: center;
+          font-size: 13px;
+          .label { color: #909399; margin-right: 8px; flex-shrink: 0; }
+          .value { color: #333; }
         }
       }
     }

+ 2 - 2
src/views/visit/routine/edit.vue

@@ -72,7 +72,7 @@ import { ref, reactive, onMounted, getCurrentInstance, watch, computed, toRefs }
 import { getRoutine, updateRoutine } from "@/api/visit/routine";
 import { listPlan } from "@/api/visit/plan";
 import { listCustomerInfo } from "@/api/customer/customerInfo/index";
-import { selectStaffOptionList } from "@/api/customer/crmStaff";
+import { listComStaff } from "@/api/system/comStaff/index";
 import { listOpportunity } from "@/api/saleManage/opportunity";
 import { listProjectSelection } from "@/api/saleManage/projectSelection";
 
@@ -196,7 +196,7 @@ onMounted(() => {
   listCustomerInfo({ pageSize: 1000 }).then(res => { customerOptions.value = res.rows || []; });
   listOpportunity({ pageSize: 1000 }).then(res => { opportunityOptions.value = res.rows || []; });
   listProjectSelection({ pageSize: 1000 }).then(res => { annualOptions.value = res.rows || []; });
-  selectStaffOptionList().then(res => { staffOptions.value = res.data || []; });
+  listComStaff({ pageSize: 1000 }).then(res => { staffOptions.value = res.rows || res.data || []; });
 });
 </script>
 

+ 94 - 28
src/views/visit/routine/index.vue

@@ -28,58 +28,66 @@
       </el-form>
     </el-card>
 
-    <div class="title-container">
-      <span class="list-title">拜访日程信息列表</span>
+    <!-- 列表标题 -->
+    <div class="filter-action-bar">
+      <div class="page-title">拜访日程信息列表</div>
     </div>
 
     <!-- 列表区域 -->
     <el-card shadow="never" class="table-card">
-      <el-table v-loading="loading" :data="dataList" border class="custom-table" :header-cell-style="{ background: '#f8fafc', color: '#333' }">
-        <el-table-column label="日程编号" align="center" prop="scheduleNo" width="160">
+      <el-table v-loading="loading" :data="dataList" border class="standard-table">
+        <el-table-column label="记录编号" align="center" width="140" fixed>
           <template #default="scope">
-            <span class="link-text" @click="handleDetail(scope.row)">{{ scope.row.scheduleNo }}</span>
+            <span class="link-text-emphasize" @click="handleDetail(scope.row)">{{ scope.row.scheduleNo?.replace('RC', '') }}</span>
           </template>
         </el-table-column>
-        <el-table-column label="关联计划" align="center" prop="planNo" width="160" />
-        <el-table-column label="客户名称" align="center" prop="customerName" min-width="200" show-overflow-tooltip />
-        <el-table-column label="拜访人" align="center" prop="callPeopleName" width="100">
+        <el-table-column label="客户名称" align="center" prop="customerName" min-width="250" show-overflow-tooltip />
+        <el-table-column label="部门" align="center" width="120">
           <template #default="scope">
-            <span>{{ staffOptions.find(s => String(s.staffId) === String(scope.row.callPeopleNo || scope.row.callPeopleName))?.staffName || scope.row.callPeopleName || '' }}</span>
+            <span>{{ findStaffDept(scope.row.callPeopleNo) || scope.row.deptName || scope.row.visitorDeptName || '' }}</span>
           </template>
         </el-table-column>
-        <el-table-column label="拜访日期" align="center" prop="callDate" width="120" >
+        <el-table-column label="行业" align="center" width="100">
           <template #default="scope">
-            <span>{{ parseTime(scope.row.callDate, '{y}-{m}-{d}') }}</span>
+             <span>{{ findCustomerAttr(scope.row.customerName, 'industry') || scope.row.profession || scope.row.industry || '' }}</span>
           </template>
         </el-table-column>
-        <el-table-column label="随访人" align="center" prop="followPeopleName" width="120" />
-        <el-table-column label="关联对象" align="center" prop="objectName" width="180" show-overflow-tooltip>
+        <el-table-column label="业务员" align="center" width="100" show-overflow-tooltip>
           <template #default="scope">
-            <span>{{ scope.row.objectName || scope.row.customerName || '' }}</span>
+            <span>{{ findCustomerAttr(scope.row.customerName, 'salesman') || scope.row.salesman || scope.row.createByName || '' }}</span>
           </template>
         </el-table-column>
-        <el-table-column label="状态" align="center" prop="scheduleStatus" width="100">
+        <el-table-column label="对象类型" align="center" width="100">
+           <template #default="scope">
+             <span>{{ scope.row.relevanceType === '0' ? '客户' : (scope.row.relevanceType === '1' ? '项目商机' : '年度入围') }}</span>
+           </template>
+        </el-table-column>
+        <el-table-column label="拜访对象" align="center" prop="objectName" width="160" show-overflow-tooltip />
+        <el-table-column label="拜访人" align="center" width="100">
           <template #default="scope">
-            <el-tag :type="String(scope.row.scheduleStatus) === '0' ? 'warning' : (String(scope.row.scheduleStatus) === '1' ? 'success' : 'danger')">
-              {{ scheduleStatusOptions.find(d => String(d.value) === String(scope.row.scheduleStatus))?.label || (String(scope.row.scheduleStatus) === '0' ? '未执行' : (String(scope.row.scheduleStatus) === '1' ? '已执行' : '放弃执行')) }}
-            </el-tag>
+            <span>{{ findStaffName(scope.row.callPeopleNo || scope.row.callPeopleName) }}</span>
           </template>
         </el-table-column>
-        <el-table-column label="关联类型" align="center" prop="relevanceType" width="100">
+        <el-table-column label="随访人" align="center" width="100">
           <template #default="scope">
-            {{ relevanceOptions.find(d => String(d.value) === String(scope.row.relevanceType))?.label || (String(scope.row.relevanceType) === '0' ? '客户' : (String(scope.row.relevanceType) === '1' ? '项目' : '供应商')) }}
+            <span>{{ scope.row.followPeopleName || scope.row.followPeople || '' }}</span>
           </template>
         </el-table-column>
-        <el-table-column label="重要级别" align="center" prop="importantLevel" width="100">
+        <el-table-column label="拜访日期" align="center" prop="callDate" width="110">
           <template #default="scope">
-            <span>{{ importanceOptions.find(d => String(d.value) === String(scope.row.importantLevel))?.label || scope.row.importantLevel || '' }}</span>
+            <span>{{ parseTime(scope.row.callDate, '{y}-{m}-{d}') }}</span>
           </template>
         </el-table-column>
-        <el-table-column label="操作" align="center" width="180" fixed="right">
+        <el-table-column label="操作" align="center" width="120" fixed="right">
+          <template #header>
+            <div class="op-header">
+              <span>操作</span>
+              <el-icon class="setting-icon"><Setting /></el-icon>
+            </div>
+          </template>
           <template #default="scope">
-            <el-button link type="primary" @click="handleDetail(scope.row)">详情</el-button>
-            <el-button link type="primary" @click="handleUpdate(scope.row)" v-hasPermi="['visit:routine:edit']">编辑</el-button>
-            <el-button link type="danger" @click="handleDelete(scope.row)" v-hasPermi="['visit:routine:remove']">删除</el-button>
+            <el-button link class="op-btn" @click="handleDetail(scope.row)">详情</el-button>
+            <el-button link class="op-btn-danger" @click="handleDelete(scope.row)">删除</el-button>
           </template>
         </el-table-column>
       </el-table>
@@ -101,7 +109,10 @@
 <script setup name="VisitRoutine">
 import { ref, reactive, onMounted, getCurrentInstance, toRefs } from 'vue';
 import { listRoutine, delRoutine } from "@/api/visit/routine";
-import { selectStaffOptionList } from "@/api/customer/crmStaff";
+import { listComStaff } from "@/api/system/comStaff/index";
+import { listIndustryCategory } from "@/api/customer/industryCategory";
+import { listCustomerInfo } from "@/api/customer/customerInfo/index";
+import { Setting } from '@element-plus/icons-vue';
 import AddRoutine from './add.vue';
 import EditRoutine from './edit.vue';
 import DetailRoutine from './detail.vue';
@@ -114,6 +125,8 @@ const {
 } = toRefs(reactive(proxy.useDict("importance_level", "schedule_status", "relevance_type")));
 
 const staffOptions = ref([]);
+const industryOptions = ref([]);
+const customerList = ref([]);
 
 const queryRef = ref(null);
 const loading = ref(false);
@@ -146,6 +159,35 @@ const getList = () => {
   });
 };
 
+const findStaffName = (val) => {
+  if (!val) return '';
+  const staff = staffOptions.value.find(s => String(s.staffId) === String(val) || String(s.userId) === String(val) || String(s.staffName) === String(val));
+  return staff ? staff.staffName : val;
+};
+
+const findStaffDept = (val) => {
+  if (!val) return '';
+  const staff = staffOptions.value.find(s => String(s.staffId) === String(val) || String(s.userId) === String(val) || String(s.staffName) === String(val));
+  return staff ? staff.deptName : '';
+};
+
+// 通过客户名称反查行业和业务员
+const findCustomerAttr = (customerName, attr) => {
+  if (!customerName) return '';
+  const customer = customerList.value.find(c => c.customerName === customerName);
+  if (!customer) return '';
+  
+  if (attr === 'industry') {
+    const indId = customer.profession || customer.industry;
+    const ind = industryOptions.value.find(o => String(o.id) === String(indId));
+    return ind ? ind.industryCategoryName : (indId || '');
+  }
+  if (attr === 'salesman') {
+    return customer.leaderName || customer.salesman || '';
+  }
+  return '';
+};
+
 const handleQuery = () => {
   queryParams.pageNum = 1;
   getList();
@@ -184,7 +226,9 @@ const handleDelete = (row) => {
 };
 
 const getOptions = () => {
-  selectStaffOptionList().then(res => { staffOptions.value = res.data || []; });
+  listComStaff({ pageSize: 1000 }).then(res => { staffOptions.value = res.rows || res.data || []; });
+  listIndustryCategory({ pageSize: 1000 }).then(res => { industryOptions.value = res.rows || []; });
+  listCustomerInfo({ pageSize: 1000 }).then(res => { customerList.value = res.rows || []; });
 };
 
 onMounted(() => { 
@@ -259,4 +303,26 @@ onMounted(() => {
 }
 
 .link-text { color: #409eff; cursor: pointer; }
+.link-text-emphasize { color: #e6a23c; cursor: pointer; } /* 橙色强调 */
+
+.op-header {
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  gap: 4px;
+  .setting-icon { font-size: 14px; cursor: pointer; color: #909399; }
+}
+
+.op-btn {
+  color: #409eff;
+  font-weight: normal;
+  &:hover { opacity: 0.8; }
+}
+
+.op-btn-danger {
+  color: #f56c6c;
+  font-weight: normal;
+  margin-left: 12px;
+  &:hover { opacity: 0.8; }
+}
 </style>