Procházet zdrojové kódy

红德堂-润天天天外呼相关代码迁移

Long před 1 týdnem
rodič
revize
41311df800
25 změnil soubory, kde provedl 1680 přidání a 0 odebrání
  1. 89 0
      fs-admin/src/main/java/com/fs/his/controller/FsDoctorVoiceLogsController.java
  2. 10 0
      fs-company/src/main/java/com/fs/company/controller/company/CompanyVoiceApiController.java
  3. 183 0
      fs-company/src/main/java/com/fs/company/controller/company/FsDoctorVoiceCallerController.java
  4. 98 0
      fs-company/src/main/java/com/fs/company/controller/doctor/FsDoctorVoiceLogsController.java
  5. 3 0
      fs-service/src/main/java/com/fs/company/service/ICompanyService.java
  6. 15 0
      fs-service/src/main/java/com/fs/company/service/impl/CompanyServiceImpl.java
  7. 114 0
      fs-service/src/main/java/com/fs/doctor/domain/FsDoctorVoiceLogs.java
  8. 65 0
      fs-service/src/main/java/com/fs/doctor/mapper/FsDoctorVoiceLogsMapper.java
  9. 18 0
      fs-service/src/main/java/com/fs/doctor/param/DoctorVoiceCallerParam.java
  10. 44 0
      fs-service/src/main/java/com/fs/doctor/param/DoctorVoiceLogsParam.java
  11. 64 0
      fs-service/src/main/java/com/fs/doctor/service/IFsDoctorVoiceLogsService.java
  12. 96 0
      fs-service/src/main/java/com/fs/doctor/service/impl/FsDoctorVoiceLogsServiceImpl.java
  13. 52 0
      fs-service/src/main/java/com/fs/doctor/vo/DoctorVoiceCallerListVO.java
  14. 96 0
      fs-service/src/main/java/com/fs/doctor/vo/DoctorVoiceLogsVO.java
  15. 48 0
      fs-service/src/main/java/com/fs/his/domain/FsDoctorVoiceCaller.java
  16. 8 0
      fs-service/src/main/java/com/fs/his/mapper/FsDoctorMapper.java
  17. 106 0
      fs-service/src/main/java/com/fs/his/mapper/FsDoctorVoiceCallerMapper.java
  18. 2 0
      fs-service/src/main/java/com/fs/his/service/IFsDoctorService.java
  19. 69 0
      fs-service/src/main/java/com/fs/his/service/IFsDoctorVoiceCallerService.java
  20. 23 0
      fs-service/src/main/java/com/fs/his/service/impl/FsDoctorServiceImpl.java
  21. 111 0
      fs-service/src/main/java/com/fs/his/service/impl/FsDoctorVoiceCallerServiceImpl.java
  22. 2 0
      fs-service/src/main/java/com/fs/voice/service/IVoiceService.java
  23. 121 0
      fs-service/src/main/java/com/fs/voice/service/impl/VoiceServiceImpl.java
  24. 80 0
      fs-service/src/main/resources/mapper/his/FsDoctorVoiceCallerMapper.xml
  25. 163 0
      fs-service/src/main/resources/mapper/his/FsDoctorVoiceLogsMapper.xml

+ 89 - 0
fs-admin/src/main/java/com/fs/his/controller/FsDoctorVoiceLogsController.java

