瀏覽代碼

字典修改

沐梦. 3 周之前
父節點
當前提交
cb0c2d3836
共有 45 個文件被更改,包括 501 次插入561 次删除
  1. 0 14
      src/api/customer/customerDict.js
  2. 6 3
      src/utils/dict.ts
  3. 13 20
      src/views/common/businessActivity.vue
  4. 5 11
      src/views/customer/care/add.vue
  5. 6 13
      src/views/customer/care/detail.vue
  6. 4 8
      src/views/customer/care/edit.vue
  7. 6 13
      src/views/customer/care/index.vue
  8. 1 1
      src/views/customer/contactPerson/add.vue
  9. 5 9
      src/views/customer/contactPerson/detail.vue
  10. 5 5
      src/views/customer/contactPerson/edit.vue
  11. 8 10
      src/views/customer/contactPerson/index.vue
  12. 10 9
      src/views/customer/highseas/detail.vue
  13. 4 4
      src/views/customer/highseas/edit.vue
  14. 7 17
      src/views/customer/highseas/index.vue
  15. 25 28
      src/views/customer/valid/detail.vue
  16. 6 9
      src/views/customer/valid/edit.vue
  17. 5 9
      src/views/customer/valid/index.vue
  18. 2 2
      src/views/sale/customerTarget/index.vue
  19. 3 3
      src/views/saleManage/accountsReceivable/index.vue
  20. 11 11
      src/views/saleManage/leads/add.vue
  21. 20 25
      src/views/saleManage/leads/detail.vue
  22. 1 1
      src/views/saleManage/leads/edit.vue
  23. 10 18
      src/views/saleManage/leads/index.vue
  24. 38 11
      src/views/saleManage/opportunity/add.vue
  25. 15 20
      src/views/saleManage/opportunity/detail.vue
  26. 36 10
      src/views/saleManage/opportunity/edit.vue
  27. 22 33
      src/views/saleManage/opportunity/index.vue
  28. 7 7
      src/views/saleManage/platformSelection/add.vue
  29. 15 19
      src/views/saleManage/platformSelection/detail.vue
  30. 7 7
      src/views/saleManage/platformSelection/edit.vue
  31. 40 36
      src/views/saleManage/platformSelection/index.vue
  32. 7 7
      src/views/saleManage/projectSelection/add.vue
  33. 19 20
      src/views/saleManage/projectSelection/detail.vue
  34. 7 7
      src/views/saleManage/projectSelection/edit.vue
  35. 28 35
      src/views/saleManage/projectSelection/index.vue
  36. 7 10
      src/views/visit/plan/add.vue
  37. 6 18
      src/views/visit/plan/detail.vue
  38. 7 10
      src/views/visit/plan/edit.vue
  39. 1 1
      src/views/visit/plan/index.vue
  40. 22 17
      src/views/visit/record/detail.vue
  41. 1 1
      src/views/visit/record/index.vue
  42. 6 8
      src/views/visit/routine/add.vue
  43. 28 18
      src/views/visit/routine/detail.vue
  44. 6 8
      src/views/visit/routine/edit.vue
  45. 13 15
      src/views/visit/routine/index.vue

+ 0 - 14
src/api/customer/customerDict.js

@@ -1,20 +1,6 @@
 import request from '@/utils/request'
 
-// 根据字典类型查询客户字典数据列表
-export function listDictByType(dictType) {
-  return request({
-    url: '/customer/dict/type/' + dictType,
-    method: 'get'
-  })
-}
 