@@ -0,0 +1,89 @@
+package com.fs.his.controller;
+
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.ParseUtils;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.doctor.domain.FsDoctorVoiceLogs;
+import com.fs.doctor.service.IFsDoctorVoiceLogsService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.List;
+
+/**
+ * 医生通话记录Controller
+ * 
+ * @author fs
+ * @date 2025-12-23
+ */
+@RestController
+@RequestMapping("/his/doctor/logs")
+public class FsDoctorVoiceLogsController extends BaseController
+{
+    @Autowired
+    private IFsDoctorVoiceLogsService fsDoctorVoiceLogsService;
+
+    /**
+     * 查询医生通话记录列表
+     */
+    @PreAuthorize("@ss.hasPermi('his:doctor:logs:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(FsDoctorVoiceLogs fsDoctorVoiceLogs)
+    {
+        startPage();
+        List<FsDoctorVoiceLogs> list = fsDoctorVoiceLogsService.selectFsDoctorVoiceLogsList(fsDoctorVoiceLogs);
+        if (list != null) {
+            for (FsDoctorVoiceLogs vo : list) {
+                vo.setCalleePhone(ParseUtils.parsePhone(vo.getCalleePhone()));
+                vo.setCallerPhone(ParseUtils.parsePhone(vo.getCallerPhone()));
+                vo.setDisplayCalleeNumber(ParseUtils.parsePhone(vo.getDisplayCalleeNumber()));
+                vo.setDisplayCallerNumber(ParseUtils.parsePhone(vo.getDisplayCallerNumber()));
+                if (vo.getRemark()!=null&&vo.getRemark().length()>11){
+                    StringBuilder replace = new StringBuilder(vo.getRemark()).replace(vo.getRemark().length() - 8, vo.getRemark().length() - 4, "*****");
+                    vo.setRemark(replace.toString());
+                }
+                if (vo.getVoiceTitle()!=null&&vo.getVoiceTitle().length()>11){
+                    StringBuilder replace = new StringBuilder(vo.getVoiceTitle()).replace(vo.getVoiceTitle().length() - 8, vo.getVoiceTitle().length() - 4, "*****");
+                    vo.setVoiceTitle(replace.toString());
+                }
+            }
+        }
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出医生通话记录列表
+     */
+    @PreAuthorize("@ss.hasPermi('his:doctor:logs:export')")
+    @Log(title = "医生通话记录", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(FsDoctorVoiceLogs fsDoctorVoiceLogs)
+    {
+        List<FsDoctorVoiceLogs> list = fsDoctorVoiceLogsService.selectFsDoctorVoiceLogsList(fsDoctorVoiceLogs);
+        if (list != null) {
+            for (FsDoctorVoiceLogs vo : list) {
+                vo.setCalleePhone(ParseUtils.parsePhone(vo.getCalleePhone()));
+                vo.setCallerPhone(ParseUtils.parsePhone(vo.getCallerPhone()));
+                vo.setDisplayCalleeNumber(ParseUtils.parsePhone(vo.getDisplayCalleeNumber()));
+                vo.setDisplayCallerNumber(ParseUtils.parsePhone(vo.getDisplayCallerNumber()));
+                if (vo.getRemark()!=null&&vo.getRemark().length()>11){
+                    StringBuilder replace = new StringBuilder(vo.getRemark()).replace(vo.getRemark().length() - 8, vo.getRemark().length() - 4, "*****");
+                    vo.setRemark(replace.toString());
+                }
+                if (vo.getVoiceTitle()!=null&&vo.getVoiceTitle().length()>11){
+                    StringBuilder replace = new StringBuilder(vo.getVoiceTitle()).replace(vo.getVoiceTitle().length() - 8, vo.getVoiceTitle().length() - 4, "*****");
+                    vo.setVoiceTitle(replace.toString());
+                }
+            }
+        }
+        ExcelUtil<FsDoctorVoiceLogs> util = new ExcelUtil<FsDoctorVoiceLogs>(FsDoctorVoiceLogs.class);
+        return util.exportExcel(list, "医生通话记录数据");
+    }
+}

+ 10 - 0
fs-company/src/main/java/com/fs/company/controller/company/CompanyVoiceApiController.java

@@ -56,6 +56,16 @@ public class CompanyVoiceApiController extends BaseController {
         return voiceService.voiceCall(loginUser.getCompany().getCompanyId(),customerId,contactsId,loginUser.getUser().getUserId(),orderId,packageOrderId);
     }
 
+    @ApiOperation("手动呼叫")
+    @GetMapping("/manualDialingCallMobile")
+    @RepeatSubmit
+    public R manualDialingCallMobile(HttpServletRequest request,
+                                     @ApiParam(required = false, name = "phoneNumber", value = "手机号") @RequestParam(value = "phoneNumber", required = false) String phoneNumber) throws Exception
+    {
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        return voiceService.manualDialingVoiceCall(loginUser.getCompany().getCompanyId(),phoneNumber,loginUser.getUser().getUserId());
+    }
+
 
     @ApiOperation("外呼挂断")
     @GetMapping("callOffMobile")

+ 183 - 0
fs-company/src/main/java/com/fs/company/controller/company/FsDoctorVoiceCallerController.java

@@ -0,0 +1,183 @@
+package com.fs.company.controller.company;
+
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.domain.R;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.ServletUtils;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.company.domain.Company;
+import com.fs.company.domain.CompanyVoiceCaller;
+import com.fs.company.service.ICompanyService;
+import com.fs.company.service.ICompanyVoiceCallerService;
+import com.fs.doctor.param.DoctorVoiceCallerParam;
+import com.fs.doctor.vo.DoctorVoiceCallerListVO;
+import com.fs.framework.security.LoginUser;
+import com.fs.framework.service.TokenService;
+import com.fs.his.domain.FsDoctorVoiceCaller;
+import com.fs.his.service.IFsDoctorVoiceCallerService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.Date;
+import java.util.List;
+
+/**
+ * 医生用户坐席Controller
+ *
+ * @author fs
+ * @date 2025-12-03
+ */
+@RestController
+@RequestMapping("/company/doctorVoice")
+public class FsDoctorVoiceCallerController extends BaseController
+{
+
+    @Autowired
+    private TokenService tokenService;
+    @Autowired
+    private IFsDoctorVoiceCallerService fsDoctorVoiceCallerService;
+    @Autowired
+    private ICompanyVoiceCallerService companyVoiceCallerService;
+    @Autowired
+    private ICompanyService companyService;
+
+    /**
+     * 查询医生用户坐席列表
+     */
+    @GetMapping("/list")
+    public TableDataInfo list(DoctorVoiceCallerParam doctorVoiceCallerParam)
+    {
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        doctorVoiceCallerParam.setCompanyId(loginUser.getUser().getCompanyId());
+        startPage();
+        List<DoctorVoiceCallerListVO> list = fsDoctorVoiceCallerService.selectFsDoctorVoiceCallerList(doctorVoiceCallerParam);
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出医生用户坐席列表
+     */
+    @Log(title = "企业用户坐席", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(DoctorVoiceCallerParam doctorVoiceCallerParam)
+    {
+
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        doctorVoiceCallerParam.setCompanyId(loginUser.getUser().getCompanyId());
+        List<DoctorVoiceCallerListVO> list = fsDoctorVoiceCallerService.selectFsDoctorVoiceCallerList(doctorVoiceCallerParam);
+        ExcelUtil<DoctorVoiceCallerListVO> util = new ExcelUtil<>(DoctorVoiceCallerListVO.class);
+        return util.exportExcel(list, "doctorCalling");
+    }
+
+    /**
+     * 获取医生用户坐席详细信息
+     */
+    @GetMapping(value = "/{callerId}")
+    public AjaxResult getInfo(@PathVariable("callerId") Long callerId)
+    {
+        return AjaxResult.success(fsDoctorVoiceCallerService.selectFsDoctorVoiceCallerByCallerId(callerId));
+    }
+
+    /**
+     * 新增企业用户坐席
+     */
+    @Log(title = "企业用户坐席", businessType = BusinessType.INSERT)
+    @Transactional
+    @PostMapping("/bindCallerNo")
+    public R bindCallerNo(@RequestBody FsDoctorVoiceCaller caller)
+    {
+
+        CompanyVoiceCaller checkCaller=companyVoiceCallerService.selectCompanyVoiceCallerById(caller.getCallerId());
+        if(checkCaller.getStatus()==0){
+            return R.error("此坐席号已绑定销售");
+        }
+        FsDoctorVoiceCaller checkDoctorCaller=fsDoctorVoiceCallerService.selectFsDoctorVoiceCallerByCallerId(caller.getCallerId());
+        if(checkDoctorCaller!=null &&checkDoctorCaller.getStatus()==0 ){
+            return R.error("此坐席号已禁用");
+        }
+        //处理 是否已添加,暂时只让一个医生绑一个坐席
+        FsDoctorVoiceCaller check=fsDoctorVoiceCallerService.selectFsDoctorVoiceCallerByDoctorId(caller.getDoctorId());
+        if(check!=null){
+            return R.error("此医生已绑定坐席");
+        }
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        Company company=companyService.selectCompanyById(caller.getCompanyId());
+        //获取已分配置所有坐席数
+        Integer counts=companyVoiceCallerService.selectCompanyVoiceCallerCountsByCompanyId(company.getCompanyId());
+        if(counts>=company.getVoiceCallerNumber()){
+            return R.error("没有可分配置的坐席号");
+        }
+
+        caller.setStatus(0);
+        caller.setCompanyId(caller.getCompanyId());
+        caller.setCompanyUserId(loginUser.getUser().getUserId());
+        caller.setCallerNo(checkCaller.getCallerNo());
+        caller.setCompanyCallerId(checkCaller.getCallerId());
+        Date currentDate = new Date();
+        caller.setBindTime(currentDate);
+
+        //将坐席号先置为绑定
+        CompanyVoiceCaller companyVoiceCaller = new CompanyVoiceCaller();
+        companyVoiceCaller.setCallerId(caller.getCallerId());
+        companyVoiceCaller.setCompanyId(caller.getCompanyId());
+        //这里绑定的是医生id
+        companyVoiceCaller.setCompanyUserId(caller.getDoctorId());
+        companyVoiceCaller.setMobile(caller.getMobile());
+        companyVoiceCaller.setStatus(0);
+        companyVoiceCaller.setRemark("医生绑定坐席");
+        companyVoiceCaller.setBindTime(currentDate);
+        if(companyVoiceCallerService.updateCompanyVoiceCaller(companyVoiceCaller)==0){
+            return R.error("绑定坐席失败1");
+        }
+
+        if(fsDoctorVoiceCallerService.insertFsDoctorVoiceCaller(caller)>0){
+            return R.ok("操作成功");
+        }
+        else
+        {
+            return R.error("绑定坐席失败2");
+        }
+    }
+
+    /**
+     * 删除医生用户坐席
+     */
+    @Log(title = "企业用户坐席", businessType = BusinessType.DELETE)
+    @Transactional
+    @DeleteMapping("/{callerIds}")
+    public R remove(@PathVariable Long[] callerIds) {
+        for(Long id:callerIds){
+            FsDoctorVoiceCaller fsDoctorVoiceCaller = fsDoctorVoiceCallerService.selectFsDoctorVoiceCallerByCallerId(id);
+            if(fsDoctorVoiceCaller==null){
+                return R.error("此坐席号不存在");
+            }
+            if(fsDoctorVoiceCaller.getCompanyCallerId() != null){
+                //将坐席号先置为解绑
+                CompanyVoiceCaller companyVoiceCaller = new CompanyVoiceCaller();
+                companyVoiceCaller.setCallerId(fsDoctorVoiceCaller.getCompanyCallerId());
+                companyVoiceCaller.setCompanyId(0L);
+                companyVoiceCaller.setMobile("");
+                companyVoiceCaller.setStatus(1);
+                companyVoiceCaller.setRemark("");
+                companyVoiceCaller.setBindTime(null);
+                companyVoiceCallerService.updateCompanyVoiceCaller(companyVoiceCaller);
+            }
+            fsDoctorVoiceCallerService.deleteFsDoctorVoiceCallerByCallerId(id);
+        }
+        return R.ok("删除成功");
+    }
+
+    /**
+     * 获取医生所属企业列表
+     */
+    @GetMapping("/getCompanyDoctor/{companyId}")
+    public R getCompanyDoctor(@PathVariable("companyId") Long companyId)
+    {
+        return R.ok().put("data", companyService.getCompanyDoctors(companyId));
+    }
+
+}

+ 98 - 0
fs-company/src/main/java/com/fs/company/controller/doctor/FsDoctorVoiceLogsController.java

@@ -0,0 +1,98 @@
+package com.fs.company.controller.doctor;
+
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.ParseUtils;
+import com.fs.common.utils.ServletUtils;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.doctor.domain.FsDoctorVoiceLogs;
+import com.fs.doctor.service.IFsDoctorVoiceLogsService;
+import com.fs.framework.security.LoginUser;
+import com.fs.framework.service.TokenService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.List;
+
+/**
+ * 医生通话记录Controller
+ * 
+ * @author fs
+ * @date 2025-12-23
+ */
+@RestController
+@RequestMapping("/company/doctor/logs")
+public class FsDoctorVoiceLogsController extends BaseController
+{
+    @Autowired
+    private IFsDoctorVoiceLogsService fsDoctorVoiceLogsService;
+    @Autowired
+    private TokenService tokenService;
+
+    /**
+     * 查询医生通话记录列表
+     */
+    @PreAuthorize("@ss.hasPermi('company:doctor:logs:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(FsDoctorVoiceLogs fsDoctorVoiceLogs)
+    {
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        fsDoctorVoiceLogs.setCompanyId(loginUser.getCompany().getCompanyId());
+        startPage();
+        List<FsDoctorVoiceLogs> list = fsDoctorVoiceLogsService.selectFsDoctorVoiceLogsList(fsDoctorVoiceLogs);
+        if (list != null) {
+            for (FsDoctorVoiceLogs vo : list) {
+                vo.setCalleePhone(ParseUtils.parsePhone(vo.getCalleePhone()));
+                vo.setCallerPhone(ParseUtils.parsePhone(vo.getCallerPhone()));
+                vo.setDisplayCalleeNumber(ParseUtils.parsePhone(vo.getDisplayCalleeNumber()));
+                vo.setDisplayCallerNumber(ParseUtils.parsePhone(vo.getDisplayCallerNumber()));
+                if (vo.getRemark()!=null&&vo.getRemark().length()>11){
+                    StringBuilder replace = new StringBuilder(vo.getRemark()).replace(vo.getRemark().length() - 8, vo.getRemark().length() - 4, "*****");
+                    vo.setRemark(replace.toString());
+                }
+                if (vo.getVoiceTitle()!=null&&vo.getVoiceTitle().length()>11){
+                    StringBuilder replace = new StringBuilder(vo.getVoiceTitle()).replace(vo.getVoiceTitle().length() - 8, vo.getVoiceTitle().length() - 4, "*****");
+                    vo.setVoiceTitle(replace.toString());
+                }
+            }
+        }
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出医生通话记录列表
+     */
+    @PreAuthorize("@ss.hasPermi('company:doctor:logs:export')")
+    @Log(title = "医生通话记录", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(FsDoctorVoiceLogs fsDoctorVoiceLogs)
+    {
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        fsDoctorVoiceLogs.setCompanyId(loginUser.getCompany().getCompanyId());
+        List<FsDoctorVoiceLogs> list = fsDoctorVoiceLogsService.selectFsDoctorVoiceLogsList(fsDoctorVoiceLogs);
+        if (list != null) {
+            for (FsDoctorVoiceLogs vo : list) {
+                vo.setCalleePhone(ParseUtils.parsePhone(vo.getCalleePhone()));
+                vo.setCallerPhone(ParseUtils.parsePhone(vo.getCallerPhone()));
+                vo.setDisplayCalleeNumber(ParseUtils.parsePhone(vo.getDisplayCalleeNumber()));
+                vo.setDisplayCallerNumber(ParseUtils.parsePhone(vo.getDisplayCallerNumber()));
+                if (vo.getRemark()!=null&&vo.getRemark().length()>11){
+                    StringBuilder replace = new StringBuilder(vo.getRemark()).replace(vo.getRemark().length() - 8, vo.getRemark().length() - 4, "*****");
+                    vo.setRemark(replace.toString());
+                }
+                if (vo.getVoiceTitle()!=null&&vo.getVoiceTitle().length()>11){
+                    StringBuilder replace = new StringBuilder(vo.getVoiceTitle()).replace(vo.getVoiceTitle().length() - 8, vo.getVoiceTitle().length() - 4, "*****");
+                    vo.setVoiceTitle(replace.toString());
+                }
+            }
+        }
+        ExcelUtil<FsDoctorVoiceLogs> util = new ExcelUtil<FsDoctorVoiceLogs>(FsDoctorVoiceLogs.class);
+        return util.exportExcel(list, "医生通话记录数据");
+    }
+}

+ 3 - 0
fs-service/src/main/java/com/fs/company/service/ICompanyService.java

@@ -14,6 +14,7 @@ import com.fs.company.vo.CompanyCrmVO;
 import com.fs.company.vo.CompanyNameVO;
 import com.fs.company.vo.CompanyVO;
 import com.fs.company.vo.DeptDataVO;
+import com.fs.his.domain.FsDoctor;
 import com.fs.his.domain.FsInquiryOrder;
 import com.fs.his.domain.FsStoreOrder;
 import com.fs.his.domain.FsStorePayment;
@@ -218,4 +219,6 @@ public interface ICompanyService
     void addCompanyTuiLiveMoney(LiveOrder order);
 
     void subLiveCompanyMoney(LiveOrder order);
+
+    List<FsDoctor> getCompanyDoctors(Long companyId);
 }

+ 15 - 0
fs-service/src/main/java/com/fs/company/service/impl/CompanyServiceImpl.java

@@ -24,11 +24,13 @@ import com.fs.company.util.CompanyRedPacketBalanceUtil;
 import com.fs.company.vo.*;
 import com.fs.course.mapper.FsCourseRedPacketLogMapper;
 import com.fs.his.config.StoreConfig;
+import com.fs.his.domain.FsDoctor;
 import com.fs.his.domain.FsInquiryOrder;
 import com.fs.his.domain.FsStoreOrder;
 import com.fs.his.domain.FsStorePayment;
 import com.fs.his.dto.InquiryConfigDTO;
 import com.fs.his.mapper.FsStoreOrderMapper;
+import com.fs.his.service.IFsDoctorService;
 import com.fs.his.vo.OptionsVO;
 import com.fs.hisStore.domain.FsStoreOrderScrm;
 import com.fs.hisStore.domain.FsStorePaymentScrm;
@@ -126,6 +128,8 @@ public class CompanyServiceImpl implements ICompanyService
     private CompanyRedPacketBalanceUtil companyRedPacketBalanceUtil;
     @Autowired
     private LiveOrderMapper liveOrderMapper;
+    @Autowired
+    private IFsDoctorService doctorService;
 
 
     @Override
@@ -1696,4 +1700,15 @@ public class CompanyServiceImpl implements ICompanyService
         }));
     }
 
+    @Override
+    public List<FsDoctor> getCompanyDoctors(Long companyId) {
+        Company company = companyMapper.selectCompanyById(companyId);
+        if(company!=null){
+            if(StringUtils.isNotEmpty(company.getDoctorIds())){
+                return doctorService.selectFsDoctorByDoctorIds(company.getDoctorIds());
+            }
+        }
+        return null;
+    }
+
 }

+ 114 - 0
fs-service/src/main/java/com/fs/doctor/domain/FsDoctorVoiceLogs.java

@@ -0,0 +1,114 @@
+package com.fs.doctor.domain;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.fs.common.annotation.Excel;
+import com.fs.common.core.domain.BaseEntity;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.util.Date;
+
+/**
+ * 医生通话记录对象 fs_doctor_voice_logs
+ *
+ * @author fs
+ * @date 2025-12-23
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+public class FsDoctorVoiceLogs extends BaseEntity{
+
+    /** ID */
+    private Long voiceId;
+
+    /** 公司id */
+    @Excel(name = "公司id")
+    private Long companyId;
+    /** 公司名 */
+    @Excel(name = "公司名")
+    private String companyName;
+
+    /** 标题 */
+    @Excel(name = "标题")
+    private String voiceTitle;
+
+    /** 录音地址 */
+    @Excel(name = "录音地址")
+    private String voiceUrl;
+
+    /** 开始时间 */
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    @Excel(name = "开始时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss")
+    private Date startTime;
+
+    /** 结束时间 */
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    @Excel(name = "结束时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss")
+    private Date finishTime;
+
+    /** 通话类型 1 语音外号 */
+    @Excel(name = "通话类型 1 语音外号")
+    private Integer voiceType;
+
+    /** 主叫 */
+    @Excel(name = "主叫")
+    private String callerPhone;
+
+    /** 被叫 */
+    @Excel(name = "被叫")
+    private String calleePhone;
+
+    /** 时长 */
+    @Excel(name = "时长")
+    private Long times;
+
+    /** 计费 分 */
+    @Excel(name = "计费 分")
+    private Long billingTime;
+
+    /** 主叫显示号 */
+    @Excel(name = "主叫显示号")
+    private String displayCallerNumber;
+
+    /** 被叫显示号 */
+    @Excel(name = "被叫显示号")
+    private String displayCalleeNumber;
+
+    /** 医生id */
+    @Excel(name = "医生id")
+    private Long doctorId;
+    /** 医生姓名 */
+    @Excel(name = "医生姓名")
+    private String doctorName;
+
+    /** 状态 1接口调用成功 2呼出 3振铃 4应答 5挂机 */
+    @Excel(name = "状态 1接口调用成功 2呼出 3振铃 4应答 5挂机")
+    private Integer status;
+
+    /** 会话ID */
+    @Excel(name = "会话ID")
+    private String sessionId;
+
+    /** 病人ID */
+    @Excel(name = "病人ID")
+    private Long patientId;
+    /** 病人姓名 */
+    @Excel(name = "病人姓名")
+    private String patientName;
+
+    /** apiId */
+    @Excel(name = "apiId")
+    private Long apiId;
+
+    /** $column.columnComment */
+    @Excel(name = "apiId")
+    private String callerNo;
+
+    private String[] createTimeList;
+
+    private String createTimeRange;
+
+    private String[] startTimeList;
+
+    private String dateRange;
+}

+ 65 - 0
fs-service/src/main/java/com/fs/doctor/mapper/FsDoctorVoiceLogsMapper.java

@@ -0,0 +1,65 @@
+package com.fs.doctor.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.fs.doctor.domain.FsDoctorVoiceLogs;
+import org.apache.ibatis.annotations.Param;
+import org.apache.ibatis.annotations.Select;
+
+import java.util.List;
+
+/**
+ * 医生通话记录Mapper接口
+ * 
+ * @author fs
+ * @date 2025-12-23
+ */
+public interface FsDoctorVoiceLogsMapper extends BaseMapper<FsDoctorVoiceLogs>{
+    /**
+     * 查询医生通话记录
+     * 
+     * @param voiceId 医生通话记录主键
+     * @return 医生通话记录
+     */
+    FsDoctorVoiceLogs selectFsDoctorVoiceLogsByVoiceId(Long voiceId);
+
+    /**
+     * 查询医生通话记录列表
+     * 
+     * @param fsDoctorVoiceLogs 医生通话记录
+     * @return 医生通话记录集合
+     */
+    List<FsDoctorVoiceLogs> selectFsDoctorVoiceLogsList(FsDoctorVoiceLogs fsDoctorVoiceLogs);
+    /**
+     * 新增医生通话记录
+     * 
+     * @param fsDoctorVoiceLogs 医生通话记录
+     * @return 结果
+     */
+    int insertFsDoctorVoiceLogs(FsDoctorVoiceLogs fsDoctorVoiceLogs);
+
+    /**
+     * 修改医生通话记录
+     * 
+     * @param fsDoctorVoiceLogs 医生通话记录
+     * @return 结果
+     */
+    int updateFsDoctorVoiceLogs(FsDoctorVoiceLogs fsDoctorVoiceLogs);
+
+    /**
+     * 删除医生通话记录
+     * 
+     * @param voiceId 医生通话记录主键
+     * @return 结果
+     */
+    int deleteFsDoctorVoiceLogsByVoiceId(Long voiceId);
+
+    /**
+     * 批量删除医生通话记录
+     * 
+     * @param voiceIds 需要删除的数据主键集合
+     * @return 结果
+     */
+    int deleteFsDoctorVoiceLogsByVoiceIds(Long[] voiceIds);
+    @Select("select * from fs_doctor_voice_logs where session_id=#{sessionId}")
+    FsDoctorVoiceLogs selectCompanyVoiceLogsBySessionId(@Param("sessionId") String sessionId);
+}

+ 18 - 0
fs-service/src/main/java/com/fs/doctor/param/DoctorVoiceCallerParam.java

@@ -0,0 +1,18 @@
+package com.fs.doctor.param;
+
+import com.fs.common.core.domain.BaseEntity;
+import lombok.Data;
+
+@Data
+public class DoctorVoiceCallerParam extends BaseEntity
+{
+    private Long doctorId;
+    private Long companyId;
+    private String doctorName;
+    private Long companyUserId;
+    private String companyUserName;
+    private String mobile;
+
+    private Integer status;
+    private String remark;
+}

+ 44 - 0
fs-service/src/main/java/com/fs/doctor/param/DoctorVoiceLogsParam.java

@@ -0,0 +1,44 @@
+package com.fs.doctor.param;
+
+import com.fs.common.core.domain.BaseEntity;
+import lombok.Data;
+
+@Data
+public class DoctorVoiceLogsParam extends BaseEntity {
+
+
+    /** 公司名 */
+    private Long doctorId;
+
+    private Long patientId;
+    private String patientName;
+
+    private Long companyUserId;
+    private String companyUserName;
+
+    private String doctorName;
+
+    /** 主叫 */
+    private String callerPhone;
+
+    /** 被叫 */
+    private String calleePhone;
+
+    private Integer status;
+
+    private Integer times;
+
+
+    private String[] createTimeList;
+
+    private String createTimeRange;
+
+    private String[] startTimeList;
+
+    private String dateRange;
+
+    private String beginTime;
+
+    private String endTime;
+
+}

+ 64 - 0
fs-service/src/main/java/com/fs/doctor/service/IFsDoctorVoiceLogsService.java

@@ -0,0 +1,64 @@
+package com.fs.doctor.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.fs.doctor.domain.FsDoctorVoiceLogs;
+
+import java.util.List;
+
+/**
+ * 医生通话记录Service接口
+ * 
+ * @author fs
+ * @date 2025-12-23
+ */
+public interface IFsDoctorVoiceLogsService extends IService<FsDoctorVoiceLogs>{
+    /**
+     * 查询医生通话记录
+     * 
+     * @param voiceId 医生通话记录主键
+     * @return 医生通话记录
+     */
+    FsDoctorVoiceLogs selectFsDoctorVoiceLogsByVoiceId(Long voiceId);
+
+    /**
+     * 查询医生通话记录列表
+     * 
+     * @param fsDoctorVoiceLogs 医生通话记录
+     * @return 医生通话记录集合
+     */
+    List<FsDoctorVoiceLogs> selectFsDoctorVoiceLogsList(FsDoctorVoiceLogs fsDoctorVoiceLogs);
+
+    /**
+     * 新增医生通话记录
+     * 
+     * @param fsDoctorVoiceLogs 医生通话记录
+     * @return 结果
+     */
+    int insertFsDoctorVoiceLogs(FsDoctorVoiceLogs fsDoctorVoiceLogs);
+
+    /**
+     * 修改医生通话记录
+     * 
+     * @param fsDoctorVoiceLogs 医生通话记录
+     * @return 结果
+     */
+    int updateFsDoctorVoiceLogs(FsDoctorVoiceLogs fsDoctorVoiceLogs);
+
+    /**
+     * 批量删除医生通话记录
+     * 
+     * @param voiceIds 需要删除的医生通话记录主键集合
+     * @return 结果
+     */
+    int deleteFsDoctorVoiceLogsByVoiceIds(Long[] voiceIds);
+
+    /**
+     * 删除医生通话记录信息
+     * 
+     * @param voiceId 医生通话记录主键
+     * @return 结果
+     */
+    int deleteFsDoctorVoiceLogsByVoiceId(Long voiceId);
+
+    FsDoctorVoiceLogs selectCompanyVoiceLogsBySessionId(String sessionId);
+}

+ 96 - 0
fs-service/src/main/java/com/fs/doctor/service/impl/FsDoctorVoiceLogsServiceImpl.java

@@ -0,0 +1,96 @@
+package com.fs.doctor.service.impl;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.fs.doctor.domain.FsDoctorVoiceLogs;
+import com.fs.doctor.mapper.FsDoctorVoiceLogsMapper;
+import com.fs.doctor.service.IFsDoctorVoiceLogsService;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+/**
+ * 医生通话记录Service业务层处理
+ * 
+ * @author fs
+ * @date 2025-12-23
+ */
+@Service
+public class FsDoctorVoiceLogsServiceImpl extends ServiceImpl<FsDoctorVoiceLogsMapper, FsDoctorVoiceLogs> implements IFsDoctorVoiceLogsService {
+
+    /**
+     * 查询医生通话记录
+     * 
+     * @param voiceId 医生通话记录主键
+     * @return 医生通话记录
+     */
+    @Override
+    public FsDoctorVoiceLogs selectFsDoctorVoiceLogsByVoiceId(Long voiceId)
+    {
+        return baseMapper.selectFsDoctorVoiceLogsByVoiceId(voiceId);
+    }
+
+    /**
+     * 查询医生通话记录列表
+     * 
+     * @param fsDoctorVoiceLogs 医生通话记录
+     * @return 医生通话记录
+     */
+    @Override
+    public List<FsDoctorVoiceLogs> selectFsDoctorVoiceLogsList(FsDoctorVoiceLogs fsDoctorVoiceLogs)
+    {
+        return baseMapper.selectFsDoctorVoiceLogsList(fsDoctorVoiceLogs);
+    }
+
+    /**
+     * 新增医生通话记录
+     * 
+     * @param fsDoctorVoiceLogs 医生通话记录
+     * @return 结果
+     */
+    @Override
+    public int insertFsDoctorVoiceLogs(FsDoctorVoiceLogs fsDoctorVoiceLogs)
+    {
+        return baseMapper.insertFsDoctorVoiceLogs(fsDoctorVoiceLogs);
+    }
+
+    /**
+     * 修改医生通话记录
+     * 
+     * @param fsDoctorVoiceLogs 医生通话记录
+     * @return 结果
+     */
+    @Override
+    public int updateFsDoctorVoiceLogs(FsDoctorVoiceLogs fsDoctorVoiceLogs)
+    {
+        return baseMapper.updateFsDoctorVoiceLogs(fsDoctorVoiceLogs);
+    }
+
+    /**
+     * 批量删除医生通话记录
+     * 
+     * @param voiceIds 需要删除的医生通话记录主键
+     * @return 结果
+     */
+    @Override
+    public int deleteFsDoctorVoiceLogsByVoiceIds(Long[] voiceIds)
+    {
+        return baseMapper.deleteFsDoctorVoiceLogsByVoiceIds(voiceIds);
+    }
+
+    /**
+     * 删除医生通话记录信息
+     * 
+     * @param voiceId 医生通话记录主键
+     * @return 结果
+     */
+    @Override
+    public int deleteFsDoctorVoiceLogsByVoiceId(Long voiceId)
+    {
+        return baseMapper.deleteFsDoctorVoiceLogsByVoiceId(voiceId);
+    }
+
+    @Override
+    public FsDoctorVoiceLogs selectCompanyVoiceLogsBySessionId(String sessionId) {
+        return baseMapper.selectCompanyVoiceLogsBySessionId(sessionId);
+    }
+}

+ 52 - 0
fs-service/src/main/java/com/fs/doctor/vo/DoctorVoiceCallerListVO.java

@@ -0,0 +1,52 @@
+package com.fs.doctor.vo;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.fs.common.annotation.Excel;
+import lombok.Data;
+
+import java.io.Serializable;
+import java.util.Date;
+
+@Data
+public class DoctorVoiceCallerListVO implements Serializable {
+
+    /** ID */
+    private Long callerId;
+
+    /** 医生ID */
+    @Excel(name = "医生ID")
+    private Long doctorId;
+
+    /** 医生名称 */
+    @Excel(name = "医生名称")
+    private String doctorName;
+
+    /** 销售ID */
+    @Excel(name = "销售ID")
+    private Long companyUserId;
+    /** 销售名称 */
+    @Excel(name = "销售名称")
+    private String companyUserName;
+    /** 坐席号 */
+    @Excel(name = "坐席号")
+    private String callerNo;
+
+    /** 手机号 主叫 */
+    @Excel(name = "手机号 主叫")
+    private String mobile;
+
+    /** 状态 1正常0禁用 */
+    @Excel(name = "状态 1正常0禁用")
+    private Integer status;
+
+    /** 备注 */
+    @Excel(name = "备注")
+    private String remark;
+
+    /** 绑定时间  */
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    @Excel(name = "绑定时间 ", width = 30, dateFormat = "yyyy-MM-dd")
+    private Date bindTime;
+
+    private String companyName;
+}

+ 96 - 0
fs-service/src/main/java/com/fs/doctor/vo/DoctorVoiceLogsVO.java

@@ -0,0 +1,96 @@
+package com.fs.doctor.vo;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.fs.common.annotation.Excel;
+import lombok.Data;
+
+import java.io.Serializable;
+import java.util.Date;
+
+@Data
+public class DoctorVoiceLogsVO implements Serializable {
+    /** ID */
+    private Long voiceId;
+
+    /** 医生ID */
+    @Excel(name = "医生ID")
+    private Long doctorId;
+    /** 医生名称 */
+    @Excel(name = "医生名称")
+    private String doctorName;
+
+    /** 标题 */
+    @Excel(name = "标题")
+    private String voiceTitle;
+
+    /** 录音地址 */
+    @Excel(name = "录音地址")
+    private String voiceUrl;
+
+    /** 开始时间 */
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    @Excel(name = "开始时间", width = 30, dateFormat = "yyyy-MM-dd")
+    private Date startTime;
+
+    /** 结束时间 */
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    @Excel(name = "结束时间", width = 30, dateFormat = "yyyy-MM-dd")
+    private Date finishTime;
+
+
+    /** 通话类型 */
+    @Excel(name = "通话类型 1 语音外号")
+    private Integer voiceType;
+
+    /** 主叫 */
+    @Excel(name = "主叫")
+    private String callerPhone;
+
+    /** 被叫 */
+    @Excel(name = "被叫")
+    private String calleePhone;
+
+    /** 时长 */
+    @Excel(name = "时长")
+    private Long times;
+
+    @Excel(name = "计费 分")
+    private Long billingTime;
+
+
+    /** 主叫显示号 */
+    @Excel(name = "主叫显示号")
+    private String displayCallerNumber;
+
+    /** 被叫显示号 */
+    @Excel(name = "被叫显示号")
+    private String displayCalleeNumber;
+    @Excel(name = "病人id")
+    private Long patientId;
+    @Excel(name = "病人姓名")
+    private String patientName;
+
+    @Excel(name = "销售id")
+    private Long companyUserId;
+    @Excel(name = "销售名称")
+    private String companyUserName;
+    @Excel(name = "会话ID")
+    private String sessionId;
+
+    private String remark;
+
+    @Excel(name = "状态 1接口调用成功 2呼出 3振铃 4应答 5挂机")
+    private Integer status;
+
+    /** 客户创建时间 */
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private Date createTime;
+
+    /** apiId */
+    @Excel(name = "apiId")
+    private Long apiId;
+
+    /** $column.columnComment */
+    @Excel(name = "callerNo")
+    private String callerNo;
+}

+ 48 - 0
fs-service/src/main/java/com/fs/his/domain/FsDoctorVoiceCaller.java

@@ -0,0 +1,48 @@
+package com.fs.his.domain;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.fs.common.annotation.Excel;
+import com.fs.common.core.domain.BaseEntity;
+import lombok.Data;
+
+import java.util.Date;
+
+/**
+ * 医生用户坐席对象 fs_doctor_voice_caller
+ *
+ * @author fs
+ * @date 2025-12-03
+ */
+@Data
+public class FsDoctorVoiceCaller extends BaseEntity{
+
+    /** ID */
+    private Long callerId;
+
+    /** 企业ID */
+    @Excel(name = "企业ID")
+    private Long companyId;
+
+    /** 医生ID */
+    @Excel(name = "医生ID")
+    private Long doctorId;
+    /** 销售ID */
+    @Excel(name = "销售ID")
+    private Long companyUserId;
+    /** 坐席号 */
+    @Excel(name = "坐席号")
+    private String callerNo;
+
+    /** 手机号 主叫 */
+    @Excel(name = "手机号 主叫")
+    private String mobile;
+
+    /** 状态 1正常0禁用 */
+    @Excel(name = "状态 1正常0禁用")
+    private Integer status;
+
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private Date bindTime; //绑定时间
+
+    private Long companyCallerId;
+}

+ 8 - 0
fs-service/src/main/java/com/fs/his/mapper/FsDoctorMapper.java

@@ -221,4 +221,12 @@ public interface FsDoctorMapper
      */
     List<FsDoctorListUVO> getFsDoctorListUVOListByIds(@Param("doctorIds") List<Long> doctorIds);
     String selectDoctorNameByIds(@Param("doctorIds") String doctorIds);
+
+    @Select({"<script> " +
+            "select * from fs_doctor where doctor_id in" +
+            " <foreach item='doctorId' collection='doctorIds.split(\",\")' open='(' separator=',' close=')'>\n" +
+            "            #{doctorId}\n" +
+            " </foreach>" +
+            "</script>"})
+    List<FsDoctor> selectFsDoctorByDoctorIds(@Param("doctorIds") String doctorIds);
 }

+ 106 - 0
fs-service/src/main/java/com/fs/his/mapper/FsDoctorVoiceCallerMapper.java

@@ -0,0 +1,106 @@
+package com.fs.his.mapper;
+
+import com.fs.doctor.param.DoctorVoiceCallerParam;
+import com.fs.doctor.vo.DoctorVoiceCallerListVO;
+import com.fs.his.domain.FsDoctorVoiceCaller;
+import org.apache.ibatis.annotations.Param;
+import org.apache.ibatis.annotations.Select;
+
+import java.util.List;
+
+/**
+ * 医生用户坐席Mapper接口
+ * 
+ * @author fs
+ * @date 2025-12-03
+ */
+public interface FsDoctorVoiceCallerMapper {
+    /**
+     * 查询医生用户坐席
+     * 
+     * @param callerId 医生用户坐席主键
+     * @return 医生用户坐席
+     */
+    FsDoctorVoiceCaller selectFsDoctorVoiceCallerByCallerId(Long callerId);
+
+    /**
+     * 查询医生用户坐席列表
+     * 
+     * @param param 医生用户坐席
+     * @return 医生用户坐席集合
+     */
+    @Select({"<script> " +
+            "SELECT vc.*, d.doctor_name,cu.user_name as companyUserName,c.company_name FROM fs_doctor_voice_caller vc " +
+            "LEFT JOIN fs_doctor d ON d.doctor_id = vc.doctor_id " +
+            "LEFT JOIN company_user cu ON cu.user_id = vc.company_user_id " +
+            "LEFT JOIN company c ON c.company_id = vc.company_id " +
+            "where vc.doctor_id is not null and vc.doctor_id != '' " +
+            "<if test = 'maps.doctorId != null  '> " +
+            "and vc.doctor_id = #{maps.doctorId}" +
+            "</if>" +
+            "<if test = 'maps.companyId != null  '> " +
+            "and vc.company_id = #{maps.companyId}" +
+            "</if>" +
+            "<if test = 'maps.doctorName != null and maps.doctorName != \"\" '> " +
+            "and d.doctor_name like '%${maps.doctorName}%' " +
+            "</if>" +
+            "<if test = 'maps.status != null '> " +
+            "and vc.status = #{maps.status}" +
+            "</if>" +
+            "<if test = 'maps.remark != null and maps.remark != \"\" '> " +
+            "and vc.remark like '%${maps.remark}%' " +
+            "</if>" +
+            "<if test = 'maps.companyUserId != null  '> " +
+            "and vc.company_user_id = #{companyUserId}" +
+            "</if>" +
+            "<if test = 'maps.companyUserName != null and maps.companyUserName != \"\" '> " +
+            "and cu.user_name like '%${maps.companyUserName}%' " +
+            "</if>" +
+            "order by vc.caller_id desc " +
+            "</script>"})
+    List<DoctorVoiceCallerListVO> selectFsDoctorVoiceCallerList(@Param("maps") DoctorVoiceCallerParam param);
+
+    /**
+     * 新增医生用户坐席
+     * 
+     * @param fsDoctorVoiceCaller 医生用户坐席
+     * @return 结果
+     */
+    int insertFsDoctorVoiceCaller(FsDoctorVoiceCaller fsDoctorVoiceCaller);
+
+    /**
+     * 修改医生用户坐席
+     * 
+     * @param fsDoctorVoiceCaller 医生用户坐席
+     * @return 结果
+     */
+    int updateFsDoctorVoiceCaller(FsDoctorVoiceCaller fsDoctorVoiceCaller);
+
+    /**
+     * 删除医生用户坐席
+     * 
+     * @param callerId 医生用户坐席主键
+     * @return 结果
+     */
+    int deleteFsDoctorVoiceCallerByCallerId(Long callerId);
+
+    /**
+     * 批量删除医生用户坐席
+     * 
+     * @param callerIds 需要删除的数据主键集合
+     * @return 结果
+     */
+    int deleteFsDoctorVoiceCallerByCallerIds(Long[] callerIds);
+
+    @Select("select * from fs_doctor_voice_caller where doctor_id=#{doctorId} limit 1")
+    FsDoctorVoiceCaller selectFsDoctorVoiceCallerByDoctorId(@Param("doctorId") Long doctorId);
+    @Select("select * from fs_doctor_voice_caller where company_id=#{companyId} and doctor_id=#{doctorId}")
+    FsDoctorVoiceCaller selectFsDoctorVoiceCallerByDoctorIdOrCompanyId(@Param("companyId")Long companyId, @Param("doctorId")Long doctorId);
+    @Select({"<script> " +
+            "select * from fs_doctor_voice_caller where doctor_id in" +
+            " <foreach item='doctorId' collection='doctorIds.split(\",\")' open='(' separator=',' close=')'>\n" +
+            "            #{doctorId}\n" +
+            " </foreach>" +
+            "</script>"})
+    List<FsDoctorVoiceCaller> selectFsDoctorVoiceCallerByDoctorIds(@Param("doctorIds") String doctorIds);
+}