-// 查询通用字典 - 根据code查询
-export function listCommonDict(dictCode) {
-  return request({
-    url: '/customer/dict/common/' + dictCode,
-    method: 'get'
-  })
-}
 
 // 查询客户类型选项列表
 export function listCustomerTypeOption() {

+ 6 - 3
src/utils/dict.ts

@@ -1,9 +1,11 @@
 import { getDicts } from '@/api/system/dict/data';
 import { useDictStore } from '@/store/modules/dict';
+import { ref, toRefs } from 'vue';
+
 /**
  * 获取字典数据
  */
-export const useDict = (...args: string[]): { [key: string]: DictDataOption[] } => {
+export const useDict = (...args: string[]) => {
   const res = ref<{
     [key: string]: DictDataOption[];
   }>({});
@@ -11,10 +13,11 @@ export const useDict = (...args: string[]): { [key: string]: DictDataOption[] }
   args.forEach(async (dictType) => {
     res.value[dictType] = [];
     const dicts = useDictStore().getDict(dictType);
-    if (dicts) {
+    if (dicts && dicts.length > 0) {
       res.value[dictType] = dicts;
     } else {
       await getDicts(dictType).then((resp) => {
+        console.log(`[useDict] 加载字典类型: ${dictType}`, resp.data);
         res.value[dictType] = resp.data.map(
           (p): DictDataOption => ({ label: p.dictLabel, value: p.dictValue, elTagType: p.listClass, elTagClass: p.cssClass })
         );
@@ -22,5 +25,5 @@ export const useDict = (...args: string[]): { [key: string]: DictDataOption[] }
       });
     }
   });
-  return res.value;
+  return toRefs(res.value);
 };

+ 13 - 20
src/views/common/businessActivity.vue

@@ -277,7 +277,7 @@
 
         <el-form-item label="权限:">
           <div class="permission-checkbox">
-            <el-checkbox v-model="memberForm.updateAccredit" :true-label="1" :false-label="0">分配修改权限</el-checkbox>
+            <el-checkbox v-model="memberForm.updateAccredit" :true-value="1" :false-value="0">分配修改权限</el-checkbox>
           </div>
         </el-form-item>
       </el-form>
@@ -293,17 +293,17 @@
 </template>
 
 <script setup>
-import { ref, computed, watch, onMounted, reactive, getCurrentInstance } from 'vue';
+import { ref, computed, watch, onMounted, reactive, getCurrentInstance, toRefs } from 'vue';
 import { User, Search, Plus } from '@element-plus/icons-vue';
 import { listTeamMember, delTeamMember, addTeamMember, updateTeamMember } from "@/api/customer/teamMember";
 import { listRecord, addRecord } from "@/api/visit/record";
 import { listOperateLog } from "@/api/visit/operateLog";
 import { listUser } from "@/api/system/user/index";
-import { listCommonDict } from "@/api/customer/customerDict";
 import { selectStaffOptionList } from "@/api/customer/crmStaff";
 import { globalHeaders } from "@/utils/request";
 
-const { proxy } = getCurrentInstance();
+const proxy = getCurrentInstance().proxy;
+const { visit_type: visitTypeDict, T0001: teamRoleDict } = toRefs(reactive(proxy.useDict("visit_type", "T0001")));
 
 const props = defineProps({
   businessId: [String, Number],
@@ -329,8 +329,6 @@ const submitLoading = ref(false);
 // 状态
 const userOptions = ref([]);
 const staffOptions = ref([]);
-const visitTypeDict = ref([]);
-const teamRoleDict = ref([]);
 const teamList = ref([]);
 const recordList = ref([]);
 const logList = ref([]);
@@ -401,21 +399,22 @@ const computedDataType = computed(() => {
 
 // 统一计算当前业务的对象编号
 const computedObjectNo = computed(() => {
-  // 优先顺序:明确的业务编号 -> 数据库 ID
+  // 对于销售线索、商机、年度入围等核心模块,后端同步团队成员时统一使用的是数据库主键 ID
+  // 因此这里需要优先返回 businessId (即实体 ID)
+  if (['leads', 'opportunity', 'projectSelection', 'platformSelection'].includes(props.businessType)) {
+    return String(props.businessId || '');
+  }
+
+  // 其他模块维持原有的优先业务编号逻辑
   const no = props.infoData?.planNo || 
-             props.infoData?.projectNo || 
              props.infoData?.receiptId || 
              props.infoData?.contactNo || 
              props.infoData?.objectNo || 
-             props.infoData?.customerNo;
+             props.infoData?.customerNo ||
+             props.infoData?.projectNo;
   
   if (no) return String(no);
   
-  // 对于客户类型,兜底使用 ID
-  if (props.businessType === 'customer') {
-    return String(props.businessId || '');
-  }
-  
   return String(props.businessId || '');
 });
 
@@ -481,12 +480,6 @@ const loadStaffs = async () => {
 };
 
 const loadDicts = async () => {
-  listCommonDict("visit_type").then(res => {
-    visitTypeDict.value = (res.data || []).map(d => ({ label: d.dictLabel, value: d.dictValue }));
-  });
-  listCommonDict("T0001").then(res => {
-    teamRoleDict.value = (res.data || []).map(d => ({ label: d.dictLabel, value: d.dictValue }));
-  });
 };
 
 const fetchDynamicData = () => {

+ 5 - 11
src/views/customer/care/add.vue

@@ -94,7 +94,7 @@
             <el-col :span="12">
               <el-form-item label="关怀类型:" prop="concernType">
                 <el-select v-model="form.concernType" placeholder="请选择" style="width: 100%">
-                  <el-option v-for="item in careTypeOptions" :key="item.dictValue" :label="item.dictLabel" :value="item.dictValue" />
+                  <el-option v-for="item in careTypeOptions" :key="item.value" :label="item.label" :value="item.value" />
                 </el-select>
               </el-form-item>
             </el-col>
@@ -160,32 +160,29 @@
 </template>
 
 <script setup name="CustomerCareAdd">
-import { ref, reactive, onMounted, getCurrentInstance } from 'vue';
+import { ref, reactive, onMounted, getCurrentInstance, toRefs } from 'vue';
 import { useRouter } from 'vue-router';
 import { Upload } from '@element-plus/icons-vue';
 import { addCare } from "@/api/customer/crmCare";
-import { listDictByType } from "@/api/customer/customerDict";
 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 { deptTreeSelect } from "@/api/system/user/index";
 
-const { proxy } = getCurrentInstance();
+const proxy = getCurrentInstance().proxy;
+const { care_type: careTypeOptions } = toRefs(reactive(proxy.useDict("care_type")));
 const router = useRouter();
 
 const visible = ref(false);
 const selectLoading = ref(false);
 const contactSearchLoading = ref(false);
-const careTypeOptions = ref([]);
 const customerOptions = ref([]);
 const contactOptions = ref([]);
 const industryOptions = ref([]);
 const staffOptions = ref([]);
 const deptOptions = ref([]);
-const fileList = ref([
-  { name: '新建 文本文档.txt', status: 'success' }
-]);
+const fileList = ref([]);
 
 const form = reactive({
   id: undefined,
@@ -352,9 +349,6 @@ const initBaseOptions = () => {
 };
 
 onMounted(() => {
-  listDictByType('care_type').then(res => {
-    careTypeOptions.value = res.data || [];
-  });
   initBaseOptions();
   remoteLoadCustomers('');
 });

+ 6 - 13
src/views/customer/care/detail.vue

@@ -153,20 +153,19 @@
 </template>
 
 <script setup name="CustomerCareDetail">
-import { ref, onMounted, getCurrentInstance } from 'vue';
+import { ref, onMounted, getCurrentInstance, toRefs } from 'vue';
 import { Close } from '@element-plus/icons-vue';
 import { getCare } from "@/api/customer/crmCare";
-import { listDictByType } from "@/api/customer/customerDict";
 import { selectStaffOptionList } from "@/api/customer/crmStaff";
 import { deptTreeSelect } from "@/api/system/user/index";
 import BusinessActivity from '../../common/businessActivity.vue';
 
-const { proxy } = getCurrentInstance();
+const proxy = getCurrentInstance().proxy;
+const { care_type: careTypeOptions } = toRefs(reactive(proxy.useDict("care_type")));
 
 const visible = ref(false);
 const loading = ref(false);
 const form = ref({});
-const careTypeOptions = ref([]);
 const staffOptions = ref([]);
 const deptOptions = ref([]);
 const fileList = ref([
@@ -196,16 +195,11 @@ function open(id) {
 
 defineExpose({ open });
 
-/** 加载关怀类型字典 */
-function loadCareTypes() {
-  listDictByType('care_type').then(res => {
-    careTypeOptions.value = res.data || [];
-  });
-}
+
 
 const careTypeText = (val) => {
-  const obj = careTypeOptions.value.find(item => item.dictValue === val);
-  return obj ? obj.dictLabel : val;
+  const obj = careTypeOptions.value.find(item => String(item.value) === String(val));
+  return obj ? obj.label : val;
 };
 
 const statusText = (status) => {
@@ -259,7 +253,6 @@ function handleClose() {
 }
 
 onMounted(() => {
-  loadCareTypes();
   initBaseOptions();
 });
 </script>

+ 4 - 8
src/views/customer/care/edit.vue

@@ -94,7 +94,7 @@
             <el-col :span="12">
               <el-form-item label="关怀类型:" prop="concernType">
                 <el-select v-model="form.concernType" placeholder="请选择" style="width: 100%">
-                  <el-option v-for="item in careTypeOptions" :key="item.dictValue" :label="item.dictLabel" :value="item.dictValue" />
+                  <el-option v-for="item in careTypeOptions" :key="item.value" :label="item.label" :value="item.value" />
                 </el-select>
               </el-form-item>
             </el-col>
@@ -149,17 +149,17 @@
 </template>
 
 <script setup name="CustomerCareEdit">
-import { ref, reactive, onMounted, getCurrentInstance } from 'vue';
+import { ref, reactive, onMounted, getCurrentInstance, toRefs } from 'vue';
 import { useRouter, useRoute } from 'vue-router';
 import { getCare, updateCare } from "@/api/customer/crmCare";
-import { listDictByType } from "@/api/customer/customerDict";
 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 { deptTreeSelect } from "@/api/system/user/index";
 
-const { proxy } = getCurrentInstance();
+const proxy = getCurrentInstance().proxy;
+const { care_type: careTypeOptions } = toRefs(reactive(proxy.useDict("care_type")));
 const router = useRouter();
 const route = useRoute();
 
@@ -167,7 +167,6 @@ const visible = ref(false);
 const loading = ref(false);
 const selectLoading = ref(false);
 const contactSearchLoading = ref(false);
-const careTypeOptions = ref([]);
 const customerOptions = ref([]);
 const contactOptions = ref([]);
 const industryOptions = ref([]);
@@ -332,9 +331,6 @@ const initBaseOptions = () => {
 
 onMounted(() => {
   getDetail();
-  listDictByType('care_type').then(res => {
-    careTypeOptions.value = res.data || [];
-  });
   initBaseOptions();
   remoteLoadCustomers('');
 });

+ 6 - 13
src/views/customer/care/index.vue

@@ -164,17 +164,17 @@
 </template>
 
 <script setup name="CustomerCare">
-import { ref, reactive, onMounted, getCurrentInstance, watch } from 'vue';
+import { ref, reactive, onMounted, getCurrentInstance, watch, toRefs } from 'vue';
 import { useRouter, useRoute } from 'vue-router';
 import { Setting, User } from '@element-plus/icons-vue';
 import { listCare, delCare, getCare } from "@/api/customer/crmCare";
-import { listDictByType } from "@/api/customer/customerDict";
 import { listContact } from "@/api/customer/crmContact";
 import { selectStaffOptionList } from "@/api/customer/crmStaff";
 import CareDetail from './detail.vue';
 import CareAdd from './add.vue';
 
-const { proxy } = getCurrentInstance();
+const proxy = getCurrentInstance().proxy;
+const { care_type: careTypeOptions } = toRefs(reactive(proxy.useDict("care_type")));
 const router = useRouter();
 const route = useRoute();
 
@@ -182,7 +182,6 @@ const loading = ref(false);
 const contactSearchLoading = ref(false);
 const total = ref(0);
 const dataList = ref([]);
-const careTypeOptions = ref([]);
 const filterContactOptions = ref([]);
 const activeTab = ref('mine');
 const detailRef = ref(null);
@@ -203,8 +202,8 @@ const queryParams = reactive({
 });
 
 const careTypeText = (val) => {
-  const obj = careTypeOptions.value.find(item => item.dictValue === val);
-  return obj ? obj.dictLabel : val;
+  const obj = careTypeOptions.value.find(item => String(item.value) === String(val));
+  return obj ? obj.label : val;
 };
 
 const statusText = (status) => {
@@ -290,12 +289,7 @@ const loadStaffOptions = () => {
   });
 };
 
-/** 加载关怀类型字典 */
-const loadCareTypes = () => {
-  listDictByType('care_type').then(res => {
-    careTypeOptions.value = res.data || [];
-  });
-};
+
 
 // 监听路由变化,关闭弹窗后刷新列表
 watch(() => route.path, (newPath) => {
@@ -306,7 +300,6 @@ watch(() => route.path, (newPath) => {
 
 onMounted(() => {
   getList();
-  loadCareTypes();
   loadStaffOptions();
   remoteLoadAllContacts('');
 });

+ 1 - 1
src/views/customer/contactPerson/add.vue

@@ -160,7 +160,7 @@ import { addContactPerson } from "@/api/customer/contactPerson";
 import { listCompanyOption, listCustomerInfo } from "@/api/customer/customerInfo/index";
 import { listProvinceWithCities } from "@/api/customer/addressArea";
 
-const { proxy } = getCurrentInstance();
+const proxy = getCurrentInstance().proxy;
 const router = useRouter();
 
 const visible = ref(false);

+ 5 - 9
src/views/customer/contactPerson/detail.vue

@@ -165,18 +165,18 @@
 </template>
 
 <script setup name="ContactPersonDetail">
-import { ref, onMounted, getCurrentInstance } from 'vue';
+import { ref, onMounted, getCurrentInstance, toRefs } from 'vue';
 import { useRouter, useRoute } from 'vue-router';
 import { getContactPerson } from "@/api/customer/contactPerson";
 import { getCustomerInfo } from "@/api/customer/customerInfo/index";
 import { listCare } from "@/api/customer/crmCare";
-import { listCommonDict } from "@/api/customer/customerDict";
 import BusinessActivity from '../../common/businessActivity.vue';
 import ContactEdit from './edit.vue';
 import CareAdd from '../care/add.vue';
 import CareDetail from '../care/detail.vue';
 
-const { proxy } = getCurrentInstance();
+const proxy = getCurrentInstance().proxy;
+const { care_type: careTypeOptions } = toRefs(reactive(proxy.useDict("care_type")));
 const router = useRouter();
 const route = useRoute();
 
@@ -185,7 +185,6 @@ const loading = ref(false);
 const activeTab = ref('info');
 const form = ref({});
 const careList = ref([]);
-const careTypeOptions = ref([]);
 const editRef = ref(null);
 const careAddRef = ref(null);
 const careDetailRef = ref(null);
@@ -268,14 +267,11 @@ function handleClose() {
 /** 字典翻译 */
 function translateDict(value, options) {
   if (!options || !value) return value;
-  const item = options.find(o => String(o.dictValue) === String(value));
-  return item ? item.dictLabel : value;
+  const item = options.find(o => String(o.value) === String(value));
+  return item ? item.label : value;
 }
 
 onMounted(() => {
-  listCommonDict('care_type').then(res => {
-    careTypeOptions.value = res.data || [];
-  });
 });
 
 defineExpose({ open });

+ 5 - 5
src/views/customer/contactPerson/edit.vue

@@ -82,16 +82,16 @@
               <el-col :span="12">
                 <el-form-item label="是否抽烟" prop="isSmoke">
                   <el-radio-group v-model="form.isSmoke">
-                    <el-radio label="1">是</el-radio>
-                    <el-radio label="0">否</el-radio>
+                    <el-radio value="1">是</el-radio>
+                    <el-radio value="0">否</el-radio>
                   </el-radio-group>
                 </el-form-item>
               </el-col>
               <el-col :span="12">
                 <el-form-item label="是否喝酒" prop="isDrink">
                   <el-radio-group v-model="form.isDrink">
-                    <el-radio label="1">是</el-radio>
-                    <el-radio label="0">否</el-radio>
+                    <el-radio value="1">是</el-radio>
+                    <el-radio value="0">否</el-radio>
                   </el-radio-group>
                 </el-form-item>
               </el-col>
@@ -158,7 +158,7 @@ import { useRouter, useRoute } from 'vue-router';
 import { getContactPerson, updateContactPerson } from "@/api/customer/contactPerson";
 import { listProvinceWithCities } from "@/api/customer/addressArea";
 
-const { proxy } = getCurrentInstance();
+const proxy = getCurrentInstance().proxy;
 const router = useRouter();
 const route = useRoute();
 

+ 8 - 10
src/views/customer/contactPerson/index.vue

@@ -8,12 +8,12 @@
         </el-form-item>
         <el-form-item label="联系人类型" prop="roleId" class="custom-form-item">
           <el-select v-model="queryParams.roleId" placeholder="请选择" clearable>
-            <el-option
-              v-for="dict in contactTypeOptions"
-              :key="dict.dictValue"
-              :label="dict.dictLabel"
-              :value="dict.dictValue"
-            />
+              <el-option
+                v-for="dict in contactTypeOptions"
+                :key="dict.value"
+                :label="dict.label"
+                :value="dict.value"
+              />
           </el-select>
         </el-form-item>
         <el-form-item label="性别" prop="gender" class="custom-form-item">
@@ -76,17 +76,16 @@
 import { ref, reactive, toRefs, getCurrentInstance, onMounted, onActivated } from 'vue';
 import { useRouter } from 'vue-router';
 import { listContactPerson, delContactPerson } from "@/api/customer/contactPerson";
-import { listCommonDict } from "@/api/customer/customerDict";
 import ContactDetail from './detail.vue';
 import ContactAdd from './add.vue';
 
-const { proxy } = getCurrentInstance();
+const proxy = getCurrentInstance().proxy;
+const { contact_type: contactTypeOptions } = toRefs(reactive(proxy.useDict("contact_type")));
 const router = useRouter();
 
 const contactPersonList = ref([]);
 const loading = ref(true);
 const total = ref(0);
-const contactTypeOptions = ref([]);
 const detailRef = ref(null);
 const addRef = ref(null);
 
@@ -148,7 +147,6 @@ function handleDelete(row) {
 
 onMounted(() => {
   getList();
-  listCommonDict("contact_type").then(res => { contactTypeOptions.value = res.data || []; });
 });
 </script>
 

+ 10 - 9
src/views/customer/highseas/detail.vue

@@ -169,16 +169,16 @@
             <el-col :span="8">
               <el-form-item label="联系人类型" prop="type">
                 <el-radio-group v-model="contactForm.type">
-                  <el-radio label="1">公司职员</el-radio>
-                  <el-radio label="2">关系资源人</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="8">
               <el-form-item label="性别" prop="gender">
                 <el-radio-group v-model="contactForm.gender">
-                  <el-radio label="1">男</el-radio>
-                  <el-radio label="2">女</el-radio>
+                  <el-radio value="1">男</el-radio>
+                  <el-radio value="2">女</el-radio>
                 </el-radio-group>
               </el-form-item>
             </el-col>
@@ -210,8 +210,8 @@
             <el-col :span="8">
               <el-form-item label="在职状态" prop="jobStatus">
                 <el-radio-group v-model="contactForm.jobStatus">
-                  <el-radio label="1">在职</el-radio>
-                  <el-radio label="2">离职</el-radio>
+                  <el-radio value="1">在职</el-radio>
+                  <el-radio value="2">离职</el-radio>
                 </el-radio-group>
               </el-form-item>
             </el-col>
@@ -290,12 +290,12 @@
           <el-row :gutter="20">
             <el-col :span="8">
               <el-form-item label="是否抽烟" prop="isSmoke">
-                <el-radio-group v-model="contactForm.isSmoke"><el-radio label="1">是</el-radio><el-radio label="0">否</el-radio></el-radio-group>
+                <el-radio-group v-model="contactForm.isSmoke"><el-radio value="1">是</el-radio><el-radio value="0">否</el-radio></el-radio-group>
               </el-form-item>
             </el-col>
             <el-col :span="8">
               <el-form-item label="是否喝酒" prop="isDrink">
-                <el-radio-group v-model="contactForm.isDrink"><el-radio label="1">是</el-radio><el-radio label="0">否</el-radio></el-radio-group>
+                <el-radio-group v-model="contactForm.isDrink"><el-radio value="1">是</el-radio><el-radio value="0">否</el-radio></el-radio-group>
               </el-form-item>
             </el-col>
           </el-row>
@@ -325,7 +325,8 @@ import { listTeamMember } from "@/api/customer/teamMember";
 import BusinessActivity from '../../common/businessActivity.vue';
 import CustomerEdit from './edit.vue';
 
-const { proxy } = getCurrentInstance();
+const emit = defineEmits(['success']);
+const proxy = getCurrentInstance().proxy;
 const visible = ref(false);
 const loading = ref(false);
 const customerData = ref({});

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

@@ -51,7 +51,7 @@
             <el-col :span="8">
               <el-form-item label="企业类型" prop="enterpriseTypeId">
                 <el-select v-model="form.enterpriseTypeId" placeholder="请选择" class="w100" clearable>
-                  <el-option v-for="item in dict.enterprise_type" :key="item.value" :label="item.label" :value="item.value" />
+                  <el-option v-for="item in dict.Q0001" :key="item.value" :label="item.label" :value="item.value" />
                 </el-select>
               </el-form-item>
             </el-col>
@@ -264,10 +264,10 @@ import { selectStaffOptionList } from "@/api/customer/crmStaff";
 import { listProvinceWithCities } from "@/api/customer/addressArea";
 import ImageUpload from "@/components/ImageUpload";
 
-const { proxy } = getCurrentInstance();
+const proxy = getCurrentInstance().proxy;
 const dict = proxy.useDict(
   'customer_source', 
-  'enterprise_type', 
+  'Q0001', 
   'enterprise_scale', 
   'customer_type', 
   'industry_category',
@@ -390,7 +390,7 @@ const loadData = (id) => {
       return (list || []).find(i => i.label === label)?.value;
     };
 
-    form.enterpriseTypeId = getDictValue(dict.enterprise_type, data.enterpriseTypeName);
+    form.enterpriseTypeId = getDictValue(dict.Q0001, data.enterpriseTypeName);
     form.customerTypeId = getDictValue(dict.customer_type, data.customerTypeName);
 
     // 基础字典项 (这些通常已有 code 映射)

+ 7 - 17
src/views/customer/highseas/index.vue

@@ -54,7 +54,7 @@
           </el-col>          <el-col :span="6">
             <el-form-item label="合作状态" prop="cooperation" class="custom-form-item">
               <el-select v-model="queryParams.cooperation" placeholder="请选择" clearable style="width: 100%">
-                <el-option v-for="item in cooperationOptions" :key="item.dictValue" :label="item.dictLabel" :value="item.dictValue" />
+                <el-option v-for="item in cooperationOptions" :key="item.value" :label="item.label" :value="item.value" />
               </el-select>
             </el-form-item>
           </el-col>
@@ -65,7 +65,7 @@
           <el-col :span="6">
             <el-form-item label="企业类型" prop="enterpriseTypeId" class="custom-form-item">
               <el-select v-model="queryParams.enterpriseTypeId" placeholder="请选择" clearable style="width: 100%">
-                <el-option v-for="item in corpTypeOptions" :key="item.dictValue" :label="item.dictLabel" :value="item.dictValue" />
+                <el-option v-for="item in corpTypeOptions" :key="item.value" :label="item.label" :value="item.value" />
               </el-select>
             </el-form-item>
           </el-col>
@@ -135,8 +135,8 @@
         </el-form-item>
         <el-form-item label="保留已有负责人:" prop="keepOwner">
           <el-radio-group v-model="claimForm.keepOwner">
-            <el-radio label="1">是</el-radio>
-            <el-radio label="0">否</el-radio>
+            <el-radio value="1">是</el-radio>
+            <el-radio value="0">否</el-radio>
           </el-radio-group>
         </el-form-item>
       </el-form>
@@ -151,17 +151,17 @@
 </template>
 
 <script setup name="CustomerHighSeas">
-import { ref, reactive, onMounted, getCurrentInstance } from 'vue';
+import { ref, reactive, onMounted, getCurrentInstance, toRefs } from 'vue';
 import { useRouter } from 'vue-router';
 import { listPool, claimPool } from "@/api/customer/customerPool";
 import { listIndustryCategory } from "@/api/customer/industryCategory";
-import { listDictByType } from "@/api/customer/customerDict";
 import { listLevel } from "@/api/customer/customerLevel";
 import { selectStaffOptionList } from "@/api/customer/crmStaff";
 import { debounce } from 'lodash-es';
 import CustomerDetail from "./detail.vue";
 
-const { proxy } = getCurrentInstance();
+const proxy = getCurrentInstance().proxy;
+const { Q0001: corpTypeOptions, cooperation_status: cooperationOptions } = toRefs(reactive(proxy.useDict("Q0001", "cooperation_status")));
 const router = useRouter();
 
 const loading = ref(false);
@@ -171,8 +171,6 @@ const dataList = ref([]);
 // 下拉选项数据
 const industryOptions = ref([]);
 const levelOptions = ref([]);
-const corpTypeOptions = ref([]);
-const cooperationOptions = ref([]);
 const staffOptions = ref([]);
 const infoRef = ref(null);
 const tableRef = ref(null);
@@ -223,14 +221,6 @@ const getOptions = async () => {
     
     const staffRes = await selectStaffOptionList();
     staffOptions.value = staffRes.data || [];
-    
-    listDictByType('enterprise_type').then(response => {
-      corpTypeOptions.value = response.data || [];
-    }).catch(() => {});
-    
-    listDictByType('cooperation_status').then(response => {
-      cooperationOptions.value = response.data || [];
-    }).catch(() => {});
   } catch (err) {
     console.error('获取选项失败:', err);
   }

+ 25 - 28
src/views/customer/valid/detail.vue

@@ -400,16 +400,16 @@
               <el-col :span="8">
                 <el-form-item label="联系人类型" prop="roleId">
                   <el-radio-group v-model="contactForm.roleId">
-                    <el-radio label="1">公司职员</el-radio>
-                    <el-radio label="2">关系资源人</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="8">
                 <el-form-item label="性别" prop="gender">
                   <el-radio-group v-model="contactForm.gender">
-                    <el-radio label="0">男</el-radio>
-                    <el-radio label="1">女</el-radio>
+                    <el-radio value="0">男</el-radio>
+                    <el-radio value="1">女</el-radio>
                   </el-radio-group>
                 </el-form-item>
               </el-col>
@@ -446,8 +446,8 @@
               <el-col :span="8">
                 <el-form-item label="在职状态" prop="status">
                   <el-radio-group v-model="contactForm.status">
-                    <el-radio label="0">在职</el-radio>
-                    <el-radio label="1">离职</el-radio>
+                    <el-radio value="0">在职</el-radio>
+                    <el-radio value="1">离职</el-radio>
                   </el-radio-group>
                 </el-form-item>
               </el-col>
@@ -540,16 +540,16 @@
               <el-col :span="8">
                 <el-form-item label="是否抽烟" prop="isSmoke">
                   <el-radio-group v-model="contactForm.isSmoke">
-                    <el-radio label="1">是</el-radio>
-                    <el-radio label="0">否</el-radio>
+                    <el-radio value="1">是</el-radio>
+                    <el-radio value="0">否</el-radio>
                   </el-radio-group>
                 </el-form-item>
               </el-col>
               <el-col :span="8">
                 <el-form-item label="是否喝酒" prop="isDrink">
                   <el-radio-group v-model="contactForm.isDrink">
-                    <el-radio label="1">是</el-radio>
-                    <el-radio label="0">否</el-radio>
+                    <el-radio value="1">是</el-radio>
+                    <el-radio value="0">否</el-radio>
                   </el-radio-group>
                 </el-form-item>
               </el-col>
@@ -624,7 +624,7 @@
               <el-col :span="12">
                 <el-form-item label="关怀类型" prop="concernType">
                   <el-select v-model="careForm.concernType" placeholder="请选择" style="width: 100%">
-                    <el-option v-for="item in careTypeOptions" :key="item.dictValue" :label="item.dictLabel" :value="item.dictValue" />
+                    <el-option v-for="item in careTypeOptions" :key="item.value" :label="item.label" :value="item.value" />
                   </el-select>
                 </el-form-item>
               </el-col>
@@ -680,7 +680,7 @@
 </template>
 
 <script setup name="CustomerValidDetail">
-import { ref, reactive, computed, onMounted, getCurrentInstance } from 'vue';
+import { ref, reactive, computed, onMounted, getCurrentInstance, toRefs } from 'vue';
 import { useRoute, useRouter } from 'vue-router';
 import { Close, Edit, Plus, Search, UserFilled, Upload } from '@element-plus/icons-vue';
 import { getCustomerInfo } from "@/api/customer/customerInfo/index";
@@ -693,16 +693,22 @@ import { listFileInfo, delFileInfo, addFileInfo } from "@/api/file/info/index";
 import { listByIds } from "@/api/system/oss";
 import { getContactPerson, addContactPerson, updateContactPerson, delContactPerson } from "@/api/customer/contactPerson";
 import { listProvinceWithCities } from "@/api/customer/addressArea";
-import { listCommonDict } from "@/api/customer/customerDict";
 import { getToken } from "@/utils/auth";
 import { globalHeaders } from "@/utils/request";
 import BusinessActivity from '../../common/businessActivity.vue';
 import CustomerEdit from "./edit.vue";
 import CareDetail from "../care/detail.vue";
 
-const { proxy } = getCurrentInstance();
+const proxy = getCurrentInstance().proxy;
+const { 
+  care_type: careTypeOptions, 
+  opportunity_level: opportunityLevelOptions, 
+  annual_level: annualLevelOptions, 
+  project_type: projectTypeOptions 
+} = toRefs(reactive(proxy.useDict("care_type", "opportunity_level", "annual_level", "project_type")));
 const route = useRoute();
 const router = useRouter();
+const emit = defineEmits(['success']);
 
 const loading = ref(false);
 const visible = ref(false);
@@ -719,9 +725,9 @@ const activeMainTab = ref('profile');
 const editRef = ref(null);
 const careDetailRef = ref(null);
 const dictOptions = reactive({
-  opportunityLevel: [],
-  annualLevel: [],
-  projectType: []
+  opportunityLevel: opportunityLevelOptions,
+  annualLevel: annualLevelOptions,
+  projectType: projectTypeOptions
 });
 
 // 客户联系人相关状态
@@ -759,7 +765,6 @@ const contactForm = reactive({
 // 客户关怀新增相关状态
 const careVisible = ref(false);
 const careFileList = ref([]);
-const careTypeOptions = ref([]);
 const careContactOptions = ref([]);
 const careForm = reactive({
   customerId: undefined,
@@ -1083,14 +1088,6 @@ onMounted(() => {
   listProvinceWithCities().then(res => {
     areaOptions.value = res.data || [];
   });
-  
-  // 加载字典
-  listCommonDict('L0001').then(res => dictOptions.opportunityLevel = res.data || []);
-  listCommonDict('XMJB0001').then(res => dictOptions.annualLevel = res.data || []);
-  listCommonDict('project_type').then(res => dictOptions.projectType = res.data || []);
-  
-  // 加载关怀类型
-  listCommonDict('care_type').then(res => careTypeOptions.value = res.data || []);
 });
 
 /** 客户关怀相关方法 */
@@ -1149,8 +1146,8 @@ const handleCareDetail = (row) => {
 /** 字典翻译 */
 function translateDict(value, options) {
   if (!options || !value) return value;
-  const item = options.find(o => String(o.dictValue) === String(value));
-  return item ? item.dictLabel : value;
+  const item = options.find(o => String(o.value) === String(value));
+  return item ? item.label : value;
 }
 
 defineExpose({ open });

+ 6 - 9
src/views/customer/valid/edit.vue

@@ -49,14 +49,14 @@
             <el-col :span="8">
               <el-form-item label="客户来源" prop="customerSourceId">
                 <el-select v-model="form.customerSourceId" placeholder="请选择" class="w100">
-                  <el-option v-for="item in sourceOptions" :key="item.dictValue" :label="item.dictLabel" :value="item.dictValue" />
+                  <el-option v-for="item in sourceOptions" :key="item.value" :label="item.label" :value="item.value" />
                 </el-select>
               </el-form-item>
             </el-col>
             <el-col :span="8">
               <el-form-item label="企业类型" prop="enterpriseTypeId">
                 <el-select v-model="form.enterpriseTypeId" placeholder="请选择" class="w100">
-                  <el-option v-for="item in corpTypeOptions" :key="item.dictValue" :label="item.dictLabel" :value="item.dictValue" />
+                  <el-option v-for="item in corpTypeOptions" :key="item.value" :label="item.label" :value="item.value" />
                 </el-select>
               </el-form-item>
             </el-col>
@@ -268,18 +268,19 @@
 </template>
 
 <script setup name="CustomerValidEdit">
-import { ref, reactive, onMounted, getCurrentInstance } from 'vue';
+import { ref, reactive, onMounted, getCurrentInstance, toRefs } from 'vue';
 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 { listDictByType, listCommonDict, listCustomerTypeOption } from "@/api/customer/customerDict";
+import { listCustomerTypeOption } from "@/api/customer/customerDict";
 import { listEnterpriseScale } from "@/api/customer/enterpriseScale";
 import { listProvinceWithCities } from "@/api/customer/addressArea";
 import { deptTreeSelect } from "@/api/system/dept";
 
-const { proxy } = getCurrentInstance();
+const proxy = getCurrentInstance().proxy;
+const { customer_source: sourceOptions, Q0001: corpTypeOptions } = toRefs(reactive(proxy.useDict("customer_source", "Q0001")));
 const route = useRoute();
 const router = useRouter();
 
@@ -343,8 +344,6 @@ const companyOptions = ref([]);
 const industryOptions = ref([]);
 const levelOptions = ref([]);
 const staffOptions = ref([]);
-const sourceOptions = ref([]);
-const corpTypeOptions = ref([]);
 const scaleOptions = ref([]);
 const categoryOptions = ref([]);
 const areaOptions = ref([]);
@@ -355,8 +354,6 @@ const initOptions = async () => {
   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));
-  listCommonDict("K0001").then(res => sourceOptions.value = res.data || []).catch(e => console.error("通用字典接口404或出错", e));
-  listDictByType("enterprise_type").then(res => corpTypeOptions.value = 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 || [];

+ 5 - 9
src/views/customer/valid/index.vue

@@ -64,14 +64,14 @@
           <el-col :span="6">
             <el-form-item label="合作状态" prop="cooperation" class="custom-form-item">
               <el-select v-model="queryParams.cooperation" placeholder="请选择" clearable style="width: 100%">
-                <el-option v-for="item in cooperationOptions" :key="item.dictValue" :label="item.dictLabel" :value="item.dictValue" />
+                <el-option v-for="item in cooperationOptions" :key="item.value" :label="item.label" :value="item.value" />
               </el-select>
             </el-form-item>
           </el-col>
           <el-col :span="6">
             <el-form-item label="企业类型" prop="enterpriseTypeId" class="custom-form-item">
               <el-select v-model="queryParams.enterpriseTypeId" placeholder="请选择" clearable style="width: 100%">
-                <el-option v-for="item in corpTypeOptions" :key="item.dictValue" :label="item.dictLabel" :value="item.dictValue" />
+                <el-option v-for="item in corpTypeOptions" :key="item.value" :label="item.label" :value="item.value" />
               </el-select>
             </el-form-item>
           </el-col>
@@ -174,17 +174,17 @@
 </template>
 
 <script setup name="CustomerValid">
-import { ref, reactive, onMounted, getCurrentInstance } from 'vue';
+import { ref, reactive, onMounted, getCurrentInstance, toRefs } from 'vue';
 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 { listDictByType } from "@/api/customer/customerDict";
 import { debounce } from 'lodash-es';
 import CustomerDetail from "./detail.vue";
 
-const { proxy } = getCurrentInstance();
+const proxy = getCurrentInstance().proxy;
+const { Q0001: corpTypeOptions, cooperation_status: cooperationOptions } = toRefs(reactive(proxy.useDict("Q0001", "cooperation_status")));
 const router = useRouter();
 
 const loading = ref(false);
@@ -198,8 +198,6 @@ const industryOptions = ref([]);
 const staffOptions = ref([]);
 const companyOptions = ref([]);
 const levelOptions = ref([]);
-const corpTypeOptions = ref([]);
-const cooperationOptions = ref([]);
 
 const activeTab = ref('all');
 const tabs = [
@@ -343,8 +341,6 @@ const initOptions = async () => {
   listIndustryCategory().then(res => industryOptions.value = res.data || []);
   listLevel().then(res => levelOptions.value = res.rows || []);
   selectStaffOptionList().then(res => staffOptions.value = res.data || []);
-  listDictByType("enterprise_type").then(res => corpTypeOptions.value = res.data || []);
-  listDictByType("cooperation_status").then(res => cooperationOptions.value = res.data || []);
 };
 
 onMounted(() => {

+ 2 - 2
src/views/sale/customerTarget/index.vue

@@ -87,8 +87,8 @@
         <el-form label-width="100px">
           <el-form-item label="任务制定:" required>
             <el-radio-group v-model="targetType">
-              <el-radio label="year">年度任务制定</el-radio>
-              <el-radio label="month">月度任务制定</el-radio>
+              <el-radio value="year">年度任务制定</el-radio>
+              <el-radio value="month">月度任务制定</el-radio>
             </el-radio-group>
           </el-form-item>
         </el-form>

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

@@ -133,8 +133,8 @@
           <el-col :span="12">
             <el-form-item label="是否欠款:" prop="izArrears">
               <el-radio-group v-model="form.izArrears">
-                <el-radio :label="1">是</el-radio>
-                <el-radio :label="0">否</el-radio>
+                <el-radio :value="1">是</el-radio>
+                <el-radio :value="0">否</el-radio>
               </el-radio-group>
             </el-form-item>
           </el-col>
@@ -182,7 +182,7 @@ import { ref, reactive, onMounted, getCurrentInstance } from 'vue';
 import { listAccountsReceivable, addAccountsReceivable, updateAccountsReceivable, delAccountsReceivable } from '@/api/saleManage/accountsReceivable/index';
 import { selectStaffOptionList } from "@/api/system/comStaff/index";
 
-const { proxy } = getCurrentInstance();
+const proxy = getCurrentInstance().proxy;
 
 const loading = ref(false);
 const total = ref(0);

+ 11 - 11
src/views/saleManage/leads/add.vue

@@ -230,7 +230,7 @@ const props = defineProps({
 });
 
 const emit = defineEmits(['update:modelValue', 'success']);
-const { proxy } = getCurrentInstance();
+const proxy = getCurrentInstance().proxy;
 
 const visible = ref(false);
 const submitting = ref(false);
@@ -264,6 +264,16 @@ const rules = reactive({
   projectDescription: [{ required: true, message: '项目描述不能为空', trigger: 'blur' }],
 });
 
+const remoteLoadCustomers = (query) => {
+  customerLoading.value = true;
+  listCustomerOption({ customerName: query, isHighSeas: 'all' }).then(res => {
+    const list = res.data || res.rows || [];
+    localCustomerOptions.value = list.map(i => ({ ...i, customerNo: String(i.customerNo) }));
+  }).finally(() => {
+    customerLoading.value = false;
+  });
+};
+
 watch(() => props.modelValue, (val) => { 
   visible.value = val; 
   if (val) {
@@ -303,16 +313,6 @@ const reset = () => {
   if (formRef.value) formRef.value.resetFields();
 };
 
-const remoteLoadCustomers = (query) => {
-  customerLoading.value = true;
-  listCustomerOption({ customerName: query, isHighSeas: 'all' }).then(res => {
-    const list = res.data || res.rows || [];
-    localCustomerOptions.value = list.map(i => ({ ...i, customerNo: String(i.customerNo) }));
-  }).finally(() => {
-    customerLoading.value = false;
-  });
-};
-
 const handleCustomerChange = (no) => {
   const customer = localCustomerOptions.value.find(i => String(i.customerNo) === String(no));
   if (customer) {

+ 20 - 25
src/views/saleManage/leads/detail.vue

@@ -102,9 +102,7 @@
                 </el-table-column>
                 <el-table-column label="性别" align="center" width="80">
                   <template #default="scope">
-                    <span v-if="(scope.row.sex || scope.row.gender) === '0'">男</span>
-                    <span v-else-if="(scope.row.sex || scope.row.gender) === '1'">女</span>
-                    <span v-else>{{ scope.row.sex || scope.row.gender || '' }}</span>
+                    <dict-tag :options="genderOptions" :value="scope.row.sex || scope.row.gender" />
                   </template>
                 </el-table-column>
                 <el-table-column label="部门" align="center" width="120">
@@ -284,16 +282,16 @@
             <el-col :span="8">
               <el-form-item label="联系人类型" prop="roleId" required>
                 <el-radio-group v-model="editContactForm.roleId">
-                  <el-radio label="1">公司职员</el-radio>
-                  <el-radio label="2">关系资源人</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="8">
               <el-form-item label="性别" prop="gender" required>
                 <el-radio-group v-model="editContactForm.gender">
-                  <el-radio label="0">男</el-radio>
-                  <el-radio label="1">女</el-radio>
+                  <el-radio value="0">男</el-radio>
+                  <el-radio value="1">女</el-radio>
                 </el-radio-group>
               </el-form-item>
             </el-col>
@@ -331,8 +329,8 @@
             <el-col :span="8">
               <el-form-item label="在职状态" prop="status" required>
                 <el-radio-group v-model="editContactForm.status">
-                  <el-radio label="0">在职</el-radio>
-                  <el-radio label="1">离职</el-radio>
+                  <el-radio value="0">在职</el-radio>
+                  <el-radio value="1">离职</el-radio>
                 </el-radio-group>
               </el-form-item>
             </el-col>
@@ -386,9 +384,9 @@
                 <el-select v-model="editContactForm.projectRole" placeholder="请选择" style="width:100%" clearable>
                   <el-option
                     v-for="dict in projectRoleOptions"
-                    :key="dict.dictValue"
-                    :label="dict.dictLabel"
-                    :value="dict.dictValue"
+                    :key="dict.value"
+                    :label="dict.label"
+                    :value="dict.value"
                   />
                 </el-select>
               </el-form-item>
@@ -444,16 +442,16 @@
             <el-col :span="8">
               <el-form-item label="是否抽烟" prop="isSmoking">
                 <el-radio-group v-model="editContactForm.isSmoking">
-                  <el-radio label="1">是</el-radio>
-                  <el-radio label="0">否</el-radio>
+                  <el-radio value="1">是</el-radio>
+                  <el-radio value="0">否</el-radio>
                 </el-radio-group>
               </el-form-item>
             </el-col>
             <el-col :span="8">
               <el-form-item label="是否喝酒" prop="isDrinking">
                 <el-radio-group v-model="editContactForm.isDrinking">
-                  <el-radio label="1">是</el-radio>
-                  <el-radio label="0">否</el-radio>
+                  <el-radio value="1">是</el-radio>
+                  <el-radio value="0">否</el-radio>
                 </el-radio-group>
               </el-form-item>
             </el-col>
@@ -504,11 +502,10 @@
 </template>
 
 <script setup>
-import { ref, reactive, watch, getCurrentInstance } from 'vue';
+import { ref, reactive, watch, getCurrentInstance, toRefs } from 'vue';
 import { getLeads, updateLeads } from '@/api/saleManage/leads/index';
 import { listContact, updateContact, delContact } from '@/api/customer/crmContact';
 import { getContactPerson } from "@/api/customer/contactPerson";
-import { listCommonDict } from "@/api/customer/customerDict";
 import { getSalesResultAnalyzeByObjectNo, addSalesResultAnalyze, updateSalesResultAnalyze } from '@/api/saleManage/leads/salesResultAnalyze';
 import { listByIds } from '@/api/system/oss/index';
 import { globalHeaders } from '@/utils/request';
@@ -548,8 +545,11 @@ const contactForm = ref({});
 const editContactVisible = ref(false);
 const editContactLoading = ref(false);
 const editContactForm = ref({});
-const projectRoleOptions = ref([]);
-const { proxy } = getCurrentInstance();
+const proxy = getCurrentInstance().proxy;
+const { 
+  LXRJE0001: projectRoleOptions,
+  sys_user_sex: genderOptions
+} = toRefs(reactive(proxy.useDict("LXRJE0001", "sys_user_sex")));
 
 const uploadFileUrl = import.meta.env.VITE_APP_BASE_API + '/resource/oss/upload';
 const headers = globalHeaders();
@@ -577,11 +577,6 @@ watch(() => [props.id, visible.value], ([newId, isVisible]) => {
 }, { immediate: true });
 
 const loadDicts = () => {
-  if (projectRoleOptions.value.length === 0) {
-    listCommonDict("LXRJE0001").then(res => {
-      projectRoleOptions.value = res.data || [];
-    });
-  }
 };
 
 const getDetail = (id) => {

+ 1 - 1
src/views/saleManage/leads/edit.vue

@@ -181,7 +181,7 @@ const props = defineProps({
 });
 
 const emit = defineEmits(['update:modelValue', 'success']);
-const { proxy } = getCurrentInstance();
+const proxy = getCurrentInstance().proxy;
 
 const visible = ref(false);
 const loading = ref(false);

+ 10 - 18
src/views/saleManage/leads/index.vue

@@ -72,7 +72,7 @@
           <el-col :span="6">
             <el-form-item label="时间查询类型" prop="timeType">
               <el-select v-model="queryParams.timeType" style="width: 100%" clearable>
-                <el-option v-for="item in timeTypeOptions" :key="item.dictValue" :label="item.dictLabel" :value="item.dictValue" />
+                <el-option v-for="item in timeTypeOptions" :key="item.value" :label="item.label" :value="item.value" />
               </el-select>
             </el-form-item>
           </el-col>
@@ -292,11 +292,10 @@
 </template>
 
 <script setup name="SalesLeads">
-import { ref, reactive, onMounted, computed, getCurrentInstance } from 'vue';
+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 { listCompanyOption, listCustomerOption } from "@/api/customer/customerInfo/index";
-import { listCommonDict } from "@/api/customer/customerDict";
 import { listIndustryCategory } from "@/api/customer/industryCategory";
 import { deptTreeSelect } from "@/api/system/user";
 import { Search, Refresh, Plus, Switch, Link, InfoFilled } from '@element-plus/icons-vue';
@@ -306,7 +305,7 @@ import LeadsAdd from './add.vue';
 import LeadsEdit from './edit.vue';
 import LeadsDetail from './detail.vue';
 
-const { proxy } = getCurrentInstance();
+const proxy = getCurrentInstance().proxy;
 const loading = ref(false);
 const total = ref(0);
 const leadsList = ref([]);
@@ -336,15 +335,17 @@ const claimForm = reactive({
   keepOldManager: false
 });
 const userStore = useUserStore();
-const saleStatusOptions = ref([]);
+const { 
+  J0001: saleStatusOptions, 
+  time_query_type: timeTypeOptions, 
+  L0001: projectLevelOptions, 
+  X0001: procurementMethodOptions, 
+  X0002: infoSourceOptions 
+} = toRefs(reactive(proxy.useDict('J0001', 'time_query_type', 'L0001', 'X0001', 'X0002')));
 const customerOptions = ref([]);
 const industryOptions = ref([]);
-const projectLevelOptions = ref([]);
-const procurementMethodOptions = ref([]);
-const infoSourceOptions = ref([]);
 const marketingActivityOptions = ref([]);
 const deptOptions = ref([]);
-const timeTypeOptions = ref([]);
 
 const customerLoading = ref(false);
 const localCustomerOptions = ref([]);
@@ -403,16 +404,7 @@ 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) })));
-  listCustomerOption({ isHighSeas: 'all' }).then(res => {
-    const list = res.data || res.rows || [];
-    customerOptions.value = list.map(i => ({ ...i, customerNo: String(i.customerNo) }));
-  });
   listIndustryCategory().then(res => industryOptions.value = res.data);
-  listCommonDict('J0001').then(res => saleStatusOptions.value = res.data.map(i => ({ value: String(i.dictValue), label: i.dictLabel })));
-  listCommonDict('L0001').then(res => projectLevelOptions.value = res.data.map(i => ({ value: String(i.dictValue), label: i.dictLabel })));
-  listCommonDict('X0001').then(res => procurementMethodOptions.value = res.data.map(i => ({ value: String(i.dictValue), label: i.dictLabel })));
-  listCommonDict('X0002').then(res => infoSourceOptions.value = res.data.map(i => ({ value: String(i.dictValue), label: i.dictLabel })));
-  listCommonDict('time_query_type').then(res => timeTypeOptions.value = res.data);
   deptTreeSelect().then(res => deptOptions.value = res.data);
 };
 

+ 38 - 11
src/views/saleManage/opportunity/add.vue

@@ -24,8 +24,18 @@
               </el-col>
               <el-col :span="12">
                 <el-form-item label="客户名称" prop="customerNo">
-                  <el-select v-model="form.customerNo" placeholder="请选择" style="width: 100%" clearable filterable @change="handleCustomerChange">
-                    <el-option v-for="item in customerOptions" :key="item.id"
+                  <el-select 
+                    v-model="form.customerNo" 
+                    placeholder="请输入关键字搜索客户" 
+                    style="width: 100%" 
+                    clearable 
+                    filterable 
+                    remote
+                    :remote-method="remoteLoadCustomers"
+                    :loading="customerLoading"
+                    @change="handleCustomerChange"
+                  >
+                    <el-option v-for="item in localCustomerOptions" :key="item.id"
                       :label="item.customerName" :value="String(item.id || item.customerNo)" />
                   </el-select>
                 </el-form-item>
@@ -88,8 +98,8 @@
               <el-col :span="8">
                 <el-form-item label="项目级别" prop="projectLevel">
                   <el-select v-model="form.projectLevel" placeholder="请选择" style="width: 100%" clearable filterable>
-                    <el-option v-for="item in projectLevelOptions" :key="item.dictValue"
-                      :label="item.dictLabel" :value="item.dictValue" />
+                    <el-option v-for="item in projectLevelOptions" :key="item.value"
+                      :label="item.label" :value="item.value" />
                   </el-select>
                 </el-form-item>
               </el-col>
@@ -101,8 +111,8 @@
               <el-col :span="8">
                 <el-form-item label="采购方式" prop="purchaseMethod">
                   <el-select v-model="form.purchaseMethod" placeholder="请选择" style="width: 100%" clearable filterable>
-                    <el-option v-for="item in procurementMethodOptions" :key="item.dictValue"
-                      :label="item.dictLabel" :value="item.dictValue" />
+                    <el-option v-for="item in procurementMethodOptions" :key="item.value"
+                      :label="item.label" :value="item.value" />
                   </el-select>
                 </el-form-item>
               </el-col>
@@ -111,8 +121,8 @@
               <el-col :span="8">
                 <el-form-item label="商机来源" prop="source">
                   <el-select v-model="form.source" placeholder="请选择" style="width: 100%" clearable filterable>
-                    <el-option v-for="item in infoSourceOptions" :key="item.dictValue"
-                      :label="item.dictLabel" :value="item.dictValue" />
+                    <el-option v-for="item in infoSourceOptions" :key="item.value"
+                      :label="item.label" :value="item.value" />
                   </el-select>
                 </el-form-item>
               </el-col>
@@ -164,6 +174,7 @@
 <script setup>
 import { ref, reactive, watch, getCurrentInstance } from 'vue';
 import { addOpportunity } from '@/api/saleManage/opportunity/index';
+import { listCustomerOption } from "@/api/customer/customerInfo/index";
 import { globalHeaders } from '@/utils/request';
 import { Close, Upload } from '@element-plus/icons-vue';
 
@@ -179,7 +190,7 @@ const props = defineProps({
 });
 
 const emit = defineEmits(['update:modelValue', 'success']);
-const { proxy } = getCurrentInstance();
+const proxy = getCurrentInstance().proxy;
 
 const visible = ref(false);
 const submitting = ref(false);
@@ -188,12 +199,25 @@ const fileList = ref([]);
 const uploadFileUrl = import.meta.env.VITE_APP_BASE_API + '/resource/oss/upload';
 const headers = globalHeaders();
 
+const customerLoading = ref(false);
+const localCustomerOptions = ref([]);
+
 const form = reactive({
   izClue: 0,
   projectType: '销售商机',
   status: '0'
 });
 
+const remoteLoadCustomers = (query) => {
+  customerLoading.value = true;
+  listCustomerOption({ customerName: query, isHighSeas: 'all' }).then(res => {
+    const list = res.data || res.rows || [];
+    localCustomerOptions.value = list.map(i => ({ ...i, customerNo: String(i.customerNo) }));
+  }).finally(() => {
+    customerLoading.value = false;
+  });
+};
+
 const rules = reactive({
   companyId: [{ required: true, message: '归属公司不能为空', trigger: 'change' }],
   customerNo: [{ required: true, message: '客户名称不能为空', trigger: 'change' }],
@@ -206,7 +230,10 @@ const rules = reactive({
 
 watch(() => props.modelValue, (val) => {
   visible.value = val;
-  if (val) reset();
+  if (val) {
+    reset();
+    remoteLoadCustomers('');
+  }
 });
 watch(() => visible.value, (val) => { emit('update:modelValue', val); });
 
@@ -240,7 +267,7 @@ const reset = () => {
 };
 
 const handleCustomerChange = (val) => {
-  const customer = props.customerOptions.find(c => String(c.id || c.customerNo) === val);
+  const customer = localCustomerOptions.value.find(c => String(c.id || c.customerNo) === val);
   if (customer) {
     form.customerName = customer.customerName;
     form.profession = customer.industryCategoryId;

+ 15 - 20
src/views/saleManage/opportunity/detail.vue

@@ -269,16 +269,16 @@
                 <el-col :span="8">
                   <el-form-item label="联系人类型" prop="contactType">
                     <el-radio-group v-model="projectContactForm.contactType">
-                      <el-radio label="1">公司职员</el-radio>
-                      <el-radio label="2">关系资源人</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="8">
                   <el-form-item label="性别" prop="sex">
                     <el-radio-group v-model="projectContactForm.sex">
-                      <el-radio label="0">男</el-radio>
-                      <el-radio label="1">女</el-radio>
+                      <el-radio value="0">男</el-radio>
+                      <el-radio value="1">女</el-radio>
                     </el-radio-group>
                   </el-form-item>
                 </el-col>
@@ -318,8 +318,8 @@
                 <el-col :span="8">
                   <el-form-item label="在职状态" prop="status">
                     <el-radio-group v-model="projectContactForm.status">
-                      <el-radio label="0">在职</el-radio>
-                      <el-radio label="1">离职</el-radio>
+                      <el-radio value="0">在职</el-radio>
+                      <el-radio value="1">离职</el-radio>
                     </el-radio-group>
                   </el-form-item>
                 </el-col>
@@ -374,7 +374,7 @@
                 <el-col :span="8">
                   <el-form-item label="项目角色" prop="projectRole">
                     <el-select v-model="projectContactForm.projectRole" style="width: 100%" placeholder="请选择" filterable>
-                      <el-option v-for="item in projectRoleOptions" :key="item.dictValue" :label="item.dictLabel" :value="item.dictValue" />
+                      <el-option v-for="item in projectRoleOptions" :key="item.value" :label="item.label" :value="item.value" />
                     </el-select>
                   </el-form-item>
                 </el-col>
@@ -407,7 +407,7 @@
 </template>
 
 <script setup>
-import { ref, computed, reactive, watch, getCurrentInstance } from 'vue';
+import { ref, computed, reactive, watch, getCurrentInstance, toRefs } from 'vue';
 import { Plus, Search, Close, Upload, Edit, ArrowDown, CircleCheck } from '@element-plus/icons-vue';
 import { getOpportunity, updateOpportunity } from '@/api/saleManage/opportunity/index';
 import { listContact, addContact, delContact, updateContact } from "@/api/customer/crmContact";
@@ -415,13 +415,13 @@ import { getContactPerson } from "@/api/customer/contactPerson";
 import { getSalesResultAnalyzeByObjectNo, addSalesResultAnalyze, updateSalesResultAnalyze } from '@/api/saleManage/leads/salesResultAnalyze';
 import { listByIds } from "@/api/system/oss/index";
 import { listIndustryCategory } from "@/api/customer/industryCategory";
-import { listCommonDict } from "@/api/customer/customerDict";
 import { globalHeaders } from '@/utils/request';
 import { ElMessageBox, ElMessage } from 'element-plus';
 import BusinessActivity from '@/views/common/businessActivity.vue';
 
 const props = defineProps({
   modelValue: Boolean,
+  id: [String, Number],
   saleStatusOptions: { type: Array, default: () => [] },
   projectLevelOptions: { type: Array, default: () => [] },
   infoSourceOptions: { type: Array, default: () => [] },
@@ -441,7 +441,7 @@ const visible = ref(false);
 const detailData = ref({});
 const leftActiveTab = ref('info');
 const industryOptions = ref([]);
-const { proxy } = getCurrentInstance();
+const proxy = getCurrentInstance().proxy;
 
 // 状态同步
 watch(() => props.modelValue, (val) => { visible.value = val; });
@@ -500,7 +500,7 @@ const associateLoading = ref(false);
 const associateList = ref([]);
 const selectedContacts = ref([]);
 const associateQuery = reactive({ contactName: '', phone: '' });
-const projectRoleOptions = ref([]);
+const { LXRJE0001: projectRoleOptions } = toRefs(reactive(proxy.useDict("LXRJE0001")));
 
 const getFileType = (name) => {
   if (!name) return '未知';
@@ -640,11 +640,6 @@ const downloadFile = (file) => {
 };
 
 const loadDicts = () => {
-  if (projectRoleOptions.value.length === 0) {
-    listCommonDict("LXRJE0001").then(res => {
-      projectRoleOptions.value = res.data || [];
-    });
-  }
 };
 
 const getIndustryList = async () => {
@@ -831,19 +826,19 @@ const handleStepClick = async (index) => {
 const getSaleStatusLabel = (status) => {
   if (String(status) === '0') return '跟进中';
   if (String(status) === '1') return '结案';
-  return props.saleStatusOptions.find(i => String(i.dictValue) === String(status))?.dictLabel || status;
+  return props.saleStatusOptions.find(i => String(i.value) === String(status))?.label || status;
 };
 
 const findProjectLevelName = (level) => {
-  return props.projectLevelOptions.find(i => String(i.dictValue) === String(level))?.dictLabel || level;
+  return props.projectLevelOptions.find(i => String(i.value) === String(level))?.label || level;
 };
 
 const findInfoSourceName = (source) => {
-  return props.infoSourceOptions.find(i => String(i.dictValue) === String(source))?.dictLabel || source;
+  return props.infoSourceOptions.find(i => String(i.value) === String(source))?.label || source;
 };
 
 const findProcurementMethodName = (method) => {
-  return props.procurementMethodOptions.find(i => String(i.dictValue) === String(method))?.dictLabel || method;
+  return props.procurementMethodOptions.find(i => String(i.value) === String(method))?.label || method;
 };
 
 const findIndustryName = (val) => {

+ 36 - 10
src/views/saleManage/opportunity/edit.vue

@@ -24,7 +24,17 @@
               </el-col>
               <el-col :span="12">
                 <el-form-item label="客户名称" prop="customerNo">
-                  <el-select v-model="form.customerNo" placeholder="请选择" style="width: 100%" clearable filterable @change="handleCustomerChange">
+                  <el-select 
+                    v-model="form.customerNo" 
+                    placeholder="请输入关键字搜索客户" 
+                    style="width: 100%" 
+                    clearable 
+                    filterable 
+                    remote
+                    :remote-method="remoteLoadCustomers"
+                    :loading="customerLoading"
+                    @change="handleCustomerChange"
+                  >
                     <el-option v-for="item in computedCustomerOptions" :key="item.id || item.customerNo"
                       :label="item.customerName" :value="String(item.id || item.customerNo)" />
                   </el-select>
@@ -88,8 +98,8 @@
               <el-col :span="8">
                 <el-form-item label="项目级别" prop="projectLevel">
                   <el-select v-model="form.projectLevel" placeholder="请选择" style="width: 100%" clearable filterable>
-                    <el-option v-for="item in projectLevelOptions" :key="item.dictValue"
-                      :label="item.dictLabel" :value="String(item.dictValue)" />
+                    <el-option v-for="item in projectLevelOptions" :key="item.value"
+                      :label="item.label" :value="item.value" />
                   </el-select>
                 </el-form-item>
               </el-col>
@@ -101,8 +111,8 @@
               <el-col :span="8">
                 <el-form-item label="采购方式" prop="purchaseMethod">
                   <el-select v-model="form.purchaseMethod" placeholder="请选择" style="width: 100%" clearable filterable>
-                    <el-option v-for="item in procurementMethodOptions" :key="item.dictValue"
-                      :label="item.dictLabel" :value="String(item.dictValue)" />
+                    <el-option v-for="item in procurementMethodOptions" :key="item.value"
+                      :label="item.label" :value="item.value" />
                   </el-select>
                 </el-form-item>
               </el-col>
@@ -111,8 +121,8 @@
               <el-col :span="8">
                 <el-form-item label="商机来源" prop="source">
                   <el-select v-model="form.source" placeholder="请选择" style="width: 100%" clearable filterable>
-                    <el-option v-for="item in infoSourceOptions" :key="item.dictValue"
-                      :label="item.dictLabel" :value="String(item.dictValue)" />
+                    <el-option v-for="item in infoSourceOptions" :key="item.value"
+                      :label="item.label" :value="item.value" />
                   </el-select>
                 </el-form-item>
               </el-col>
@@ -164,6 +174,7 @@
 <script setup>
 import { ref, reactive, watch, computed, getCurrentInstance } from 'vue';
 import { getOpportunity, updateOpportunity } from '@/api/saleManage/opportunity/index';
+import { listCustomerOption } from "@/api/customer/customerInfo/index";
 import { listByIds } from '@/api/system/oss/index';
 import { globalHeaders } from '@/utils/request';
 import { Close, Upload } from '@element-plus/icons-vue';
@@ -181,7 +192,7 @@ const props = defineProps({
 });
 
 const emit = defineEmits(['update:modelValue', 'success']);
-const { proxy } = getCurrentInstance();
+const proxy = getCurrentInstance().proxy;
 
 const visible = ref(false);
 const loading = ref(false);
@@ -192,6 +203,18 @@ const uploadFileUrl = import.meta.env.VITE_APP_BASE_API + '/resource/oss/upload'
 const headers = globalHeaders();
 
 const form = reactive({});
+const customerLoading = ref(false);
+const localCustomerOptions = ref([]);
+
+const remoteLoadCustomers = (query) => {
+  customerLoading.value = true;
+  listCustomerOption({ customerName: query, isHighSeas: 'all' }).then(res => {
+    const list = res.data || res.rows || [];
+    localCustomerOptions.value = list.map(i => ({ ...i, id: String(i.id || i.customerNo) }));
+  }).finally(() => {
+    customerLoading.value = false;
+  });
+};
 
 const rules = reactive({
   companyId: [{ required: true, message: '归属公司不能为空', trigger: 'change' }],
@@ -205,7 +228,7 @@ const rules = reactive({
 
 // 【增强回显】通过计算属性确保当前项在选项列表中,防止分页或数据不全导致回显显示为 ID
 const computedCustomerOptions = computed(() => {
-  const options = [...(props.customerOptions || [])];
+  const options = [...localCustomerOptions.value];
   if (form.customerNo && form.customerName) {
     const exists = options.some(i => String(i.id || i.customerNo) === String(form.customerNo));
     if (!exists) options.unshift({ id: form.customerNo, customerNo: form.customerNo, customerName: form.customerName });
@@ -233,7 +256,10 @@ const computedCompanyOptions = computed(() => {
 
 watch(() => props.modelValue, (val) => {
   visible.value = val;
-  if (val && props.id) loadDetail(props.id);
+  if (val && props.id) {
+    loadDetail(props.id);
+    remoteLoadCustomers('');
+  }
 });
 watch(() => visible.value, (val) => { emit('update:modelValue', val); });
 

+ 22 - 33
src/views/saleManage/opportunity/index.vue

@@ -56,16 +56,16 @@
           <el-col :span="6">
             <el-form-item label="项目状态" prop="projectStatus">
               <el-select v-model="queryParams.projectStatus" placeholder="请选择" style="width: 100%" clearable>
-                <el-option v-for="item in saleStatusOptions" :key="item.dictValue"
-                  :label="item.dictLabel" :value="item.dictValue" />
+                <el-option v-for="item in saleStatusOptions" :key="item.value"
+                  :label="item.label" :value="item.value" />
               </el-select>
             </el-form-item>
           </el-col>
           <el-col :span="6">
             <el-form-item label="成交结果" prop="result">
               <el-select v-model="queryParams.result" placeholder="请选择" style="width: 100%" clearable>
-                <el-option v-for="item in dealResultOptions" :key="item.dictValue"
-                  :label="item.dictLabel" :value="item.dictValue" />
+                <el-option v-for="item in dealResultOptions" :key="item.value"
+                  :label="item.label" :value="item.value" />
               </el-select>
             </el-form-item>
           </el-col>
@@ -74,8 +74,8 @@
            <el-col :span="6">
             <el-form-item label="时间查询类型" prop="timeType">
               <el-select v-model="queryParams.timeType" placeholder="请选择" style="width: 100%" clearable>
-                <el-option v-for="item in timeQueryTypeOptions" :key="item.dictValue"
-                  :label="item.dictLabel" :value="item.dictValue" />
+                <el-option v-for="item in timeQueryTypeOptions" :key="item.value"
+                  :label="item.label" :value="item.value" />
               </el-select>
             </el-form-item>
           </el-col>
@@ -213,7 +213,6 @@
     <OpportunityAdd 
       v-model="addVisible" 
       :company-options="companyOptions" 
-      :customer-options="customerOptions" 
       :user-options="userOptions" 
       :project-level-options="projectLevelOptions" 
       :procurement-method-options="procurementMethodOptions" 
@@ -227,7 +226,6 @@
       v-model="editVisible" 
       :id="currentId"
       :company-options="companyOptions" 
-      :customer-options="customerOptions" 
       :user-options="userOptions" 
       :project-level-options="projectLevelOptions" 
       :procurement-method-options="procurementMethodOptions" 
@@ -295,11 +293,10 @@
 </template>
 
 <script setup name="ProjectOpportunity">
-import { ref, reactive, onMounted, getCurrentInstance } from 'vue';
+import { ref, reactive, onMounted, getCurrentInstance, toRefs } from 'vue';
 import { listOpportunity, delOpportunity, transferOpportunity } from '@/api/saleManage/opportunity/index';
 import { selectStaffOptionList } from "@/api/system/comStaff/index";
-import { listCompanyOption, listCustomerInfo } from "@/api/customer/customerInfo/index";
-import { listCommonDict } from "@/api/customer/customerDict";
+import { listCompanyOption, listCustomerOption } from "@/api/customer/customerInfo/index";
 import { listDept } from "@/api/system/dept/index";
 import { listIndustryCategory } from "@/api/customer/industryCategory";
 import { listRecord, addRecord } from "@/api/visit/record";
@@ -310,7 +307,7 @@ import OpportunityDetail from './detail.vue';
 
 const detailDrawerRef = ref(null);
 
-const { proxy } = getCurrentInstance();
+const proxy = getCurrentInstance().proxy;
 const { parseTime } = proxy.useDict ? { parseTime: proxy.parseTime } : proxy;
 
 /* ========== 状态 ========== */
@@ -324,16 +321,17 @@ const allCount = ref(0);
 
 /* ========== 下拉选项 ========== */
 const companyOptions = ref([]);
-const customerOptions = ref([]);
 const userOptions = ref([]);
 const deptOptions = ref([]);
-const saleStatusOptions = ref([]);
-const timeQueryTypeOptions = ref([]);
-const projectLevelOptions = ref([]);
-const procurementMethodOptions = ref([]);
-const infoSourceOptions = ref([]);
 const industryOptions = ref([]);
-const dealResultOptions = ref([]);
+const { 
+  J0001: saleStatusOptions, 
+  time_query_type: timeQueryTypeOptions, 
+  L0001: projectLevelOptions, 
+  X0001: procurementMethodOptions, 
+  X0002: infoSourceOptions, 
+  deal_result: dealResultOptions 
+} = toRefs(reactive(proxy.useDict('J0001', 'time_query_type', 'L0001', 'X0001', 'X0002', 'deal_result')));
 const marketingActivityOptions = ref([]);
 
 /* ========== 弹窗状态 ========== */
@@ -522,8 +520,8 @@ const getSaleStatusLabel = (status) => {
   if (String(status) === '1') return '结案';
 
   if (!saleStatusOptions.value || saleStatusOptions.value.length === 0) return status;
-  const item = saleStatusOptions.value.find(i => String(i.dictValue) === String(status));
-  return item ? item.dictLabel : status;
+  const item = saleStatusOptions.value.find(i => String(i.value) === String(status));
+  return item ? item.label : status;
 };
 
 const getStatusClass = (status) => {
@@ -535,27 +533,18 @@ const getStatusClass = (status) => {
 
 const findProjectLevelName = (id) => {
   if (!id) return '';
-  return projectLevelOptions.value.find(i => String(i.dictValue) === String(id))?.dictLabel || id;
+  return projectLevelOptions.value.find(i => String(i.value) === String(id))?.label || id;
 };
 
 /* ========== 加载选项列表 ========== */
 function getCompanyList() { listCompanyOption().then(r => companyOptions.value = r.data); }
-function getCustomerList() { listCustomerInfo({ pageSize: 9999 }).then(r => customerOptions.value = r.rows || []); }
 function getUserList() { selectStaffOptionList().then(r => userOptions.value = r.data); }
 function getDeptList() { listDept().then(r => deptOptions.value = proxy.handleTree(r.data, 'deptId')); }
-function getSaleStatusList() { listCommonDict('J0001').then(r => saleStatusOptions.value = r.data); }
-function getTimeQueryTypeList() { listCommonDict('time_query_type').then(r => timeQueryTypeOptions.value = r.data); }
-function getProjectLevelList() { listCommonDict('L0001').then(r => projectLevelOptions.value = r.data); }
-function getProcurementMethodList() { listCommonDict('X0001').then(r => procurementMethodOptions.value = r.data); }
-function getInfoSourceList() { listCommonDict('X0002').then(r => infoSourceOptions.value = r.data); }
 function getIndustryList() { listIndustryCategory().then(r => industryOptions.value = r.data); }
-function getDealResultList() { listCommonDict('deal_result').then(r => dealResultOptions.value = r.data); }
 
 onMounted(() => {
-  getList(); getCompanyList(); getCustomerList(); getUserList(); getDeptList();
-  getSaleStatusList(); getTimeQueryTypeList(); getProjectLevelList();
-  getProcurementMethodList(); getInfoSourceList(); getIndustryList();
-  getDealResultList();
+  getList(); getCompanyList(); getUserList(); getDeptList();
+  getIndustryList();
 });
 </script>
 

+ 7 - 7
src/views/saleManage/platformSelection/add.vue

@@ -42,7 +42,7 @@
             <el-col :span="8">
               <el-form-item label="项目级别" prop="projectLevel" label-for="projectLevelSelect">
                 <el-select id="projectLevelSelect" v-model="drawerForm.projectLevel" style="width:100%" placeholder="请选择">
-                  <el-option v-for="item in options.level" :key="item.dictValue" :label="item.dictLabel" :value="Number(item.dictValue)" />
+                  <el-option v-for="item in options.level" :key="item.value" :label="item.label" :value="item.value" />
                 </el-select>
               </el-form-item>
             </el-col>
@@ -51,7 +51,7 @@
             <el-col :span="8">
               <el-form-item label="项目类型" prop="businessType" label-for="businessTypeSelect">
                 <el-select id="businessTypeSelect" v-model="drawerForm.businessType" style="width:100%" placeholder="请选择">
-                  <el-option v-for="item in options.type" :key="item.dictValue" :label="item.dictLabel" :value="Number(item.dictValue)" />
+                  <el-option v-for="item in options.type" :key="item.value" :label="item.label" :value="item.value" />
                 </el-select>
               </el-form-item>
             </el-col>
@@ -138,7 +138,7 @@
             <el-col :span="8">
               <el-form-item label="入围类型" prop="shortlistedType">
                 <el-select v-model="drawerForm.shortlistedType" style="width:100%" placeholder="请选择">
-                  <el-option v-for="item in options.shortlisted" :key="item.dictValue" :label="item.dictLabel" :value="Number(item.dictValue)" />
+                  <el-option v-for="item in options.shortlisted" :key="item.value" :label="item.label" :value="item.value" />
                 </el-select>
               </el-form-item>
             </el-col>
@@ -147,7 +147,7 @@
             <el-col :span="8">
               <el-form-item label="物资类目" prop="profession">
                 <el-select v-model="drawerForm.profession" style="width:100%" placeholder="请选择">
-                  <el-option v-for="item in options.material" :key="item.dictValue" :label="item.dictLabel" :value="Number(item.dictValue)" />
+                  <el-option v-for="item in options.material" :key="item.value" :label="item.label" :value="item.value" />
                 </el-select>
               </el-form-item>
             </el-col>
@@ -166,8 +166,8 @@
             <el-col :span="24">
               <el-form-item label="标期类型" prop="bidPeriodType">
                 <el-radio-group v-model="drawerForm.bidPeriodType">
-                  <el-radio :label="1">单项目入围</el-radio>
-                  <el-radio :label="2">周期性框架</el-radio>
+                  <el-radio :value="1">单项目入围</el-radio>
+                  <el-radio :value="2">周期性框架</el-radio>
                 </el-radio-group>
               </el-form-item>
             </el-col>
@@ -248,7 +248,7 @@ import { listCustomerInfo, listCustomerListPage } from "@/api/customer/customerI
 import { getToken } from "@/utils/auth";
 import { Upload } from '@element-plus/icons-vue';
 
-const { proxy } = getCurrentInstance();
+const proxy = getCurrentInstance().proxy;
 
 const props = defineProps({
   modelValue: Boolean,

+ 15 - 19
src/views/saleManage/platformSelection/detail.vue

@@ -269,15 +269,15 @@
             <el-col :span="8">
               <el-form-item label="联系人类型" prop="contactType">
                 <el-radio-group v-model="projectContactForm.contactType">
-                  <el-radio label="1">公司职员</el-radio>
-                  <el-radio label="2">关系资源人</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="8">
               <el-form-item label="性别" prop="sex">
                 <el-radio-group v-model="projectContactForm.sex">
-                  <el-radio label="0">男</el-radio><el-radio label="1">女</el-radio>
+                  <el-radio value="0">男</el-radio><el-radio value="1">女</el-radio>
                 </el-radio-group>
               </el-form-item>
             </el-col>
@@ -309,8 +309,8 @@
             <el-col :span="8">
               <el-form-item label="在职状态" prop="status">
                 <el-radio-group v-model="projectContactForm.status">
-                  <el-radio label="0">在职</el-radio>
-                  <el-radio label="1">离职</el-radio>
+                  <el-radio value="0">在职</el-radio>
+                  <el-radio value="1">离职</el-radio>
                 </el-radio-group>
               </el-form-item>
             </el-col>
@@ -360,7 +360,7 @@
             <el-col :span="8">
               <el-form-item label="项目角色" prop="projectRole">
                 <el-select v-model="projectContactForm.projectRole" style="width: 100%" placeholder="请选择" filterable clearable>
-                  <el-option v-for="item in projectRoleOptions" :key="item.dictValue" :label="item.dictLabel" :value="item.dictValue" />
+                  <el-option v-for="item in projectRoleOptions" :key="item.value" :label="item.label" :value="item.value" />
                 </el-select>
               </el-form-item>
             </el-col>
@@ -405,11 +405,10 @@
 </template>
 
 <script setup>
-import { ref, reactive, computed, watch, getCurrentInstance } from 'vue';
+import { ref, reactive, computed, watch, getCurrentInstance, toRefs } from 'vue';
 import { getPlatformSelection, updatePlatformSelection } from '@/api/saleManage/platformSelection/index';
 import { listContact } from '@/api/customer/crmContact';
 import { Plus, Close, Edit, ArrowDown, Upload, CircleCheck } from '@element-plus/icons-vue';
-import { listCommonDict } from "@/api/customer/customerDict";
 import { parseTime } from "@/utils/ruoyi";
 import { addContact, delContact, updateContact } from "@/api/customer/crmContact";
 import { getSalesResultAnalyzeByObjectNo, addSalesResultAnalyze, updateSalesResultAnalyze } from '@/api/saleManage/leads/salesResultAnalyze';
@@ -419,7 +418,7 @@ import { listProvinceWithCities } from "@/api/customer/addressArea";
 import BusinessActivity from '@/views/common/businessActivity.vue';
 import { ElMessageBox, ElMessage } from 'element-plus';
 
-const { proxy } = getCurrentInstance();
+const proxy = getCurrentInstance().proxy;
 
 const props = defineProps({
   modelValue: Boolean,
@@ -455,7 +454,7 @@ const projectContactRules = {
   phonenumber: [{ required: true, message: '手机号码不能为空', trigger: 'blur' }],
   deptName: [{ required: true, message: '部门不能为空', trigger: 'blur' }],
 };
-const projectRoleOptions = ref([]);
+const { LXRJE0001: projectRoleOptions } = toRefs(reactive(proxy.useDict("LXRJE0001")));
 const areaOptions = ref([]);
 const associateVisible = ref(false);
 const associateLoading = ref(false);
@@ -533,9 +532,6 @@ const fetchContactList = async (id) => {
 };
 
 const loadDicts = () => {
-  if (projectRoleOptions.value.length === 0) {
-    listCommonDict("LXRJE0001").then(res => { projectRoleOptions.value = res.data || []; });
-  }
   if (areaOptions.value.length === 0) {
     listProvinceWithCities().then(res => { areaOptions.value = res.data || []; });
   }
@@ -748,25 +744,25 @@ const openLink = (link) => {
 };
 
 const formatDate = (date) => date ? parseTime(date, '{y}-{m}-{d}') : '';
-const getStatusLabel = (s) => props.options.status?.find(o => String(o.dictValue) === String(s))?.dictLabel || '';
+const getStatusLabel = (s) => props.options.status?.find(o => String(o.value) === String(s))?.label || '';
 const getProjectRoleLabel = (val) => {
-  return projectRoleOptions.value.find(o => String(o.dictValue) === String(val))?.dictLabel || val || '';
+  return projectRoleOptions.value.find(o => String(o.value) === String(val))?.label || val || '';
 };
 
 const displayProfessionName = computed(() => {
   const val = drawerForm.value.profession || drawerForm.value.materialCategory;
-  return props.options.material?.find(o => String(o.dictValue) === String(val))?.dictLabel || '';
+  return props.options.material?.find(o => String(o.value) === String(val))?.label || '';
 });
 const displayShortlistedName = computed(() => {
   const val = drawerForm.value.shortlistedType || drawerForm.value.finalizationType;
-  return props.options.shortlisted?.find(o => String(o.dictValue) === String(val))?.dictLabel || '';
+  return props.options.shortlisted?.find(o => String(o.value) === String(val))?.label || '';
 });
 const displayCompanyName = computed(() => {
   const val = drawerForm.value.companyNo;
   return props.options.company?.find(c => String(c.companyCode) === String(val) || String(c.id) === String(val))?.companyName || '';
 });
-const displayProjectLevelName = computed(() => props.options.level?.find(o => String(o.dictValue) === String(drawerForm.value.projectLevel))?.dictLabel || '');
-const displayProjectTypeName = computed(() => props.options.type?.find(o => String(o.dictValue) === String(drawerForm.value.businessType))?.dictLabel || '');
+const displayProjectLevelName = computed(() => props.options.level?.find(o => String(o.value) === String(drawerForm.value.projectLevel))?.label || '');
+const displayProjectTypeName = computed(() => props.options.type?.find(o => String(o.value) === String(drawerForm.value.businessType))?.label || '');
 
 </script>
 

+ 7 - 7
src/views/saleManage/platformSelection/edit.vue

@@ -42,7 +42,7 @@
             <el-col :span="8">
               <el-form-item label="项目级别" prop="projectLevel">
                 <el-select v-model="drawerForm.projectLevel" style="width:100%" placeholder="请选择">
-                  <el-option v-for="item in options.level" :key="item.dictValue" :label="item.dictLabel" :value="Number(item.dictValue)" />
+                  <el-option v-for="item in options.level" :key="item.value" :label="item.label" :value="item.value" />
                 </el-select>
               </el-form-item>
             </el-col>
@@ -51,7 +51,7 @@
             <el-col :span="8">
               <el-form-item label="项目类型" prop="businessType">
                 <el-select v-model="drawerForm.businessType" style="width:100%" placeholder="请选择">
-                  <el-option v-for="item in options.type" :key="item.dictValue" :label="item.dictLabel" :value="Number(item.dictValue)" />
+                  <el-option v-for="item in options.type" :key="item.value" :label="item.label" :value="item.value" />
                 </el-select>
               </el-form-item>
             </el-col>
@@ -138,7 +138,7 @@
             <el-col :span="8">
               <el-form-item label="入围类型" prop="shortlistedType">
                 <el-select v-model="drawerForm.shortlistedType" style="width:100%" placeholder="请选择">
-                  <el-option v-for="item in options.shortlisted" :key="item.dictValue" :label="item.dictLabel" :value="Number(item.dictValue)" />
+                  <el-option v-for="item in options.shortlisted" :key="item.value" :label="item.label" :value="item.value" />
                 </el-select>
               </el-form-item>
             </el-col>
@@ -147,7 +147,7 @@
             <el-col :span="8">
               <el-form-item label="物资类目" prop="profession">
                 <el-select v-model="drawerForm.profession" style="width:100%" placeholder="请选择">
-                  <el-option v-for="item in options.material" :key="item.dictValue" :label="item.dictLabel" :value="Number(item.dictValue)" />
+                  <el-option v-for="item in options.material" :key="item.value" :label="item.label" :value="item.value" />
                 </el-select>
               </el-form-item>
             </el-col>
@@ -166,8 +166,8 @@
             <el-col :span="24">
               <el-form-item label="标期类型" prop="bidPeriodType">
                 <el-radio-group v-model="drawerForm.bidPeriodType">
-                  <el-radio :label="1">单项目入围</el-radio>
-                  <el-radio :label="2">周期性框架</el-radio>
+                  <el-radio :value="1">单项目入围</el-radio>
+                  <el-radio :value="2">周期性框架</el-radio>
                 </el-radio-group>
               </el-form-item>
             </el-col>
@@ -249,7 +249,7 @@ import { listCustomerInfo, listCustomerListPage } from "@/api/customer/customerI
 import { getToken } from "@/utils/auth";
 import { Upload } from '@element-plus/icons-vue';
 
-const { proxy } = getCurrentInstance();
+const proxy = getCurrentInstance().proxy;
 
 const props = defineProps({
   modelValue: Boolean,

+ 40 - 36
src/views/saleManage/platformSelection/index.vue

@@ -55,14 +55,14 @@
           <el-col :span="6">
             <el-form-item label="项目级别" prop="projectLevel">
               <el-select v-model="queryParams.projectLevel" placeholder="请选择" style="width: 100%" clearable>
-                 <el-option v-for="item in projectLevelOptions" :key="item.dictValue" :label="item.dictLabel" :value="Number(item.dictValue)" />
+                 <el-option v-for="item in projectLevelOptions" :key="item.value" :label="item.label" :value="Number(item.value)" />
               </el-select>
             </el-form-item>
           </el-col>
           <el-col :span="6">
             <el-form-item label="项目类型" prop="businessType">
               <el-select v-model="queryParams.businessType" placeholder="请选择" style="width: 100%" clearable>
-                 <el-option v-for="item in projectTypeOptions" :key="item.dictValue" :label="item.dictLabel" :value="Number(item.dictValue)" />
+                 <el-option v-for="item in projectTypeOptions" :key="item.value" :label="item.label" :value="Number(item.value)" />
               </el-select>
             </el-form-item>
           </el-col>
@@ -71,28 +71,28 @@
           <el-col :span="6">
             <el-form-item label="入围类型" prop="finalizationType">
               <el-select v-model="queryParams.finalizationType" placeholder="请选择" style="width: 100%" clearable>
-                <el-option v-for="item in shortlistedTypeOptions" :key="item.dictValue" :label="item.dictLabel" :value="Number(item.dictValue)" />
+                <el-option v-for="item in shortlistedTypeOptions" :key="item.value" :label="item.label" :value="Number(item.value)" />
               </el-select>
             </el-form-item>
           </el-col>
           <el-col :span="6">
             <el-form-item label="项目状态" prop="projectStatus">
               <el-select v-model="queryParams.projectStatus" style="width: 100%" clearable>
-                <el-option v-for="item in statusOptions" :key="item.dictValue" :label="item.dictLabel" :value="Number(item.dictValue)" />
+                <el-option v-for="item in statusOptions" :key="item.value" :label="item.label" :value="Number(item.value)" />
               </el-select>
             </el-form-item>
           </el-col>
           <el-col :span="6">
             <el-form-item label="成交结果" prop="result">
               <el-select v-model="queryParams.result" placeholder="请选择" style="width: 100%" clearable>
-                <el-option v-for="item in resultOptions" :key="item.dictValue" :label="item.dictLabel" :value="Number(item.dictValue)" />
+                <el-option v-for="item in resultOptions" :key="item.value" :label="item.label" :value="Number(item.value)" />
               </el-select>
             </el-form-item>
           </el-col>
           <el-col :span="6">
             <el-form-item label="时间查询类型" prop="timeType">
               <el-select v-model="queryParams.timeType" style="width: 100%" clearable>
-                <el-option v-for="item in timeTypeOptions" :key="item.dictValue" :label="item.dictLabel" :value="Number(item.dictValue)" />
+                <el-option v-for="item in timeTypeOptions" :key="item.value" :label="item.label" :value="Number(item.value)" />
               </el-select>
             </el-form-item>
           </el-col>
@@ -157,12 +157,12 @@
         <el-table-column label="客户名称" align="center" prop="customName" min-width="200" show-overflow-tooltip />
         <el-table-column label="项目级别" align="center" prop="projectLevel" width="100">
           <template #default="scope">
-            {{ projectLevelOptions.find(o => String(o.dictValue) === String(scope.row.projectLevel))?.dictLabel || scope.row.projectLevel }}
+            {{ projectLevelOptions.find(o => String(o.value) === String(scope.row.projectLevel))?.label || scope.row.projectLevel }}
           </template>
         </el-table-column>
         <el-table-column label="项目类型" align="center" prop="businessType" width="100">
           <template #default="scope">
-            {{ projectTypeOptions.find(o => String(o.dictValue) === String(scope.row.businessType))?.dictLabel || scope.row.businessType }}
+            {{ projectTypeOptions.find(o => String(o.value) === String(scope.row.businessType))?.label || scope.row.businessType }}
           </template>
         </el-table-column>
         <el-table-column label="金额(万)" align="center" prop="amount" width="100" sortable />
@@ -211,17 +211,17 @@
         </el-table-column>
         <el-table-column label="入围类型" align="center" prop="finalizationType" width="100">
           <template #default="scope">
-            {{ shortlistedTypeOptions.find(o => String(o.dictValue) === String(scope.row.finalizationType || scope.row.shortlistedType || scope.row.selectionType))?.dictLabel || scope.row.finalizationType || scope.row.selectionType }}
+            {{ shortlistedTypeOptions.find(o => String(o.value) === String(scope.row.finalizationType || scope.row.shortlistedType || scope.row.selectionType))?.label || scope.row.finalizationType || scope.row.selectionType }}
           </template>
         </el-table-column>
         <el-table-column label="项目状态" align="center" prop="projectStatus" width="100">
            <template #default="scope">
-             <el-tag :type="scope.row.projectStatus === 5 ? 'info' : 'warning'" plain>{{ statusOptions.find(o => String(o.dictValue) === String(scope.row.projectStatus))?.dictLabel || '跟进中' }}</el-tag>
+             <el-tag :type="scope.row.projectStatus === 5 ? 'info' : 'warning'" plain>{{ statusOptions.find(o => String(o.value) === String(scope.row.projectStatus))?.label || '跟进中' }}</el-tag>
            </template>
         </el-table-column>
         <el-table-column label="成交结果" align="center" prop="result" width="100">
           <template #default="scope">
-            {{ resultOptions.find(o => String(o.dictValue) === String(scope.row.result))?.dictLabel || scope.row.result }}
+            {{ resultOptions.find(o => String(o.value) === String(scope.row.result))?.label || scope.row.result }}
           </template>
         </el-table-column>
         <el-table-column label="操作" align="center" width="180" fixed="right">
@@ -312,14 +312,13 @@
 </template>
 
 <script setup name="PlatformSelection">
-import { ref, reactive, onMounted, getCurrentInstance } from 'vue';
+import { ref, reactive, onMounted, getCurrentInstance, toRefs } from 'vue';
 import {
   listPlatformSelection,
   delPlatformSelection,
   transferPlatformSelection
 } from '@/api/saleManage/platformSelection/index';
 import { listRecord, addRecord } from "@/api/visit/record";
-import { listCommonDict } from "@/api/customer/customerDict";
 import { selectStaffOptionList } from "@/api/system/comStaff/index";
 import { listCompanyOption, listCustomerInfo } from "@/api/customer/customerInfo/index";
 import { listIndustryCategory } from "@/api/customer/industryCategory";
@@ -329,7 +328,7 @@ import AddDialog from './add.vue';
 import EditDialog from './edit.vue';
 import DetailDialog from './detail.vue';
 
-const { proxy } = getCurrentInstance();
+const proxy = getCurrentInstance().proxy;
 
 // 列表状态
 const loading = ref(false);
@@ -381,28 +380,40 @@ const queryParams = reactive({
 });
 
 // 下拉选项
-const projectLevelOptions = ref([]);
-const projectTypeOptions = ref([]);
-const shortlistedTypeOptions = ref([]);
-const statusOptions = ref([]);
+const {
+  XMJB0001, L0001, R0001, J0001, ZBPL0001, deal_result, time_query_type
+} = proxy.useDict('XMJB0001', 'L0001', 'R0001', 'J0001', 'ZBPL0001', 'deal_result', 'time_query_type');
+
+const projectLevelOptions = L0001;
+const projectTypeOptions = XMJB0001;
+const shortlistedTypeOptions = R0001;
+const statusOptions = J0001;
+const resultOptions = deal_result;
+const timeTypeOptions = time_query_type;
+const materialOptions = ZBPL0001;
 const userOptions = ref([]);
 const companyOptions = ref([]);
 const deptOptions = ref([]);
-const resultOptions = ref([]);
-const timeTypeOptions = ref([]);
 const industryOptions = ref([]);
 
-const drawerOptions = reactive({
+// 使用 computed 确保传给子组件的是展开后的数组(而非 ref 对象),保持响应式
+const drawerOptionsBase = reactive({
   company: [],
   user: [],
-  level: [],
-  type: [],
-  shortlisted: [],
-  material: [],
   industryList: [],
-  status: []
 });
 
+const drawerOptions = computed(() => ({
+  company: drawerOptionsBase.company,
+  user: drawerOptionsBase.user,
+  industryList: drawerOptionsBase.industryList,
+  level: L0001.value || [],
+  type: XMJB0001.value || [],
+  shortlisted: R0001.value || [],
+  material: ZBPL0001.value || [],
+  status: J0001.value || [],
+}));
+
 /** 查询列表 */
 const getList = async () => {
   loading.value = true;
@@ -544,11 +555,6 @@ const confirmTransfer = async () => {
 
 /** 初始化基础数据 */
 const initData = () => {
-  listCommonDict('XMJB0001').then(res => { projectLevelOptions.value = res.data; drawerOptions.level = res.data; });
-  listCommonDict('L0001').then(res => { projectTypeOptions.value = res.data; drawerOptions.type = res.data; });
-  listCommonDict('R0001').then(res => { shortlistedTypeOptions.value = res.data; drawerOptions.shortlisted = res.data; });
-  listCommonDict('J0001').then(res => { statusOptions.value = res.data; drawerOptions.status = res.data; });
-  listCommonDict('ZBPL0001').then(res => { drawerOptions.material = res.data; });
   listIndustryCategory().then(res => {
     const flatten = (list) => {
       let result = [];
@@ -560,13 +566,11 @@ const initData = () => {
     };
     const flatData = flatten(res.data || []);
     industryOptions.value = flatData;
-    drawerOptions.industryList = res.data; // 弹窗中通常需要树形结构或特定结构
+    drawerOptionsBase.industryList = res.data; 
   });
-  selectStaffOptionList().then(res => { userOptions.value = res.data; drawerOptions.user = res.data; });
-  listCompanyOption().then(res => { companyOptions.value = res.data; drawerOptions.company = res.data; });
-  listCommonDict('deal_result').then(res => resultOptions.value = res.data);
+  selectStaffOptionList().then(res => { userOptions.value = res.data; drawerOptionsBase.user = res.data; });
+  listCompanyOption().then(res => { companyOptions.value = res.data; drawerOptionsBase.company = res.data; });
   deptTreeSelect().then(res => deptOptions.value = res.data);
-  listCommonDict('time_query_type').then(res => timeTypeOptions.value = res.data);
 };
 
 onMounted(() => {

+ 7 - 7
src/views/saleManage/projectSelection/add.vue

@@ -47,7 +47,7 @@
               <el-col :span="8">
                 <el-form-item label="项目类型" prop="businessType">
                   <el-select v-model="form.businessType" placeholder="请选择" style="width: 100%" clearable>
-                    <el-option v-for="item in projectTypeOptions" :key="item.dictValue" :label="item.dictLabel" :value="String(item.dictValue)" />
+                    <el-option v-for="item in projectTypeOptions" :key="item.value" :label="item.label" :value="String(item.value)" />
                   </el-select>
                 </el-form-item>
               </el-col>
@@ -56,7 +56,7 @@
               <el-col :span="8">
                 <el-form-item label="项目类别" prop="projectLevel">
                   <el-select v-model="form.projectLevel" placeholder="请选择" style="width: 100%" clearable>
-                    <el-option v-for="item in projectLevelOptions" :key="item.dictValue" :label="item.dictLabel" :value="String(item.dictValue)" />
+                    <el-option v-for="item in projectLevelOptions" :key="item.value" :label="item.label" :value="String(item.value)" />
                   </el-select>
                 </el-form-item>
               </el-col>
@@ -128,7 +128,7 @@
               <el-col :span="8">
                 <el-form-item label="入围类型" prop="shortlistedType">
                   <el-select v-model="form.shortlistedType" placeholder="请选择" style="width: 100%" clearable>
-                    <el-option v-for="item in shortlistedTypeOptions" :key="item.dictValue" :label="item.dictLabel" :value="String(item.dictValue)" />
+                    <el-option v-for="item in shortlistedTypeOptions" :key="item.value" :label="item.label" :value="String(item.value)" />
                   </el-select>
                 </el-form-item>
               </el-col>
@@ -137,7 +137,7 @@
               <el-col :span="8">
                 <el-form-item label="物资类目" prop="profession">
                   <el-select v-model="form.profession" placeholder="请选择" style="width: 100%" clearable>
-                    <el-option v-for="item in professionOptions" :key="item.id || item.dictValue" :label="item.industryCategoryName || item.dictLabel" :value="String(item.id || item.dictValue)" />
+                    <el-option v-for="item in professionOptions" :key="item.id || item.value" :label="item.industryCategoryName || item.label" :value="String(item.id || item.value)" />
                   </el-select>
                 </el-form-item>
               </el-col>
@@ -154,8 +154,8 @@
             </el-row>
             <el-form-item label="标期类型" prop="bidPeriodType">
               <el-radio-group v-model="form.bidPeriodType">
-                <el-radio :label="1">单项目入围</el-radio>
-                <el-radio :label="2">周期性框架</el-radio>
+                <el-radio :value="1">单项目入围</el-radio>
+                <el-radio :value="2">周期性框架</el-radio>
               </el-radio-group>
             </el-form-item>
             <el-form-item label="招标链接" prop="biddingLink" v-if="form.bidPeriodType === 2">
@@ -223,7 +223,7 @@ const props = defineProps({
 });
 
 const emit = defineEmits(['update:modelValue', 'success']);
-const { proxy } = getCurrentInstance();
+const proxy = getCurrentInstance().proxy;
 
 const visible = ref(false);
 const submitting = ref(false);

+ 19 - 20
src/views/saleManage/projectSelection/detail.vue

@@ -258,15 +258,15 @@
                 <el-col :span="8">
                   <el-form-item label="联系人类型" prop="contactType">
                     <el-radio-group v-model="projectContactForm.contactType">
-                      <el-radio label="1">公司职员</el-radio>
-                      <el-radio label="2">关系资源人</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="8">
                   <el-form-item label="性别" prop="sex">
                     <el-radio-group v-model="projectContactForm.sex">
-                      <el-radio label="0">男</el-radio><el-radio label="1">女</el-radio>
+                      <el-radio value="0">男</el-radio><el-radio value="1">女</el-radio>
                     </el-radio-group>
                   </el-form-item>
                 </el-col>
@@ -300,8 +300,8 @@
                 <el-col :span="8">
                   <el-form-item label="在职状态" prop="status">
                     <el-radio-group v-model="projectContactForm.status">
-                      <el-radio label="0">在职</el-radio>
-                      <el-radio label="1">离职</el-radio>
+                      <el-radio value="0">在职</el-radio>
+                      <el-radio value="1">离职</el-radio>
                     </el-radio-group>
                   </el-form-item>
                 </el-col>
@@ -353,7 +353,7 @@
                 <el-col :span="8">
                   <el-form-item label="项目角色" prop="projectRole">
                     <el-select v-model="projectContactForm.projectRole" style="width: 100%" placeholder="请选择" filterable clearable>
-                      <el-option v-for="item in projectRoleOptions" :key="item.dictValue" :label="item.dictLabel" :value="item.dictValue" />
+                      <el-option v-for="item in projectRoleOptions" :key="item.value" :label="item.label" :value="item.value" />
                     </el-select>
                   </el-form-item>
                 </el-col>
@@ -401,12 +401,11 @@
 </template>
 
 <script setup>
-import { ref, computed, watch, reactive, getCurrentInstance } from 'vue';
+import { ref, computed, watch, reactive, getCurrentInstance, toRefs } from 'vue';
 import { Edit, Upload, Plus, Close, CircleCheck, ArrowDown } from '@element-plus/icons-vue';
 import { getProjectSelection, updateProjectSelection } from '@/api/saleManage/projectSelection/index';
 import { listContact, addContact, delContact, updateContact } from "@/api/customer/crmContact";
 import { getSalesResultAnalyzeByObjectNo, addSalesResultAnalyze, updateSalesResultAnalyze } from '@/api/saleManage/leads/salesResultAnalyze';
-import { listCommonDict } from "@/api/customer/customerDict";
 import { listProvinceWithCities } from "@/api/customer/addressArea";
 import { listByIds } from "@/api/system/oss/index";
 import { globalHeaders } from '@/utils/request';
@@ -436,7 +435,11 @@ const currentStepIndex = computed(() => {
 const visible = ref(false);
 const detailData = ref({});
 const leftActiveTab = ref('info');
-const { proxy } = getCurrentInstance();
+const proxy = getCurrentInstance().proxy;
+const { 
+  LXRJE0001: projectRoleOptions,
+  deal_result: resultOptions
+} = toRefs(reactive(proxy.useDict("LXRJE0001", "deal_result")));
 
 // 附件管理
 const detailFileList = ref([]);
@@ -502,7 +505,6 @@ const projectContactRules = {
   phonenumber: [{ required: true, message: '手机号码不能为空', trigger: 'blur' }],
   deptName: [{ required: true, message: '部门不能为空', trigger: 'blur' }],
 };
-const projectRoleOptions = ref([]);
 const areaOptions = ref([]);
 const associateVisible = ref(false);
 const associateLoading = ref(false);
@@ -510,9 +512,6 @@ const associateList = ref([]);
 const selectedContacts = ref([]);
 
 const loadDicts = () => {
-  if (projectRoleOptions.value.length === 0) {
-    listCommonDict("LXRJE0001").then(res => { projectRoleOptions.value = res.data || []; });
-  }
   if (areaOptions.value.length === 0) {
     listProvinceWithCities().then(res => { areaOptions.value = res.data || []; });
   }
@@ -606,7 +605,7 @@ const handleDeleteContact = (row) => {
 };
 
 // --- 结果分析逻辑 ---
-const analysisForm = reactive({ id: undefined, resultType: 'win', summary: '', loseReason: '', fileNo: '' });
+const analysisForm = reactive({ id: undefined, resultType: undefined, summary: '', loseReason: '', fileNo: '' });
 const analysisFileList = ref([]);
 
 const loadAnalysisData = async () => {
@@ -615,7 +614,7 @@ const loadAnalysisData = async () => {
     const res = await getSalesResultAnalyzeByObjectNo(detailData.value.projectNo);
     if (res.data) {
       Object.assign(analysisForm, {
-        id: res.data.id, resultType: res.data.dealResult === 1 ? 'win' : 'lose',
+        id: res.data.id, resultType: res.data.dealResult ? String(res.data.dealResult) : undefined,
         summary: res.data.winSumUp, loseReason: res.data.loseReason, fileNo: res.data.fileNo
       });
       if (analysisForm.fileNo) {
@@ -634,7 +633,7 @@ const handleSaveAnalysis = async () => {
   const ossIds = analysisFileList.value.map(f => f.ossId).join(',');
   const payload = {
     id: analysisForm.id, objectNo: detailData.value.projectNo,
-    dealResult: analysisForm.resultType === 'win' ? 1 : 2,
+    dealResult: analysisForm.resultType,
     winSumUp: analysisForm.summary, loseReason: analysisForm.loseReason, fileNo: ossIds
   };
   try {
@@ -712,10 +711,10 @@ const handleStepClick = async (index) => {
   }
 };
 
-const getStatusLabel = (val) => props.statusOptions?.find(o => String(o.dictValue) === String(val))?.dictLabel || val;
-const getLevelLabel = (val) => props.projectLevelOptions?.find(o => String(o.dictValue) === String(val))?.dictLabel || val;
-const getTypeLabel = (val) => props.projectTypeOptions?.find(o => String(o.dictValue) === String(val))?.dictLabel || val;
-const getShortlistedLabel = (val) => props.shortlistedTypeOptions?.find(o => String(o.dictValue) === String(val))?.dictLabel || val;
+const getStatusLabel = (val) => props.statusOptions?.find(o => String(o.value) === String(val))?.label || val;
+const getLevelLabel = (val) => props.projectLevelOptions?.find(o => String(o.value) === String(val))?.label || val;
+const getTypeLabel = (val) => props.projectTypeOptions?.find(o => String(o.value) === String(val))?.label || val;
+const getShortlistedLabel = (val) => props.shortlistedTypeOptions?.find(o => String(o.value) === String(val))?.label || val;
 const findIndustryName = (val) => props.professionOptions?.find(o => String(o.id || o.dictValue) === String(val))?.industryCategoryName || val;
 const findLeaderDeptName = (val) => {
   const leaderId = val || detailData.value.leaderId || detailData.value.leader;

+ 7 - 7
src/views/saleManage/projectSelection/edit.vue

@@ -47,7 +47,7 @@
               <el-col :span="8">
                 <el-form-item label="项目类型" prop="businessType">
                   <el-select v-model="form.businessType" placeholder="请选择" style="width: 100%" clearable>
-                    <el-option v-for="item in projectTypeOptions" :key="item.dictValue" :label="item.dictLabel" :value="String(item.dictValue)" />
+                    <el-option v-for="item in projectTypeOptions" :key="item.value" :label="item.label" :value="String(item.value)" />
                   </el-select>
                 </el-form-item>
               </el-col>
@@ -56,7 +56,7 @@
               <el-col :span="8">
                 <el-form-item label="项目类别" prop="projectLevel">
                   <el-select v-model="form.projectLevel" placeholder="请选择" style="width: 100%" clearable>
-                    <el-option v-for="item in projectLevelOptions" :key="item.dictValue" :label="item.dictLabel" :value="String(item.dictValue)" />
+                    <el-option v-for="item in projectLevelOptions" :key="item.value" :label="item.label" :value="String(item.value)" />
                   </el-select>
                 </el-form-item>
               </el-col>
@@ -128,7 +128,7 @@
               <el-col :span="8">
                 <el-form-item label="入围类型" prop="shortlistedType">
                   <el-select v-model="form.shortlistedType" placeholder="请选择" style="width: 100%" clearable>
-                    <el-option v-for="item in shortlistedTypeOptions" :key="item.dictValue" :label="item.dictLabel" :value="String(item.dictValue)" />
+                    <el-option v-for="item in shortlistedTypeOptions" :key="item.value" :label="item.label" :value="String(item.value)" />
                   </el-select>
                 </el-form-item>
               </el-col>
@@ -137,7 +137,7 @@
               <el-col :span="8">
                 <el-form-item label="物资类目" prop="profession">
                   <el-select v-model="form.profession" placeholder="请选择" style="width: 100%" clearable>
-                    <el-option v-for="item in professionOptions" :key="item.id || item.dictValue" :label="item.industryCategoryName || item.dictLabel" :value="String(item.id || item.dictValue)" />
+                    <el-option v-for="item in professionOptions" :key="item.id" :label="item.industryCategoryName" :value="String(item.id)" />
                   </el-select>
                 </el-form-item>
               </el-col>
@@ -154,8 +154,8 @@
             </el-row>
             <el-form-item label="标期类型" prop="bidPeriodType">
               <el-radio-group v-model="form.bidPeriodType">
-                <el-radio :label="1">单项目入围</el-radio>
-                <el-radio :label="2">周期性框架</el-radio>
+                <el-radio :value="1">单项目入围</el-radio>
+                <el-radio :value="2">周期性框架</el-radio>
               </el-radio-group>
             </el-form-item>
             <el-form-item label="招标链接" prop="biddingLink" v-if="form.bidPeriodType === 2">
@@ -225,7 +225,7 @@ const props = defineProps({
 });
 
 const emit = defineEmits(['update:modelValue', 'success']);
-const { proxy } = getCurrentInstance();
+const proxy = getCurrentInstance().proxy;
 
 const visible = ref(false);
 const loading = ref(false);

+ 28 - 35
src/views/saleManage/projectSelection/index.vue

@@ -54,14 +54,14 @@
           <el-col :span="6">
             <el-form-item label="项目级别" prop="projectLevel">
               <el-select v-model="queryParams.projectLevel" placeholder="请选择" style="width: 100%" clearable>
-                <el-option v-for="item in projectLevelOptions" :key="item.dictValue" :label="item.dictLabel" :value="item.dictValue" />
+                <el-option v-for="item in projectLevelOptions" :key="item.value" :label="item.label" :value="item.value" />
               </el-select>
             </el-form-item>
           </el-col>
           <el-col :span="6">
             <el-form-item label="项目类型" prop="businessType">
               <el-select v-model="queryParams.businessType" placeholder="请选择" style="width: 100%" clearable>
-                <el-option v-for="item in projectTypeOptions" :key="item.dictValue" :label="item.dictLabel" :value="item.dictValue" />
+                <el-option v-for="item in projectTypeOptions" :key="item.value" :label="item.label" :value="item.value" />
               </el-select>
             </el-form-item>
           </el-col>
@@ -70,28 +70,28 @@
           <el-col :span="6">
             <el-form-item label="入围类型" prop="selectionType">
               <el-select v-model="queryParams.selectionType" placeholder="请选择" style="width: 100%" clearable>
-                <el-option v-for="item in shortlistedTypeOptions" :key="item.dictValue" :label="item.dictLabel" :value="item.dictValue" />
+                <el-option v-for="item in shortlistedTypeOptions" :key="item.value" :label="item.label" :value="item.value" />
               </el-select>
             </el-form-item>
           </el-col>
           <el-col :span="6">
             <el-form-item label="项目状态" prop="projectStatus">
               <el-select v-model="queryParams.projectStatus" placeholder="请选择" style="width: 100%" clearable>
-                <el-option v-for="item in statusOptions" :key="item.dictValue" :label="item.dictLabel" :value="Number(item.dictValue)" />
+                <el-option v-for="item in statusOptions" :key="item.value" :label="item.label" :value="item.value" />
               </el-select>
             </el-form-item>
           </el-col>
           <el-col :span="6">
             <el-form-item label="成交结果" prop="result">
               <el-select v-model="queryParams.result" placeholder="请选择" style="width: 100%" clearable>
-                <el-option v-for="item in resultOptions" :key="item.dictValue" :label="item.dictLabel" :value="Number(item.dictValue)" />
+                <el-option v-for="item in resultOptions" :key="item.value" :label="item.label" :value="item.value" />
               </el-select>
             </el-form-item>
           </el-col>
           <el-col :span="6">
             <el-form-item label="查询类型" prop="timeType">
               <el-select v-model="queryParams.timeType" placeholder="请选择" style="width: 100%" clearable>
-                <el-option v-for="item in timeTypeOptions" :key="item.dictValue" :label="item.dictLabel" :value="Number(item.dictValue)" />
+                <el-option v-for="item in timeTypeOptions" :key="item.value" :label="item.label" :value="item.value" />
               </el-select>
             </el-form-item>
           </el-col>
@@ -159,12 +159,12 @@
         </el-table-column>
         <el-table-column label="项目级别" align="center" prop="projectLevel" width="100">
           <template #default="{ row }">
-            {{ projectLevelOptions.find(o => String(o.dictValue) === String(row.projectLevel))?.dictLabel || row.projectLevel }}
+            {{ projectLevelOptions.find(o => String(o.value) === String(row.projectLevel))?.label || row.projectLevel }}
           </template>
         </el-table-column>
         <el-table-column label="项目类型" align="center" prop="businessType" width="100">
           <template #default="{ row }">
-            {{ projectTypeOptions.find(o => String(o.dictValue) === String(row.businessType))?.dictLabel || row.businessType }}
+            {{ projectTypeOptions.find(o => String(o.value) === String(row.businessType))?.label || row.businessType }}
           </template>
         </el-table-column>
         <el-table-column label="金额(万)" align="center" prop="amount" width="100">
@@ -209,13 +209,13 @@
         </el-table-column>
         <el-table-column label="入围类型" align="center" prop="finalizationType" width="100">
           <template #default="{ row }">
-            {{ shortlistedTypeOptions.find(o => String(o.dictValue) === String(row.finalizationType))?.dictLabel || row.finalizationType }}
+            {{ shortlistedTypeOptions.find(o => String(o.value) === String(row.finalizationType))?.label || row.finalizationType }}
           </template>
         </el-table-column>
         <el-table-column label="项目状态" align="center" prop="projectStatus" width="100">
           <template #default="{ row }">
             <span class="status-tag" :class="getStatusClass(row.projectStatus)">
-              {{ statusOptions.find(o => String(o.dictValue) === String(row.projectStatus))?.dictLabel || (String(row.projectStatus) === '2' ? '进行中' : row.projectStatus) }}
+              {{ statusOptions.find(o => String(o.value) === String(row.projectStatus))?.label || (String(row.projectStatus) === '2' ? '进行中' : row.projectStatus) }}
             </span>
           </template>
         </el-table-column>
@@ -229,7 +229,7 @@
             </template>
             <template v-else>
               <span :style="{ color: (row.result === '赢单' || row.dealResult === '赢单') ? '#67c23a' : (row.result === '丢单' || row.dealResult === '丢单') ? '#f56c6c' : '' }">
-                {{ row.result || row.dealResult || resultOptions.find(o => String(o.dictValue) === String(row.result || row.dealResult))?.dictLabel || '' }}
+                {{ row.result || row.dealResult || resultOptions.find(o => String(o.value) === String(row.result || row.dealResult))?.label || '' }}
               </span>
             </template>
           </template>
@@ -350,21 +350,28 @@
 </template>
 
 <script setup name="ProjectSelection">
-import { ref, reactive, onMounted, getCurrentInstance } from 'vue';
+import { ref, reactive, onMounted, getCurrentInstance, toRefs } from 'vue';
 import { listProjectSelection, delProjectSelection, transferProjectSelection, publishProjectProgress } from '@/api/saleManage/projectSelection/index';
 import { listSalesResultAnalyze } from '@/api/saleManage/leads/salesResultAnalyze';
 import { listRecord, addRecord } from "@/api/visit/record";
-import { listCommonDict } from "@/api/customer/customerDict";
-import { selectStaffOptionList } from "@/api/system/comStaff/index";
-import { listCompanyOption } from "@/api/customer/customerInfo/index";
 import { listIndustryCategory } from "@/api/customer/industryCategory";
+import { selectStaffOptionList } from "@/api/customer/crmStaff";
+import { listCompanyOption } from "@/api/customer/customerInfo/index";
 import { deptTreeSelect } from "@/api/system/user";
 
 import SelectionAdd from './add.vue';
 import SelectionEdit from './edit.vue';
 import SelectionDetail from './detail.vue';
 
-const { proxy } = getCurrentInstance();
+const proxy = getCurrentInstance().proxy;
+const {
+  L0001: projectLevelOptions,
+  XMJB0001: projectTypeOptions,
+  R0001: shortlistedTypeOptions,
+  J0001: statusOptions,
+  deal_result: resultOptions,
+  time_query_type: timeTypeOptions
+} = toRefs(reactive(proxy.useDict('XMJB0001', 'L0001', 'R0001', 'J0001', 'deal_result', 'time_query_type')));
 
 const loading = ref(false);
 const progressVisible = ref(false);
@@ -394,6 +401,11 @@ const progressTotal = ref(0);
 const progressPage = ref(1);
 const progressPageSize = ref(5);
 
+const userOptions = ref([]);
+const companyOptions = ref([]);
+const deptOptions = ref([]);
+const professionOptions = ref([]);
+
 const queryParams = reactive({
   pageNum: 1, pageSize: 10,
   companyNo: undefined, projectName: undefined, customerName: undefined, managerId: undefined,
@@ -546,21 +558,7 @@ const handleBatchDelete = () => {
   }).catch(() => {});
 };
 
-const projectLevelOptions = ref([]);
-const projectTypeOptions = ref([]);
-const shortlistedTypeOptions = ref([]);
-const professionOptions = ref([]);
-const userOptions = ref([]);
-const companyOptions = ref([]);
-const statusOptions = ref([]);
-const resultOptions = ref([]);
-const timeTypeOptions = ref([]);
-const deptOptions = ref([]);
-
 const initOptions = () => {
-  listCommonDict('XMJB0001').then(r => projectLevelOptions.value = r.data);
-  listCommonDict('L0001').then(r => projectTypeOptions.value = r.data);
-  listCommonDict('R0001').then(r => shortlistedTypeOptions.value = r.data);
   listIndustryCategory().then(r => {
     // 行业数据通常是树形结构,扁平化处理以便列表查找
     const flatten = (list) => {
@@ -575,11 +573,6 @@ const initOptions = () => {
   });
   selectStaffOptionList().then(r => userOptions.value = r.data);
   listCompanyOption().then(r => companyOptions.value = r.data);
-  listCommonDict('J0001').then(r => statusOptions.value = r.data);
-  listCommonDict('deal_result').then(r => resultOptions.value = r.data);
-  listCommonDict('time_query_type').then(res => {
-    timeTypeOptions.value = res.data;
-  });
   deptTreeSelect().then(res => {
     deptOptions.value = res.data;
   });

+ 7 - 10
src/views/visit/plan/add.vue

@@ -100,7 +100,7 @@
           <el-col :span="12">
             <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.dictValue" :label="dict.dictLabel" :value="dict.dictValue" />
+                <el-option v-for="dict in urgencyOptions" :key="dict.value" :label="dict.label" :value="dict.value" />
               </el-select>
             </el-form-item>
           </el-col>
@@ -127,9 +127,8 @@
 </template>
 
 <script setup>
-import { ref, reactive, computed, watch, getCurrentInstance, onMounted } from 'vue';
+import { ref, reactive, computed, watch, getCurrentInstance, onMounted, toRefs } from 'vue';
 import { addPlan } from "@/api/visit/plan";
-import { listCommonDict } from "@/api/customer/customerDict";
 import { selectStaffOptionList } from "@/api/customer/crmStaff";
 import { listCustomerInfo } from "@/api/customer/customerInfo/index";
 import { listOpportunity } from "@/api/saleManage/opportunity";
@@ -141,7 +140,8 @@ const props = defineProps({
 
 const emit = defineEmits(['update:modelValue', 'success']);
 
-const { proxy } = getCurrentInstance();
+const proxy = getCurrentInstance().proxy;
+const { importance_level: urgencyOptions } = toRefs(reactive(proxy.useDict("importance_level")));
 
 const formRef = ref();
 const scheduleFormRef = ref();
@@ -185,7 +185,7 @@ watch(() => scheduleForm.value.customerName, (val) => {
   }
 });
 
-const urgencyOptions = ref([]);
+
 
 const form = ref({
   visitorId: undefined,
@@ -202,8 +202,8 @@ const rules = {
 };
 
 const getUrgencyLabel = (val) => {
-  const found = urgencyOptions.value.find(item => String(item.dictValue) === String(val));
-  return found ? found.dictLabel : (val || '--');
+  const found = urgencyOptions.value.find(item => String(item.value) === String(val));
+  return found ? found.label : (val || '--');
 };
 
 const scheduleRules = {
@@ -315,9 +315,6 @@ const resetForm = () => {
 };
 
 onMounted(() => {
-  listCommonDict("importance_level").then(response => {
-    urgencyOptions.value = response.data || [];
-  });
   selectStaffOptionList().then(response => {
     staffOptions.value = response.data || [];
   });

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

@@ -137,7 +137,7 @@
           <el-col :span="12">
             <el-form-item label="紧要程度:">
               <el-select v-model="currentSchedule.importantLevel" placeholder="请选择" disabled style="width: 100%">
-                <el-option v-for="dict in urgencyOptions" :key="dict.dictValue" :label="dict.dictLabel" :value="dict.dictValue" />
+                <el-option v-for="dict in urgencyOptions" :key="dict.value" :label="dict.label" :value="dict.value" />
               </el-select>
             </el-form-item>
           </el-col>
@@ -159,14 +159,10 @@
 </template>
 
 <script setup>
-import { ref, reactive, computed, watch, getCurrentInstance, onMounted } from 'vue';
+import { ref, reactive, computed, watch, getCurrentInstance, onMounted, toRefs } from 'vue';
 import { Close, Search, Plus, UserFilled } from '@element-plus/icons-vue';
 import { getPlan } from "@/api/visit/plan";
 import { listOperateLog } from "@/api/visit/operateLog";
-import { listTeamMember, addTeamMember, delTeamMember } from "@/api/customer/teamMember";
-import { selectStaffOptionList } from "@/api/customer/crmStaff";
-import { listCommonDict } from "@/api/customer/customerDict";
-import { getDicts } from "@/api/system/dict/data";
 import BusinessActivity from '../../common/businessActivity.vue';
 
 const props = defineProps({
@@ -176,7 +172,8 @@ const props = defineProps({
 
 const emit = defineEmits(['update:modelValue']);
 
-const { proxy } = getCurrentInstance();
+const proxy = getCurrentInstance().proxy;
+const { importance_level: urgencyOptions } = toRefs(reactive(proxy.useDict("importance_level")));
 
 const loading = ref(false);
 const detailData = ref({});
@@ -193,7 +190,6 @@ const currentSchedule = ref({
   accompanyPersons: '',
   purpose: ''
 });
-const urgencyOptions = ref([]);
 
 watch(() => props.modelValue, (val) => {
   if (val && props.id) {
@@ -222,13 +218,8 @@ const handleViewSchedule = (row) => {
 };
 
 const getUrgencyLabel = (val) => {
-  const found = urgencyOptions.value.find(item => String(item.dictValue) === String(val));
-  return found ? found.dictLabel : (val || '--');
-};
-
-const getRoleLabel = (code) => {
-  const found = memberRoleOptions.value.find(r => String(r.dictValue) === String(code));
-  return found ? found.dictLabel : (code || '普通成员');
+  const found = urgencyOptions.value.find(item => String(item.value) === String(val));
+  return found ? found.label : (val || '--');
 };
 
 const getOperateTypeText = (type) => {
@@ -243,9 +234,6 @@ const translateLogTarget = (details) => {
 };
 
 onMounted(() => {
-  listCommonDict('T0001').then(res => memberRoleOptions.value = res.data || []);
-  selectStaffOptionList().then(res => staffOptions.value = res.data || []);
-  listCommonDict("importance_level").then(res => urgencyOptions.value = res.data || []);
 });
 </script>
 

+ 7 - 10
src/views/visit/plan/edit.vue

@@ -100,7 +100,7 @@
           <el-col :span="12">
             <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.dictValue" :label="dict.dictLabel" :value="dict.dictValue" />
+                <el-option v-for="dict in urgencyOptions" :key="dict.value" :label="dict.label" :value="dict.value" />
               </el-select>
             </el-form-item>
           </el-col>
@@ -127,9 +127,8 @@
 </template>
 
 <script setup>
-import { ref, reactive, computed, watch, getCurrentInstance, onMounted } from 'vue';
+import { ref, reactive, computed, watch, getCurrentInstance, onMounted, toRefs } from 'vue';
 import { getPlan, updatePlan } from "@/api/visit/plan";
-import { listCommonDict } from "@/api/customer/customerDict";
 import { selectStaffOptionList } from "@/api/customer/crmStaff";
 import { listCustomerInfo } from "@/api/customer/customerInfo/index";
 import { listOpportunity } from "@/api/saleManage/opportunity";
@@ -142,7 +141,8 @@ const props = defineProps({
 
 const emit = defineEmits(['update:modelValue', 'success']);
 
-const { proxy } = getCurrentInstance();
+const proxy = getCurrentInstance().proxy;
+const { importance_level: urgencyOptions } = toRefs(reactive(proxy.useDict("importance_level")));
 
 const loading = ref(false);
 const formRef = ref();
@@ -183,7 +183,7 @@ watch(() => scheduleForm.value.customerName, (val) => {
     scheduleForm.value.objectName = val;
   }
 });
-const urgencyOptions = ref([]);
+
 
 const form = ref({
   id: undefined,
@@ -200,8 +200,8 @@ const rules = {
   endTime: [{ required: true, message: "请选择结束时间", trigger: "change" }]
 };
 const getUrgencyLabel = (val) => {
-  const found = urgencyOptions.value.find(item => String(item.dictValue) === String(val));
-  return found ? found.dictLabel : (val || '--');
+  const found = urgencyOptions.value.find(item => String(item.value) === String(val));
+  return found ? found.label : (val || '--');
 };
 
 const scheduleRules = {
@@ -308,9 +308,6 @@ const cancel = () => {
 };
 
 onMounted(() => {
-  listCommonDict("importance_level").then(response => {
-    urgencyOptions.value = response.data || [];
-  });
   selectStaffOptionList().then(response => {
     staffOptions.value = response.data || [];
   });

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

@@ -105,7 +105,7 @@ import { selectStaffOptionList } from "@/api/customer/crmStaff";
 import AddPlan from './add.vue';
 import DetailPlan from './detail.vue';
 
-const { proxy } = getCurrentInstance();
+const proxy = getCurrentInstance().proxy;
 
 const loading = ref(false);
 const dataList = ref([]);

+ 22 - 17
src/views/visit/record/detail.vue

@@ -271,15 +271,15 @@
 </template>
 
 <script setup>
-import { ref, watch, getCurrentInstance } from 'vue';
+import { ref, watch, getCurrentInstance, toRefs } from 'vue';
 import { Close, ChatLineRound, Upload } from '@element-plus/icons-vue';
 import { getRecord, listRecord } from "@/api/visit/record";
-import { listCommonDict } from "@/api/customer/customerDict";
 import { selectStaffOptionList } from "@/api/customer/crmStaff";
 import { globalHeaders } from "@/utils/request";
 import BusinessActivity from '../../common/businessActivity.vue';
 
-const { proxy } = getCurrentInstance();
+const proxy = getCurrentInstance().proxy;
+const { visit_type: callTypeOptions } = toRefs(reactive(proxy.useDict("visit_type")));
 
 const props = defineProps({
   modelValue: Boolean,
@@ -291,7 +291,7 @@ const emit = defineEmits(['update:modelValue']);
 const detailData = ref({});
 const leftTab = ref('followup');
 const fileList = ref([]);
-const callTypeOptions = ref([]);
+
 const staffOptions = ref([]);
 const uploadFileUrl = ref(import.meta.env.VITE_APP_BASE_API + '/resource/oss/upload');
 const headers = ref(globalHeaders());
@@ -317,10 +317,7 @@ function getData(id) {
   });
 }
 
-// 获取字典
-listCommonDict("visit_type").then(res => {
-  callTypeOptions.value = res.data || [];
-});
+
 
 selectStaffOptionList().then(res => {
   staffOptions.value = res.data || [];
@@ -328,8 +325,8 @@ selectStaffOptionList().then(res => {
 
 const getVisitTypeName = (code) => {
   if (!code && code !== 0) return '上门拜访';
-  const dict = callTypeOptions.value.find(d => String(d.dictValue) === String(code));
-  return dict ? dict.dictLabel : '上门拜访';
+  const dict = callTypeOptions.value.find(d => String(d.value) === String(code));
+  return dict ? dict.label : '上门拜访';
 };
 
 const handleUploadSuccess = (res, file) => {
@@ -373,21 +370,21 @@ const handleDownloadFile = (row) => {
 }
 
 .drawer-header {
-  height: 32px;
+  height: 56px;
   display: flex;
   align-items: center;
   justify-content: space-between;
-  padding: 0 15px;
-  background-color: #f0f7ff;
-  border-bottom: 1px solid #e1f0ff;
+  padding: 0 24px;
+  background-color: #fff;
+  border-bottom: 1px solid #f0f0f0;
   z-index: 10;
-  .header-title { font-size: 13px; color: #409eff; font-weight: normal; line-height: 32px; }
-  .close-icon { font-size: 16px; cursor: pointer; color: #409eff; &:hover { color: #1890ff; } }
+  .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; } }
 }
 
 .detail-wrap {
   display: flex;
-  height: calc(100vh - 32px);
+  height: calc(100vh - 56px);
   overflow: hidden;
   background: #fff;
   margin: 0;
@@ -400,6 +397,10 @@ const handleDownloadFile = (row) => {
   display: flex;
   flex-direction: column;
   border-right: 1px solid #f0f0f0;
+  overflow-y: auto;
+  &::-webkit-scrollbar { display: none; } /* 隐藏滚动条 */
+  -ms-overflow-style: none; /* IE/Edge */
+  scrollbar-width: none; /* Firefox */
 }
 
 .right-panel {
@@ -407,6 +408,10 @@ const handleDownloadFile = (row) => {
   background: #fff;
   display: flex;
   flex-direction: column;
+  overflow-y: auto;
+  &::-webkit-scrollbar { display: none; } /* 隐藏滚动条 */
+  -ms-overflow-style: none; /* IE/Edge */
+  scrollbar-width: none; /* Firefox */
 }
 
 /* 蓝色 Tab 覆盖样式 */

+ 1 - 1
src/views/visit/record/index.vue

@@ -91,7 +91,7 @@ import { listRecord, delRecord } from "@/api/visit/record";
 import { selectStaffOptionList } from "@/api/customer/crmStaff";
 import Detail from './detail.vue';
 
-const { proxy } = getCurrentInstance();
+const proxy = getCurrentInstance().proxy;
 
 const loading = ref(false);
 const dataList = ref([]);

+ 6 - 8
src/views/visit/routine/add.vue

@@ -38,9 +38,9 @@
               <el-select v-model="form.importantLevel" placeholder="请选择" style="width: 100%">
                 <el-option
                   v-for="dict in importanceOptions"
-                  :key="dict.dictValue"
-                  :label="dict.dictLabel"
-                  :value="dict.dictValue"
+                  :key="dict.value"
+                  :label="dict.label"
+                  :value="dict.value"
                 />
               </el-select>
             </el-form-item>
@@ -68,12 +68,11 @@
 </template>
 
 <script setup>
-import { ref, reactive, onMounted, getCurrentInstance, computed } from 'vue';
+import { ref, reactive, onMounted, getCurrentInstance, computed, toRefs } from 'vue';
 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 { listCommonDict } from "@/api/customer/customerDict";
 import { listOpportunity } from "@/api/saleManage/opportunity";
 import { listProjectSelection } from "@/api/saleManage/projectSelection";
 import { useUserStore } from "@/store/modules/user";
@@ -83,8 +82,9 @@ const props = defineProps({
 });
 
 const emit = defineEmits(['update:modelValue', 'success']);
-const { proxy } = getCurrentInstance();
+const proxy = getCurrentInstance().proxy;
 const userStore = useUserStore();
+const { importance_level: importanceOptions } = toRefs(reactive(proxy.useDict("importance_level")));
 
 const formRef = ref(null);
 const planOptions = ref([]);
@@ -92,7 +92,6 @@ const customerOptions = ref([]);
 const opportunityOptions = ref([]);
 const annualOptions = ref([]);
 const staffOptions = ref([]);
-const importanceOptions = ref([]);
 
 const form = ref({
   planNo: undefined,
@@ -210,7 +209,6 @@ onMounted(() => {
   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 || []; });
-  listCommonDict("importance_level").then(res => { importanceOptions.value = res.data || []; });
 });
 </script>
 

+ 28 - 18
src/views/visit/routine/detail.vue

@@ -36,7 +36,7 @@
               <el-row class="info-row">
                 <el-col :span="12" class="info-col">
                   <span class="info-label">状态</span>
-                  <span class="info-value">{{ scheduleStatusOptions.find(d => String(d.dictValue) === String(detailData.scheduleStatus))?.dictLabel || (String(detailData.scheduleStatus) === '0' ? '未执行' : (String(detailData.scheduleStatus) === '1' ? '已执行' : '放弃执行')) }}</span>
+                  <span class="info-value">{{ scheduleStatusOptions.find(d => String(d.value) === String(detailData.scheduleStatus))?.label || (String(detailData.scheduleStatus) === '0' ? '未执行' : (String(detailData.scheduleStatus) === '1' ? '已执行' : '放弃执行')) }}</span>
                 </el-col>
                 <el-col :span="12" class="info-col">
                   <span class="info-label">拜访目的</span>
@@ -46,7 +46,7 @@
               <el-row class="info-row">
                 <el-col :span="12" class="info-col">
                   <span class="info-label">关联类型</span>
-                  <span class="info-value">{{ relevanceOptions.find(d => String(d.dictValue) === String(detailData.relevanceType))?.dictLabel || (String(detailData.relevanceType) === '0' ? '客户' : (String(detailData.relevanceType) === '1' ? '项目' : '供应商')) }}</span>
+                  <span class="info-value">{{ relevanceOptions.find(d => String(d.value) === String(detailData.relevanceType))?.label || (String(detailData.relevanceType) === '0' ? '客户' : (String(detailData.relevanceType) === '1' ? '项目' : '供应商')) }}</span>
                 </el-col>
                 <el-col :span="12" class="info-col">
                   <span class="info-label">关联对象</span>
@@ -110,7 +110,7 @@
           <el-col :span="12">
             <el-form-item label="拜访方式:" prop="visitType">
               <el-select v-model="recordForm.visitType" placeholder="请选择" style="width: 100%">
-                <el-option v-for="dict in visitTypeOptions" :key="dict.dictValue" :label="dict.dictLabel" :value="dict.dictValue" />
+                <el-option v-for="dict in visitTypeOptions" :key="dict.value" :label="dict.label" :value="dict.value" />
               </el-select>
             </el-form-item>
           </el-col>
@@ -154,12 +154,12 @@
 </template>
 
 <script setup>
-import { ref, reactive, watch, getCurrentInstance } from 'vue';
+import { ref, reactive, watch, getCurrentInstance, toRefs } from 'vue';
 import { Plus } from '@element-plus/icons-vue';
 import { getRoutine } from "@/api/visit/routine";
-import { addRecord, listRecord } from "@/api/visit/record";
-import { listCommonDict } from "@/api/customer/customerDict";
 import { selectStaffOptionList } from "@/api/customer/crmStaff";
+import { addRecord, listRecord } from "@/api/visit/record";
+import { listOperateLog } from "@/api/visit/operateLog";
 import BusinessActivity from '../../common/businessActivity.vue';
 
 const props = defineProps({
@@ -168,7 +168,12 @@ const props = defineProps({
 });
 
 const emit = defineEmits(['update:modelValue']);
-const { proxy } = getCurrentInstance();
+const proxy = getCurrentInstance().proxy;
+const { 
+  visit_type: visitTypeOptions, 
+  schedule_status: scheduleStatusOptions, 
+  relevance_type: relevanceOptions 
+} = toRefs(reactive(proxy.useDict("visit_type", "schedule_status", "relevance_type")));
 
 const visible = ref(false);
 const detailData = ref({});
@@ -178,9 +183,6 @@ const operateLogs = ref([]);
 const recordList = ref([]);
 const recordLoading = ref(false);
 
-const visitTypeOptions = ref([]);
-const scheduleStatusOptions = ref([]);
-const relevanceOptions = ref([]);
 const staffOptions = ref([]);
 
 const recordDialogOpen = ref(false);
@@ -237,9 +239,6 @@ function getOperateLogs(id) {
 }
 
 function getOptions() {
-  listCommonDict("visit_type").then(res => { visitTypeOptions.value = res.data || []; });
-  listCommonDict("schedule_status").then(res => { scheduleStatusOptions.value = res.data || []; });
-  listCommonDict("relevance_type").then(res => { relevanceOptions.value = res.data || []; });
   selectStaffOptionList().then(res => { staffOptions.value = res.data || []; });
 }
 
@@ -290,8 +289,9 @@ const submitRecord = () => {
 :deep(.custom-drawer) {
   .el-drawer__header {
     margin-bottom: 0;
-    padding: 12px 20px;
-    border-bottom: 1px solid #ebeef5;
+    padding: 20px 24px;
+    border-bottom: 1px solid #f0f0f0;
+    background-color: #fff !important;
     color: #333;
     font-weight: normal;
   }
@@ -307,15 +307,20 @@ const submitRecord = () => {
 
 .detail-wrap {
   display: flex;
-  height: 100%;
+  height: calc(100vh - 64px);
+  overflow: hidden;
   
   .left-panel {
     flex: 1;
     background: #fff;
-    padding: 15px 20px;
+    padding: 0;
     margin-right: 10px;
     border-right: 1px solid #ebeef5;
-    
+    overflow-y: auto;
+    &::-webkit-scrollbar { display: none; }
+    -ms-overflow-style: none;
+    scrollbar-width: none;
+
     :deep(.el-tabs__header) {
       margin: 0;
       padding: 0 10px;
@@ -337,6 +342,7 @@ const submitRecord = () => {
     }
 
     .info-section {
+      padding: 15px 20px;
       padding-top: 5px;
       
       .info-title {
@@ -370,6 +376,10 @@ const submitRecord = () => {
     width: 450px;
     background: #fff;
     padding: 15px 20px;
+    overflow-y: auto;
+    &::-webkit-scrollbar { display: none; }
+    -ms-overflow-style: none;
+    scrollbar-width: none;
     
     :deep(.el-tabs__item) {
       font-size: 14px;

+ 6 - 8
src/views/visit/routine/edit.vue

@@ -38,9 +38,9 @@
               <el-select v-model="form.importantLevel" placeholder="请选择" style="width: 100%">
                 <el-option
                   v-for="dict in importanceOptions"
-                  :key="dict.dictValue"
-                  :label="dict.dictLabel"
-                  :value="dict.dictValue"
+                  :key="dict.value"
+                  :label="dict.label"
+                  :value="dict.value"
                 />
               </el-select>
             </el-form-item>
@@ -68,12 +68,11 @@
 </template>
 
 <script setup>
-import { ref, reactive, onMounted, getCurrentInstance, watch, computed } from 'vue';
+import { ref, reactive, onMounted, getCurrentInstance, watch, computed, toRefs } from 'vue';
 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 { listCommonDict } from "@/api/customer/customerDict";
 import { listOpportunity } from "@/api/saleManage/opportunity";
 import { listProjectSelection } from "@/api/saleManage/projectSelection";
 
@@ -83,7 +82,8 @@ const props = defineProps({
 });
 
 const emit = defineEmits(['update:modelValue', 'success']);
-const { proxy } = getCurrentInstance();
+const proxy = getCurrentInstance().proxy;
+const { importance_level: importanceOptions } = toRefs(reactive(proxy.useDict("importance_level")));
 
 const formRef = ref(null);
 const planOptions = ref([]);
@@ -91,7 +91,6 @@ const customerOptions = ref([]);
 const opportunityOptions = ref([]);
 const annualOptions = ref([]);
 const staffOptions = ref([]);
-const importanceOptions = ref([]);
 
 const form = ref({
   id: undefined,
@@ -198,7 +197,6 @@ onMounted(() => {
   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 || []; });
-  listCommonDict("importance_level").then(res => { importanceOptions.value = res.data || []; });
 });
 </script>
 

+ 13 - 15
src/views/visit/routine/index.vue

@@ -13,9 +13,9 @@
           <el-select v-model="queryParams.scheduleStatus" placeholder="请选择" clearable>
             <el-option
               v-for="dict in scheduleStatusOptions"
-              :key="dict.dictValue"
-              :label="dict.dictLabel"
-              :value="dict.dictValue"
+              :key="dict.value"
+              :label="dict.label"
+              :value="dict.value"
             />
           </el-select>
         </el-form-item>
@@ -61,18 +61,18 @@
         <el-table-column label="状态" align="center" prop="scheduleStatus" 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.dictValue) === String(scope.row.scheduleStatus))?.dictLabel || (String(scope.row.scheduleStatus) === '0' ? '未执行' : (String(scope.row.scheduleStatus) === '1' ? '已执行' : '放弃执行')) }}
+              {{ scheduleStatusOptions.find(d => String(d.value) === String(scope.row.scheduleStatus))?.label || (String(scope.row.scheduleStatus) === '0' ? '未执行' : (String(scope.row.scheduleStatus) === '1' ? '已执行' : '放弃执行')) }}
             </el-tag>
           </template>
         </el-table-column>
         <el-table-column label="关联类型" align="center" prop="relevanceType" width="100">
           <template #default="scope">
-            {{ relevanceOptions.find(d => String(d.dictValue) === String(scope.row.relevanceType))?.dictLabel || (String(scope.row.relevanceType) === '0' ? '客户' : (String(scope.row.relevanceType) === '1' ? '项目' : '供应商')) }}
+            {{ relevanceOptions.find(d => String(d.value) === String(scope.row.relevanceType))?.label || (String(scope.row.relevanceType) === '0' ? '客户' : (String(scope.row.relevanceType) === '1' ? '项目' : '供应商')) }}
           </template>
         </el-table-column>
         <el-table-column label="重要级别" align="center" prop="importantLevel" width="100">
           <template #default="scope">
-            <span>{{ importanceOptions.find(d => String(d.dictValue) === String(scope.row.importantLevel))?.dictLabel || scope.row.importantLevel || '' }}</span>
+            <span>{{ importanceOptions.find(d => String(d.value) === String(scope.row.importantLevel))?.label || scope.row.importantLevel || '' }}</span>
           </template>
         </el-table-column>
         <el-table-column label="操作" align="center" width="180" fixed="right">
@@ -99,19 +99,20 @@
 </template>
 
 <script setup name="VisitRoutine">
-import { ref, reactive, onMounted, getCurrentInstance } from 'vue';
+import { ref, reactive, onMounted, getCurrentInstance, toRefs } from 'vue';
 import { listRoutine, delRoutine } from "@/api/visit/routine";
-import { listCommonDict } from "@/api/customer/customerDict";
 import { selectStaffOptionList } from "@/api/customer/crmStaff";
 import AddRoutine from './add.vue';
 import EditRoutine from './edit.vue';
 import DetailRoutine from './detail.vue';
 
-const { proxy } = getCurrentInstance();
+const proxy = getCurrentInstance().proxy;
+const { 
+  importance_level: importanceOptions, 
+  schedule_status: scheduleStatusOptions, 
+  relevance_type: relevanceOptions 
+} = toRefs(reactive(proxy.useDict("importance_level", "schedule_status", "relevance_type")));
 
-const importanceOptions = ref([]);
-const scheduleStatusOptions = ref([]);
-const relevanceOptions = ref([]);
 const staffOptions = ref([]);
 
 const queryRef = ref(null);
@@ -183,9 +184,6 @@ const handleDelete = (row) => {
 };
 
 const getOptions = () => {
-  listCommonDict("importance_level").then(res => { importanceOptions.value = res.data || []; });
-  listCommonDict("schedule_status").then(res => { scheduleStatusOptions.value = res.data || []; });
-  listCommonDict("relevance_type").then(res => { relevanceOptions.value = res.data || []; });
   selectStaffOptionList().then(res => { staffOptions.value = res.data || []; });
 };