+ 2 - 0
fs-service/src/main/java/com/fs/his/service/IFsDoctorService.java

@@ -115,4 +115,6 @@ public interface IFsDoctorService
      * 查询医生选择列表
      */
     List<FsDoctorChooseVO> getChooseDoctorListByMap(Map<String, Object> params);
+
+    List<FsDoctor> selectFsDoctorByDoctorIds(String doctorIds);
 }

+ 69 - 0
fs-service/src/main/java/com/fs/his/service/IFsDoctorVoiceCallerService.java

@@ -0,0 +1,69 @@
+package com.fs.his.service;
+
+import com.fs.doctor.param.DoctorVoiceCallerParam;
+import com.fs.doctor.vo.DoctorVoiceCallerListVO;
+import com.fs.his.domain.FsDoctorVoiceCaller;
+
+import java.util.List;
+
+/**
+ * 医生用户坐席Service接口
+ * 
+ * @author fs
+ * @date 2025-12-03
+ */
+public interface IFsDoctorVoiceCallerService {
+    /**
+     * 查询医生用户坐席
+     * 
+     * @param callerId 医生用户坐席主键
+     * @return 医生用户坐席
+     */
+    FsDoctorVoiceCaller selectFsDoctorVoiceCallerByCallerId(Long callerId);
+
+    /**
+     * 查询医生用户坐席列表
+     * 
+     * @param doctorVoiceCallerParam 医生用户坐席
+     * @return 医生用户坐席集合
+     */
+    List<DoctorVoiceCallerListVO> selectFsDoctorVoiceCallerList(DoctorVoiceCallerParam doctorVoiceCallerParam);
+
+    /**
+     * 新增医生用户坐席
+     * 
+     * @param fsDoctorVoiceCaller 医生用户坐席
+     * @return 结果
+     */
+    int insertFsDoctorVoiceCaller(FsDoctorVoiceCaller fsDoctorVoiceCaller);
+
+    /**
+     * 修改医生用户坐席
+     * 
+     * @param fsDoctorVoiceCaller 医生用户坐席
+     * @return 结果
+     */
+    int updateFsDoctorVoiceCaller(FsDoctorVoiceCaller fsDoctorVoiceCaller);
+
+    /**
+     * 批量删除医生用户坐席
+     * 
+     * @param callerIds 需要删除的医生用户坐席主键集合
+     * @return 结果
+     */
+    int deleteFsDoctorVoiceCallerByCallerIds(Long[] callerIds);
+
+    /**
+     * 删除医生用户坐席信息
+     * 
+     * @param callerId 医生用户坐席主键
+     * @return 结果
+     */
+    int deleteFsDoctorVoiceCallerByCallerId(Long callerId);
+
+    FsDoctorVoiceCaller selectFsDoctorVoiceCallerByDoctorId(Long doctorId);
+
+    FsDoctorVoiceCaller selectFsDoctorVoiceCallerByDoctorIdOrCompanyId(Long companyId,Long doctorId);
+
+    List<FsDoctorVoiceCaller> selectFsDoctorVoiceCallerByDoctorIds(String doctorIds);
+}

+ 23 - 0
fs-service/src/main/java/com/fs/his/service/impl/FsDoctorServiceImpl.java

@@ -18,6 +18,7 @@ import com.fs.his.param.FsDoctorListUParam;
 import com.fs.his.param.FsDoctorParam;
 import com.fs.his.param.FsUpdateFollowParam;
 import com.fs.his.service.IFsDoctorService;
+import com.fs.his.service.IFsDoctorVoiceCallerService;
 import com.fs.his.service.IFsPrescribeService;
 import com.fs.his.utils.ConfigUtil;
 import com.fs.his.utils.HttpUtil;
@@ -47,6 +48,7 @@ import java.io.*;
 import java.net.URL;
 import java.util.*;
 import java.util.List;
+import java.util.stream.Collectors;
 
 /**
  * 医生管理Service业务层处理
@@ -77,6 +79,8 @@ public class FsDoctorServiceImpl implements IFsDoctorService
     ConfigUtil configUtil;
     @Autowired
     private OpenIMService openIMService;
+    @Autowired
+    private IFsDoctorVoiceCallerService doctorVoiceCallerService;
 
     /**
      * 查询医生管理
@@ -551,4 +555,23 @@ public class FsDoctorServiceImpl implements IFsDoctorService
         return fsDoctorMapper.getChooseDoctorListByMap(params);
     }
 
+    @Override
+    public List<FsDoctor> selectFsDoctorByDoctorIds(String doctorIds) {
+        // 查询所有医生
+        List<FsDoctor> DataBaseDoctors = fsDoctorMapper.selectFsDoctorByDoctorIds(doctorIds);
+
+        // 查询已绑定的医生
+        List<FsDoctorVoiceCaller> doctorVoiceCallers = doctorVoiceCallerService.selectFsDoctorVoiceCallerByDoctorIds(doctorIds);
+
+        // 提取已绑定医生的ID到Set中,便于快速查找
+        Set<Long> boundDoctorIds = doctorVoiceCallers.stream()
+                .map(FsDoctorVoiceCaller::getDoctorId)
+                .collect(Collectors.toSet());
+
+        // 过滤掉已绑定的医生
+        return DataBaseDoctors.stream()
+                .filter(doctor -> !boundDoctorIds.contains(doctor.getDoctorId()))
+                .collect(Collectors.toList());
+    }
+
 }

+ 111 - 0
fs-service/src/main/java/com/fs/his/service/impl/FsDoctorVoiceCallerServiceImpl.java

@@ -0,0 +1,111 @@
+package com.fs.his.service.impl;
+
+import com.fs.doctor.param.DoctorVoiceCallerParam;
+import com.fs.doctor.vo.DoctorVoiceCallerListVO;
+import com.fs.his.domain.FsDoctorVoiceCaller;
+import com.fs.his.mapper.FsDoctorVoiceCallerMapper;
+import com.fs.his.service.IFsDoctorVoiceCallerService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+/**
+ * 医生用户坐席Service业务层处理
+ * 
+ * @author fs
+ * @date 2025-12-03
+ */
+@Service
+public class FsDoctorVoiceCallerServiceImpl implements IFsDoctorVoiceCallerService {
+
+    @Autowired
+    private FsDoctorVoiceCallerMapper baseMapper;
+
+    /**
+     * 查询医生用户坐席
+     * 
+     * @param callerId 医生用户坐席主键
+     * @return 医生用户坐席
+     */
+    @Override
+    public FsDoctorVoiceCaller selectFsDoctorVoiceCallerByCallerId(Long callerId)
+    {
+        return baseMapper.selectFsDoctorVoiceCallerByCallerId(callerId);
+    }
+
+    /**
+     * 查询医生用户坐席列表
+     * 
+     * @param doctorVoiceCallerParam 医生用户坐席
+     * @return 医生用户坐席
+     */
+    @Override
+    public List<DoctorVoiceCallerListVO> selectFsDoctorVoiceCallerList(DoctorVoiceCallerParam doctorVoiceCallerParam)
+    {
+        return baseMapper.selectFsDoctorVoiceCallerList(doctorVoiceCallerParam);
+    }
+
+    /**
+     * 新增医生用户坐席
+     * 
+     * @param fsDoctorVoiceCaller 医生用户坐席
+     * @return 结果
+     */
+    @Override
+    public int insertFsDoctorVoiceCaller(FsDoctorVoiceCaller fsDoctorVoiceCaller)
+    {
+        return baseMapper.insertFsDoctorVoiceCaller(fsDoctorVoiceCaller);
+    }
+
+    /**
+     * 修改医生用户坐席
+     * 
+     * @param fsDoctorVoiceCaller 医生用户坐席
+     * @return 结果
+     */
+    @Override
+    public int updateFsDoctorVoiceCaller(FsDoctorVoiceCaller fsDoctorVoiceCaller)
+    {
+        return baseMapper.updateFsDoctorVoiceCaller(fsDoctorVoiceCaller);
+    }
+
+    /**
+     * 批量删除医生用户坐席
+     * 
+     * @param callerIds 需要删除的医生用户坐席主键
+     * @return 结果
+     */
+    @Override
+    public int deleteFsDoctorVoiceCallerByCallerIds(Long[] callerIds)
+    {
+        return baseMapper.deleteFsDoctorVoiceCallerByCallerIds(callerIds);
+    }
+
+    /**
+     * 删除医生用户坐席信息
+     * 
+     * @param callerId 医生用户坐席主键
+     * @return 结果
+     */
+    @Override
+    public int deleteFsDoctorVoiceCallerByCallerId(Long callerId)
+    {
+        return baseMapper.deleteFsDoctorVoiceCallerByCallerId(callerId);
+    }
+
+    @Override
+    public FsDoctorVoiceCaller selectFsDoctorVoiceCallerByDoctorId(Long doctorId) {
+        return baseMapper.selectFsDoctorVoiceCallerByDoctorId(doctorId);
+    }
+
+    @Override
+    public FsDoctorVoiceCaller selectFsDoctorVoiceCallerByDoctorIdOrCompanyId(Long companyId, Long doctorId) {
+        return baseMapper.selectFsDoctorVoiceCallerByDoctorIdOrCompanyId(companyId,doctorId);
+    }
+
+    @Override
+    public List<FsDoctorVoiceCaller> selectFsDoctorVoiceCallerByDoctorIds(String doctorIds) {
+        return baseMapper.selectFsDoctorVoiceCallerByDoctorIds(doctorIds);
+    }
+}

+ 2 - 0
fs-service/src/main/java/com/fs/voice/service/IVoiceService.java

@@ -21,4 +21,6 @@ public interface IVoiceService
     R voiceAppCall(Long companyId, Long customerId, Long userId, String mobile);
 
     R voiceAppCallOff(Long voiceId);
+
+    R manualDialingVoiceCall(Long companyId, String phoneNumber, Long userId);
 }

+ 121 - 0
fs-service/src/main/java/com/fs/voice/service/impl/VoiceServiceImpl.java

@@ -28,6 +28,7 @@ import com.fs.system.config.SystemVoiceConfig;
 import com.fs.system.service.ISysConfigService;
 import com.fs.voice.service.IVoiceService;
 import lombok.Synchronized;
+import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
@@ -37,6 +38,7 @@ import java.util.Date;
 import static com.fs.his.utils.PhoneUtil.decryptPhone;
 
 @Service
+@Slf4j
 public class VoiceServiceImpl implements IVoiceService
 {
     @Autowired
@@ -570,5 +572,124 @@ public class VoiceServiceImpl implements IVoiceService
         }
     }
 
+    @Override
+    public R manualDialingVoiceCall(Long companyId, String calleeNbr, Long userId) {
+        log.info("拨号手机号:::::{}",calleeNbr);
+
+        //查询主叫号是不是坐席 查询主叫号是否已过期
+        Company company=companyService.selectCompanyById(companyId);
+        if(company.getStatus()==0){
+            return R.error("公司已停用");
+        }
+        if(company.getVoiceApiId()==null){
+            return R.error("未配置外呼接口");
+        }
+        CompanyVoiceApi api=companyVoiceApiService.selectCompanyVoiceApiById(company.getVoiceApiId());
+        if(api==null){
+            return R.error("外呼接口不存在");
+        }
+        if(api.getStatus().equals(0)){
+            return R.error("外呼接口已禁用");
+        }
+        CompanyUser user=userService.selectCompanyUserById(userId);
+        CompanyVoiceCaller caller=callerService.selectCompanyVoiceCallerByUserId(companyId,userId);
+        CompanyVoice companyVoice=companyVoiceService.selectCompanyVoiceByCompanyId(user.getCompanyId());
+        if(caller==null){
+            return R.error("未绑定坐席");
+        }
+        if(companyVoice.getTimes()<=0){
+            return R.error("剩余时长不足,请购买套餐");
+        }
+        //黑名单处理
+        if(blacklistService.selectCompanyVoiceBlacklistByMobile(caller.getMobile())>0){
+            return R.error("主叫号码已被设置为黑名单");
+        }
+        if(blacklistService.selectCompanyVoiceBlacklistByMobile(calleeNbr)>0){
+            return R.error("被叫号码已被设置为黑名单");
+        }
+        //处理主叫和被叫限制
+        CompanyVoiceConfig companyVoiceConfig=companyVoiceConfigService.selectCompanyVoiceConfigByCompanyId(companyId);
+        if(companyVoiceConfig!=null){
+            SystemVoiceConfig callerConfig=JSONUtil.toBean(companyVoiceConfig.getCallerJson(), SystemVoiceConfig.class);
+            if(callerConfig.getCallerMinute()!=null&&callerConfig.getCallerMinute()>0){
+                if(logsService.selectCompanyVoiceLogsCountByCallerMobile("+86"+caller.getMobile(),1)>=callerConfig.getCallerMinute()){
+                    return R.error("主叫分钟限制");
+                }
+            }
+            if(callerConfig.getCallerHour()!=null&&callerConfig.getCallerHour()>0){
+                if(logsService.selectCompanyVoiceLogsCountByCallerMobile("+86"+caller.getMobile(),2)>=callerConfig.getCallerHour()){
+                    return R.error("主叫小时限制");
+                }
+            }
+            if(callerConfig.getCallerDay()!=null&&callerConfig.getCallerDay()>0){
+                if(logsService.selectCompanyVoiceLogsCountByCallerMobile("+86"+caller.getMobile(),3)>=callerConfig.getCallerDay()){
+                    return R.error("主叫天限制");
+                }
+            }
+            if(callerConfig.getCallerWeek()!=null&&callerConfig.getCallerWeek()>0){
+                if(logsService.selectCompanyVoiceLogsCountByCallerMobile("+86"+caller.getMobile(),4)>=callerConfig.getCallerWeek()){
+                    return R.error("主叫周限制");
+                }
+            }
+            if(callerConfig.getCallerMonth()!=null&&callerConfig.getCallerMonth()>0){
+
+                if(logsService.selectCompanyVoiceLogsCountByCallerMobile("+86"+caller.getMobile(),5)>=callerConfig.getCallerMonth()){
+                    return R.error("主叫月限制");
+                }
+            }
+            SystemVoiceConfig calleeConfig=JSONUtil.toBean(companyVoiceConfig.getCalleeJson(), SystemVoiceConfig.class);
+            if(calleeConfig.getCalleeMinute()!=null&&calleeConfig.getCalleeMinute()>0){
+                if(logsService.selectCompanyVoiceLogsCountByCalleeMobile("+86"+calleeNbr,1)>=calleeConfig.getCalleeMinute()){
+                    return R.error("被叫分钟限制");
+                }
+            }
+            if(calleeConfig.getCalleeHour()!=null&&calleeConfig.getCalleeHour()>0){
+                if(logsService.selectCompanyVoiceLogsCountByCalleeMobile("+86"+calleeNbr,2)>=calleeConfig.getCalleeHour()){
+                    return R.error("被叫小时限制");
+                }
+            }
+            if(calleeConfig.getCalleeDay()!=null&&calleeConfig.getCalleeDay()>0){
+                if(logsService.selectCompanyVoiceLogsCountByCalleeMobile("+86"+calleeNbr,3)>=calleeConfig.getCalleeDay()){
+                    return R.error("被叫天限制");
+                }
+            }
+            if(calleeConfig.getCalleeWeek()!=null&&calleeConfig.getCalleeWeek()>0){
+                if(logsService.selectCompanyVoiceLogsCountByCalleeMobile("+86"+calleeNbr,4)>=calleeConfig.getCalleeWeek()){
+                    return R.error("被叫周限制");
+                }
+            }
+            if(calleeConfig.getCalleeMonth()!=null&&calleeConfig.getCalleeMonth()>0){
+                if(logsService.selectCompanyVoiceLogsCountByCalleeMobile("+86"+calleeNbr,5)>=calleeConfig.getCalleeMonth()){
+                    return R.error("被叫月限制");
+                }
+            }
+        }
+        String orderSn =  OrderCodeUtils.getOrderSn();
+        if(StringUtils.isEmpty(orderSn)){
+            return R.error("订单生成失败,请重试");
+        }
+        //写入SESSION
+        CompanyVoiceLogs logs=new CompanyVoiceLogs();
+        logs.setCompanyId(companyId);
+        logs.setVoiceTitle(user.getNickName()+"呼叫:"+calleeNbr);
+        logs.setStartTime(new Date());
+        logs.setVoiceType(3);//定义其他类型 fs_user_id格式
+        logs.setCalleePhone(calleeNbr);
+        logs.setCallerPhone(caller.getMobile());
+        logs.setDisplayCalleeNumber(calleeNbr);
+        logs.setDisplayCallerNumber("");
+        logs.setRemark(user.getNickName()+"发起呼叫"+calleeNbr);
+        logs.setCompanyUserId(userId);
+//        logs.setCustomerId(fUserId);
+        logs.setApiId(api.getApiId());
+        logs.setSessionId(orderSn);
+        logs.setCallerNo(caller.getCallerNo());
+        logsService.insertCompanyVoiceLogs(logs);
+//        voiceMobile.setStatus(0);
+//        mobileService.updateCompanyVoiceMobile(voiceMobile);
+        String displayMobile=calleeNbr.replaceAll("(\\d{2})\\d*", "$1*********");
+        return R.ok().put("logs",logs).put("mobile",calleeNbr).put("displayMobile",displayMobile);
+    }
+
 
 }

+ 80 - 0
fs-service/src/main/resources/mapper/his/FsDoctorVoiceCallerMapper.xml

@@ -0,0 +1,80 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.fs.his.mapper.FsDoctorVoiceCallerMapper">
+
+    <resultMap type="FsDoctorVoiceCaller" id="FsDoctorVoiceCallerResult">
+        <result property="callerId"    column="caller_id"    />
+        <result property="companyId"    column="company_id"    />
+        <result property="doctorId"    column="doctor_id"    />
+        <result property="companyUserId"    column="company_user_id"    />
+        <result property="callerNo"    column="caller_no"    />
+        <result property="mobile"    column="mobile"    />
+        <result property="status"    column="status"    />
+        <result property="remark"    column="remark"    />
+        <result property="bindTime"    column="bind_time"    />
+        <result property="companyCallerId"    column="company_caller_id"    />
+    </resultMap>
+
+    <sql id="selectFsDoctorVoiceCallerVo">
+        select caller_id, company_id, doctor_id,company_user_id,caller_no, mobile, status, remark,bind_time,company_caller_id from fs_doctor_voice_caller
+    </sql>
+
+    <select id="selectFsDoctorVoiceCallerByCallerId" parameterType="Long" resultMap="FsDoctorVoiceCallerResult">
+        <include refid="selectFsDoctorVoiceCallerVo"/>
+        where caller_id = #{callerId}
+    </select>
+
+    <insert id="insertFsDoctorVoiceCaller" parameterType="FsDoctorVoiceCaller" useGeneratedKeys="true" keyProperty="callerId">
+        insert into fs_doctor_voice_caller
+        <trim prefix="(" suffix=")" suffixOverrides=",">
+            <if test="companyId != null">company_id,</if>
+            <if test="doctorId != null">doctor_id,</if>
+            <if test="companyUserId != null">company_user_id,</if>
+            <if test="callerNo != null">caller_no,</if>
+            <if test="mobile != null">mobile,</if>
+            <if test="status != null">status,</if>
+            <if test="remark != null">remark,</if>
+            <if test="bindTime != null">bind_time,</if>
+            <if test="companyCallerId != null">company_caller_id,</if>
+        </trim>
+        <trim prefix="values (" suffix=")" suffixOverrides=",">
+            <if test="companyId != null">#{companyId},</if>
+            <if test="doctorId != null">#{doctorId},</if>
+            <if test="companyUserId != null">#{companyUserId},</if>
+            <if test="callerNo != null">#{callerNo},</if>
+            <if test="mobile != null">#{mobile},</if>
+            <if test="status != null">#{status},</if>
+            <if test="remark != null">#{remark},</if>
+            <if test="bindTime != null">#{bindTime},</if>
+            <if test="companyCallerId != null">#{companyCallerId},</if>
+        </trim>
+    </insert>
+
+    <update id="updateFsDoctorVoiceCaller" parameterType="FsDoctorVoiceCaller">
+        update fs_doctor_voice_caller
+        <trim prefix="SET" suffixOverrides=",">
+            <if test="companyId != null">company_id = #{companyId},</if>
+            <if test="doctorId != null">doctor_id = #{doctorId},</if>
+            <if test="companyUserId != null">company_user_id = #{companyUserId},</if>
+            <if test="callerNo != null">caller_no = #{callerNo},</if>
+            <if test="mobile != null">mobile = #{mobile},</if>
+            <if test="status != null">status = #{status},</if>
+            <if test="remark != null">remark = #{remark},</if>
+            <if test="companyCallerId != null">company_caller_id = #{companyCallerId},</if>
+        </trim>
+        where caller_id = #{callerId}
+    </update>
+
+    <delete id="deleteFsDoctorVoiceCallerByCallerId" parameterType="Long">
+        delete from fs_doctor_voice_caller where caller_id = #{callerId}
+    </delete>
+
+    <delete id="deleteFsDoctorVoiceCallerByCallerIds" parameterType="String">
+        delete from fs_doctor_voice_caller where caller_id in
+        <foreach item="callerId" collection="array" open="(" separator="," close=")">
+            #{callerId}
+        </foreach>
+    </delete>
+</mapper>

+ 163 - 0
fs-service/src/main/resources/mapper/his/FsDoctorVoiceLogsMapper.xml

@@ -0,0 +1,163 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.fs.doctor.mapper.FsDoctorVoiceLogsMapper">
+    
+    <resultMap type="FsDoctorVoiceLogs" id="FsDoctorVoiceLogsResult">
+        <result property="voiceId"    column="voice_id"    />
+        <result property="companyId"    column="company_id"    />
+        <result property="voiceTitle"    column="voice_title"    />
+        <result property="voiceUrl"    column="voice_url"    />
+        <result property="startTime"    column="start_time"    />
+        <result property="finishTime"    column="finish_time"    />
+        <result property="voiceType"    column="voice_type"    />
+        <result property="remark"    column="remark"    />
+        <result property="callerPhone"    column="caller_phone"    />
+        <result property="calleePhone"    column="callee_phone"    />
+        <result property="times"    column="times"    />
+        <result property="billingTime"    column="billing_time"    />
+        <result property="displayCallerNumber"    column="display_caller_number"    />
+        <result property="displayCalleeNumber"    column="display_callee_number"    />
+        <result property="doctorId"    column="doctor_id"    />
+        <result property="status"    column="status"    />
+        <result property="sessionId"    column="session_id"    />
+        <result property="patientId"    column="patient_id"    />
+        <result property="apiId"    column="api_id"    />
+        <result property="callerNo"    column="caller_no"    />
+        <result property="patientName"    column="patient_name"    />
+        <result property="doctorName"    column="doctor_name"    />
+        <result property="companyName"    column="company_name"    />
+    </resultMap>
+
+    <sql id="selectFsDoctorVoiceLogsVo">
+        select voice_id, company_id, voice_title, voice_url, start_time, finish_time, voice_type, remark, caller_phone, callee_phone, times, billing_time,
+               display_caller_number, display_callee_number, doctor_id, status, session_id, patient_id, api_id, caller_no,patient_name,doctor_name,
+               company_name from fs_doctor_voice_logs
+    </sql>
+
+    <select id="selectFsDoctorVoiceLogsList" parameterType="FsDoctorVoiceLogs" resultMap="FsDoctorVoiceLogsResult">
+        <include refid="selectFsDoctorVoiceLogsVo"/>
+        <where>  
+            <if test="companyId != null "> and company_id = #{companyId}</if>
+            <if test="voiceTitle != null  and voiceTitle != ''"> and voice_title = #{voiceTitle}</if>
+            <if test="voiceUrl != null  and voiceUrl != ''"> and voice_url = #{voiceUrl}</if>
+            <if test="startTime != null "> and start_time = #{startTime}</if>
+            <if test="finishTime != null "> and finish_time = #{finishTime}</if>
+            <if test="voiceType != null "> and voice_type = #{voiceType}</if>
+            <if test="callerPhone != null  and callerPhone != ''"> and caller_phone = #{callerPhone}</if>
+            <if test="calleePhone != null  and calleePhone != ''"> and callee_phone = #{calleePhone}</if>
+            <if test="times != null "> and times = #{times}</if>
+            <if test="billingTime != null "> and billing_time = #{billingTime}</if>
+            <if test="displayCallerNumber != null  and displayCallerNumber != ''"> and display_caller_number = #{displayCallerNumber}</if>
+            <if test="displayCalleeNumber != null  and displayCalleeNumber != ''"> and display_callee_number = #{displayCalleeNumber}</if>
+            <if test="doctorId != null "> and doctor_id = #{doctorId}</if>
+            <if test="status != null "> and status = #{status}</if>
+            <if test="sessionId != null  and sessionId != ''"> and session_id = #{sessionId}</if>
+            <if test="patientId != null "> and patient_id = #{patientId}</if>
+            <if test="apiId != null "> and api_id = #{apiId}</if>
+            <if test="callerNo != null  and callerNo != ''"> and caller_no = #{callerNo}</if>
+            <if test="patientName != null  and patientName != ''"> and patient_name like '%${patientName}%'</if>
+            <if test="doctorName != null  and doctorName != ''"> and doctor_name like '%${doctorName}%'</if>
+            <if test="companyName != null  and companyName != ''"> and company_name like '%${companyName}%'</if>
+        </where>
+        order by voice_id desc
+    </select>
+    
+    <select id="selectFsDoctorVoiceLogsByVoiceId" parameterType="Long" resultMap="FsDoctorVoiceLogsResult">
+        <include refid="selectFsDoctorVoiceLogsVo"/>
+        where voice_id = #{voiceId}
+    </select>
+        
+    <insert id="insertFsDoctorVoiceLogs" parameterType="FsDoctorVoiceLogs" useGeneratedKeys="true" keyProperty="voiceId">
+        insert into fs_doctor_voice_logs
+        <trim prefix="(" suffix=")" suffixOverrides=",">
+            <if test="companyId != null">company_id,</if>
+            <if test="voiceTitle != null">voice_title,</if>
+            <if test="voiceUrl != null">voice_url,</if>
+            <if test="startTime != null">start_time,</if>
+            <if test="finishTime != null">finish_time,</if>
+            <if test="voiceType != null">voice_type,</if>
+            <if test="remark != null">remark,</if>
+            <if test="callerPhone != null">caller_phone,</if>
+            <if test="calleePhone != null">callee_phone,</if>
+            <if test="times != null">times,</if>
+            <if test="billingTime != null">billing_time,</if>
+            <if test="displayCallerNumber != null">display_caller_number,</if>
+            <if test="displayCalleeNumber != null">display_callee_number,</if>
+            <if test="doctorId != null">doctor_id,</if>
+            <if test="status != null">status,</if>
+            <if test="sessionId != null">session_id,</if>
+            <if test="patientId != null">patient_id,</if>
+            <if test="apiId != null">api_id,</if>
+            <if test="callerNo != null">caller_no,</if>
+            <if test="patientName != null">patient_name,</if>
+            <if test="doctorName != null">doctor_name,</if>
+            <if test="companyName != null">company_name,</if>
+         </trim>
+        <trim prefix="values (" suffix=")" suffixOverrides=",">
+            <if test="companyId != null">#{companyId},</if>
+            <if test="voiceTitle != null">#{voiceTitle},</if>
+            <if test="voiceUrl != null">#{voiceUrl},</if>
+            <if test="startTime != null">#{startTime},</if>
+            <if test="finishTime != null">#{finishTime},</if>
+            <if test="voiceType != null">#{voiceType},</if>
+            <if test="remark != null">#{remark},</if>
+            <if test="callerPhone != null">#{callerPhone},</if>
+            <if test="calleePhone != null">#{calleePhone},</if>
+            <if test="times != null">#{times},</if>
+            <if test="billingTime != null">#{billingTime},</if>
+            <if test="displayCallerNumber != null">#{displayCallerNumber},</if>
+            <if test="displayCalleeNumber != null">#{displayCalleeNumber},</if>
+            <if test="doctorId != null">#{doctorId},</if>
+            <if test="status != null">#{status},</if>
+            <if test="sessionId != null">#{sessionId},</if>
+            <if test="patientId != null">#{patientId},</if>
+            <if test="apiId != null">#{apiId},</if>
+            <if test="callerNo != null">#{callerNo},</if>
+            <if test="patientName != null">#{patientName},</if>
+            <if test="doctorName != null">#{doctorName},</if>
+            <if test="companyName != null">#{companyName},</if>
+         </trim>
+    </insert>
+
+    <update id="updateFsDoctorVoiceLogs" parameterType="FsDoctorVoiceLogs">
+        update fs_doctor_voice_logs
+        <trim prefix="SET" suffixOverrides=",">
+            <if test="companyId != null">company_id = #{companyId},</if>
+            <if test="voiceTitle != null">voice_title = #{voiceTitle},</if>
+            <if test="voiceUrl != null">voice_url = #{voiceUrl},</if>
+            <if test="startTime != null">start_time = #{startTime},</if>
+            <if test="finishTime != null">finish_time = #{finishTime},</if>
+            <if test="voiceType != null">voice_type = #{voiceType},</if>
+            <if test="remark != null">remark = #{remark},</if>
+            <if test="callerPhone != null">caller_phone = #{callerPhone},</if>
+            <if test="calleePhone != null">callee_phone = #{calleePhone},</if>
+            <if test="times != null">times = #{times},</if>
+            <if test="billingTime != null">billing_time = #{billingTime},</if>
+            <if test="displayCallerNumber != null">display_caller_number = #{displayCallerNumber},</if>
+            <if test="displayCalleeNumber != null">display_callee_number = #{displayCalleeNumber},</if>
+            <if test="doctorId != null">doctor_id = #{doctorId},</if>
+            <if test="status != null">status = #{status},</if>
+            <if test="sessionId != null">session_id = #{sessionId},</if>
+            <if test="patientId != null">patient_id = #{patientId},</if>
+            <if test="apiId != null">api_id = #{apiId},</if>
+            <if test="callerNo != null">caller_no = #{callerNo},</if>
+            <if test="patientName != null">patient_name = #{patientName},</if>
+            <if test="doctorName != null">doctor_name = #{doctorName},</if>
+            <if test="companyName != null">company_name = #{companyName},</if>
+        </trim>
+        where voice_id = #{voiceId}
+    </update>
+
+    <delete id="deleteFsDoctorVoiceLogsByVoiceId" parameterType="Long">
+        delete from fs_doctor_voice_logs where voice_id = #{voiceId}
+    </delete>
+
+    <delete id="deleteFsDoctorVoiceLogsByVoiceIds" parameterType="String">
+        delete from fs_doctor_voice_logs where voice_id in 
+        <foreach item="voiceId" collection="array" open="(" separator="," close=")">
+            #{voiceId}
+        </foreach>
+    </delete>
+</mapper>