From 4b221581b1d7b6c22e86af4e12c363ef482898c8 Mon Sep 17 00:00:00 2001
From: WXL (wul) <wl_5969728@163.com>
Date: 星期三, 20 八月 2025 17:37:38 +0800
Subject: [PATCH] 随访详情及控制台错误优化

---
 src/views/followvisit/record/detailpage/index.vue |  412 +++++++++++++++++++++++++++++++++++++++++++++++++++-------
 1 files changed, 357 insertions(+), 55 deletions(-)

diff --git a/src/views/followvisit/record/detailpage/index.vue b/src/views/followvisit/record/detailpage/index.vue
index dbb2ba3..0e292ce 100644
--- a/src/views/followvisit/record/detailpage/index.vue
+++ b/src/views/followvisit/record/detailpage/index.vue
@@ -215,7 +215,12 @@
     </div>
     <div class="Followuserinfos">
       <div>
-        <el-form ref="form" :model="form" label-width="120px">
+        <el-form
+          ref="userform"
+          :model="form"
+          :rules="userrules"
+          label-width="120px"
+        >
           <div class="headline">
             <div>浜哄伐澶勭悊</div>
             <el-row :gutter="20">
@@ -224,6 +229,13 @@
                   <el-input
                     placeholder="鑱旂郴鐢佃瘽缂哄け"
                     v-model="userform.telcode"
+                  >
+                    <el-button
+                      slot="append"
+                      icon="el-icon-phone"
+                      @click="handleCall(userform.telcode, 'tel')"
+                      :disabled="!isValidPhone(userform.telcode)"
+                    ></el-button
                   ></el-input> </el-form-item
               ></el-col>
               <el-col :span="8"
@@ -231,6 +243,13 @@
                   <el-input
                     placeholder="鑱旂郴浜虹數璇濈己澶�"
                     v-model="userform.relativetelcode"
+                  >
+                    <el-button
+                      slot="append"
+                      icon="el-icon-phone"
+                      @click="handleCall(userform.relativetelcode, 'relative')"
+                      :disabled="!isValidPhone(userform.relativetelcode)"
+                    ></el-button
                   ></el-input> </el-form-item
               ></el-col>
               <el-col :span="8"
@@ -241,13 +260,37 @@
                   ></el-input> </el-form-item
               ></el-col>
             </el-row>
+
             <div style="margin-left: 30px">
               <el-button type="primary" plain @click="Editsingletasksonyic('')"
                 >淇濆瓨鏈嶅姟</el-button
               >
             </div>
           </div>
+          <el-row :gutter="20" v-if="callStatus !== 'idle'">
+            <el-col :span="24">
+              <el-alert
+                :title="callStatusText"
+                :type="callStatusType"
+                :closable="false"
+                show-icon
+              />
+            </el-col>
+          </el-row>
 
+          <!-- 鎸傛柇鎸夐挳锛堜粎鍦ㄩ�氳瘽涓樉绀猴級 -->
+          <el-row :gutter="20" v-if="callStatus === 'connected'">
+            <el-col :span="24" style="text-align: center; margin-top: 10px">
+              <el-button
+                type="danger"
+                icon="el-icon-phone"
+                @click="endCurrentCall"
+                :loading="isEndingCall"
+              >
+                鎸傛柇鐢佃瘽
+              </el-button>
+            </el-col>
+          </el-row>
           <el-form-item label="闅忚璁板綍">
             <el-input type="textarea" v-model="form.remark"></el-input>
           </el-form-item>
@@ -352,6 +395,14 @@
           </el-collapse-item>
         </el-collapse>
       </div>
+    </div>
+    <div>
+      <h2>涓�閿懠鍙姛鑳�</h2>
+      <CallButton
+        ref="callButton"
+        :phoneNumber="currentPhoneNumber"
+        style="display: none"
+      />
     </div>
     <div>
       <el-tabs v-model="activeName" type="border-card">
@@ -536,7 +587,7 @@
               瀹屾暣璇煶锛�
               <mini-audio
                 :audio-source="
-                  voice ? voice : 'https://example.com/example.mp3'
+                  voice ? voice : '@assets/order/example.mp3'
                 "
               ></mini-audio>
             </div>
@@ -560,7 +611,7 @@
                         :audio-source="
                           item.questionvoice
                             ? item.questionvoice
-                            : 'https://example.com/example.mp3'
+                            : '@assets/order/example.mp3'
                         "
                       ></mini-audio>
                     </div>
@@ -625,60 +676,93 @@
         <div class="headline">涓婃闅忚</div>
         <el-divider></el-divider>
         <el-row>
-          <el-col>
-            <el-select
-              v-model="form.visitType"
-              multiple
-              filterable
-              allow-create
-              default-first-option
-              placeholder="璇烽�夋嫨鏂囩珷鏍囩"
-            >
-              <el-option
-                v-for="item in options"
-                :key="item.value"
-                :label="item.label"
-                :value="item.value"
+          <el-col :span="12">
+            <el-form-item label="闅忚鏂瑰紡">
+              <el-select
+                v-model="form.visitType2"
+                filterable
+                allow-create
+                default-first-option
+                disabled
+                placeholder="璇烽�夋嫨闅忚鏂瑰紡"
+                class="custom-disabled"
               >
-              </el-option>
-            </el-select>
+                <el-option
+                  v-for="item in options"
+                  :key="item.value"
+                  :label="item.label"
+                  :value="item.value"
+                >
+                </el-option>
+              </el-select>
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="闅忚鏃堕棿">
+              <el-date-picker
+                type="date"
+                disabled
+                placeholder="閫夋嫨鏃ユ湡"
+                :picker-options="pickerOptions"
+                align="right"
+                v-model="form.date2"
+                class="custom-disabled"
+              ></el-date-picker>
+            </el-form-item>
           </el-col>
         </el-row>
-        <el-form-item label="闅忚鏃堕棿" prop="date1">
-          <el-date-picker
-            type="date"
-            placeholder="閫夋嫨鏃ユ湡"
-            :picker-options="pickerOptions"
-            align="right"
-            v-model="form.date1"
-            style="width: 100%"
-          ></el-date-picker>
-        </el-form-item>
+
         <el-form-item label="闅忚璁板綍">
-          <el-input type="textarea" v-model="form.remark"></el-input>
+          <el-input
+            class="custom-disabled"
+            type="textarea"
+            disabled
+            v-model="form.remark2"
+          ></el-input>
         </el-form-item>
         <div class="headline">涓嬫闅忚</div>
         <el-divider></el-divider>
-
+        <el-row>
+          <el-col :span="12">
+            <el-form-item label="闅忚鏂瑰紡" prop="date1">
+              <el-select
+                v-model="form.visitType"
+                filterable
+                allow-create
+                default-first-option
+                @change="visitChange"
+                placeholder="璇烽�夋嫨闅忚鏂瑰紡(渚濆嚭闄㈡椂闂存妧璁$畻)"
+              >
+                <el-option
+                  v-for="item in options"
+                  :key="item.value"
+                  :label="item.label"
+                  :value="item.value"
+                >
+                </el-option>
+              </el-select>
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="闅忚鏃堕棿" prop="date1">
+              <el-date-picker
+                type="date"
+                placeholder="閫夋嫨鏃ユ湡"
+                :picker-options="pickerOptions"
+                align="right"
+                v-model="form.date1"
+                class="custom-disabled"
+              ></el-date-picker>
+            </el-form-item>
+          </el-col>
+        </el-row>
         <el-form-item label="闅忚鏂瑰紡" prop="resource">
           <el-radio-group v-model="form.resource">
             <el-radio label="1">鏈梾鍖洪殢璁�</el-radio>
             <el-radio label="2">闅忚涓績闅忚</el-radio>
           </el-radio-group>
         </el-form-item>
-        <!-- <el-form-item label="鍗冲埢鍙戦��">
-          <el-switch v-model="zcform.delivery"></el-switch>
-        </el-form-item> -->
-        <el-form-item label="闅忚鏃堕棿" prop="date1">
-          <el-date-picker
-            type="date"
-            placeholder="閫夋嫨鏃ユ湡"
-            :picker-options="pickerOptions"
-            align="right"
-            v-model="form.date1"
-            style="width: 100%"
-          ></el-date-picker>
-        </el-form-item>
+
         <el-form-item label="闅忚璁板綍">
           <el-input type="textarea" v-model="form.remark"></el-input>
         </el-form-item>
@@ -712,11 +796,34 @@
   alterpatient,
   listcontactinformation,
 } from "@/api/patient/homepage";
+import CallButton from "@/components/CallButton";
 export default {
+  components: {
+    CallButton,
+  },
+
   dicts: ["sys_normal_disable", "sys_user_sex", "sys_yujing", "sys_suggest"],
   data() {
+    const validatePhone = (rule, value, callback) => {
+      if (!value) {
+        return callback(new Error("璇疯緭鍏ヨ仈绯荤數璇�"));
+      }
+      setTimeout(() => {
+        if (!/^1[3-9]\d{9}$/.test(value)) {
+          callback(new Error("璇疯緭鍏ユ纭殑11浣嶆墜鏈哄彿鐮�"));
+        } else {
+          callback();
+        }
+      }, 300);
+    };
     return {
       userid: "",
+      currentPhoneNumber: "",
+      callType: "", // 鐢ㄤ簬鍖哄垎鏄摢涓數璇�
+      // 宸叉湁鏁版嵁...
+      callStatus: "idle", // idle, calling, connected, ended, failed
+      isEndingCall: false,
+      currentCall: null, // 褰撳墠閫氳瘽瀵硅薄
       input: "浠婂ぉ韬綋杩樹笉閿�",
       radio: "2",
       taskname: "",
@@ -734,6 +841,10 @@
           { required: true, message: "璇烽�夋嫨闅忚鏂瑰紡", trigger: "change" },
         ],
         date1: [{ required: true, message: "璇烽�夋嫨闅忚鏃堕棿", trigger: "blur" }],
+      },
+      userrules: {
+        telcode: [{ validator: validatePhone, trigger: "blur" }],
+        relativetelcode: [{ validator: validatePhone, trigger: "blur" }],
       },
       url: "http://9.208.2.190:8090/smartor/serviceExternal/query360PatInfo",
       postData: {
@@ -770,6 +881,10 @@
         },
       },
       pickerOptions: {
+        disabledDate(time) {
+          // 绂佺敤浠婂ぉ鍙婁箣鍓嶇殑鏃ユ湡
+          return time.getTime() < Date.now() - 24 * 60 * 60 * 1000;
+        },
         shortcuts: [
           {
             text: "涓冨ぉ鍚�",
@@ -861,7 +976,28 @@
       patid: null,
     };
   },
-
+  computed: {
+    callStatusText() {
+      const statusMap = {
+        idle: "鍑嗗鍛煎彨",
+        calling: `姝e湪鍛煎彨 ${this.currentPhoneNumber}...`,
+        connected: `宸叉帴閫� ${this.currentPhoneNumber}`,
+        ended: "閫氳瘽宸茬粨鏉�",
+        failed: "鍛煎彨澶辫触",
+      };
+      return statusMap[this.callStatus];
+    },
+    callStatusType() {
+      const typeMap = {
+        idle: "info",
+        calling: "warning",
+        connected: "success",
+        ended: "info",
+        failed: "error",
+      };
+      return typeMap[this.callStatus];
+    },
+  },
   created() {
     this.taskid = this.$route.query.taskid;
     this.id = this.$route.query.id;
@@ -951,6 +1087,37 @@
         }
       });
     },
+    // 鍐嶆闅忚鏃堕棿閫夊彇
+    visitChange(value) {
+      // 鏍规嵁閫夋嫨鐨勯殢璁挎柟寮忚缃椂闂�
+      const now = new Date();
+      if (value.includes("涓冨ぉ鍚�")) {
+        this.form.date1 = new Date(
+          Date.parse(this.form.endtime) + 3600 * 1000 * 24 * 7
+        );
+      } else if (value.includes("15澶╁悗")) {
+        this.form.date1 = new Date(
+          Date.parse(this.form.endtime) + 3600 * 1000 * 24 * 15
+        );
+      } else if (value.includes("涓�涓湀鍚�")) {
+        this.form.date1 = new Date(
+          Date.parse(this.form.endtime) + 3600 * 1000 * 24 * 30
+        );
+      } else if (value.includes("涓変釜鏈堝悗")) {
+        this.form.date1 = new Date(
+          Date.parse(this.form.endtime) + 3600 * 1000 * 24 * 90
+        );
+      } else if (value.includes("鍏釜鏈堝悗")) {
+        this.form.date1 = new Date(
+          Date.parse(this.form.endtime) + 3600 * 1000 * 24 * 180
+        );
+      } else if (value.includes("涓�骞村悗")) {
+        this.form.date1 = new Date(
+          Date.parse(this.form.endtime) + 3600 * 1000 * 24 * 365
+        );
+      }
+    },
+
     // 鑾峰彇璇煶鏁版嵁
     getPersonVoices(id) {
       let obj = {
@@ -1067,11 +1234,12 @@
             )
             .then(() => {
               document.querySelector("#app").scrollTo(0, 0);
+              this.formtidy();
               this.dialogFormVisible = true;
             })
             .catch(() => {
               if (this.form.serviceType == 13) {
-                if (this.visitCount) {
+                if (this.visitCount!=1) {
                   this.$router.push({
                     path: "/logisticsservice/zbAgain",
                   });
@@ -1080,10 +1248,10 @@
                     path: "/logisticsservice/record",
                   });
                 }
-              } else if (form.serviceType == 2) {
-                if (this.visitCount) {
+              } else if (this.form.serviceType == 2) {
+                if (this.visitCount!=1) {
                   this.$router.push({
-                    path: "/followvisit/again",
+                    path: "/logisticsservice/again",
                   });
                 } else {
                   this.$router.push({
@@ -1097,6 +1265,96 @@
           // 濡傛灉鏈変换浣曚竴涓紓姝ユ搷浣滃け璐ワ紝浼氳繘鍏ヨ繖閲�
           console.error("鍙戠敓閿欒锛�", error);
         });
+    },
+    // 楠岃瘉鐢佃瘽鍙风爜鏍煎紡骞惰繑鍥為敊璇俊鎭�
+    validatePhoneNumber(phone) {
+      if (!phone) {
+        return { isValid: false, message: "璇疯緭鍏ョ數璇濆彿鐮�" };
+      }
+
+      // 鎵嬫満鍙锋鍒�
+      const mobileRegex = /^1[3-9]\d{9}$/;
+
+      // 甯﹀尯鍙风殑鍥哄畾鐢佃瘽锛堝畬鏁存牸寮忥級
+      const landlineFullRegex = /^0\d{2,3}-?\d{7,8}$/;
+
+      // 涓嶅甫鍖哄彿鐨勫浐瀹氱數璇濓紙浠呮湰鍦板彿鐮侊級
+      const landlineLocalRegex = /^\d{7,8}$/;
+
+      if (mobileRegex.test(phone)) {
+        return { isValid: true, type: "mobile" };
+      } else if (landlineFullRegex.test(phone)) {
+        return { isValid: true, type: "landline" };
+      } else if (landlineLocalRegex.test(phone)) {
+        return {
+          isValid: false,
+          message: "鏈湴鍙风爜璇锋坊鍔犲尯鍙凤紙濡�028-1234567锛�",
+        };
+      } else {
+        return {
+          isValid: false,
+          message: "璇疯緭鍏ユ纭殑鐢佃瘽鍙风爜锛堟墜鏈哄彿鎴栧甫鍖哄彿鐨勫浐瀹氱數璇濓級",
+        };
+      }
+    },
+
+    // 浣跨敤绀轰緥
+    isValidPhone(phone) {
+      return this.validatePhoneNumber(phone).isValid;
+    },
+    handleCall(phone, type) {
+      if (!this.isValidPhone(phone)) {
+        this.$message.error("璇疯緭鍏ユ纭殑鎵嬫満鍙风爜");
+        return;
+      }
+
+      this.currentPhoneNumber = phone;
+      this.callType = type;
+      this.callStatus = "calling";
+
+      this.$nextTick(() => {
+        this.$refs.callButton.startCall();
+
+        // 鐩戝惉閫氳瘽鐘舵�佸彉鍖�
+        this.$refs.callButton.$on("call-status-change", (status) => {
+          this.handleCallStatusChange(status);
+        });
+      });
+    },
+
+    // 澶勭悊閫氳瘽鐘舵�佸彉鍖�
+    handleCallStatusChange(status) {
+      console.log(status, "status");
+
+      this.callStatus = status.type;
+
+      if (status.type === "connected") {
+        this.currentCall = {
+          phone: this.currentPhoneNumber,
+          type: this.callType,
+          startTime: new Date(),
+        };
+      } else if (status.type === "ended" || status.type === "failed") {
+        this.currentCall = null;
+      }
+
+      // 鍙互鏍规嵁鐘舵�佹墽琛屽叾浠栨搷浣�
+      if (status.type === "failed") {
+        this.$message.error(`鍛煎彨澶辫触: ${status.text}`);
+      }
+    },
+
+    // 缁撴潫褰撳墠閫氳瘽
+    endCurrentCall() {
+      if (!this.currentCall) return;
+
+      this.isEndingCall = true;
+      this.$refs.callButton.endCall();
+
+      // 3绉掑悗閲嶇疆鐘舵��
+      setTimeout(() => {
+        this.isEndingCall = false;
+      }, 3000);
     },
     yuyingetdetail() {
       this.tableDatatop.forEach((item, index) => {
@@ -1138,11 +1396,12 @@
             )
             .then(() => {
               document.querySelector("#app").scrollTo(0, 0);
+              this.formtidy();
               this.dialogFormVisible = true;
             })
             .catch(() => {
               if (this.form.serviceType == 13) {
-                if (this.visitCount) {
+                if (this.visitCount != 1) {
                   this.$router.push({
                     path: "/logisticsservice/zbAgain",
                   });
@@ -1152,7 +1411,7 @@
                   });
                 }
               } else if (form.serviceType == 2) {
-                if (this.visitCount) {
+                if (this.visitCount != 1) {
                   this.$router.push({
                     path: "/followvisit/again",
                   });
@@ -1166,7 +1425,12 @@
         }
       });
     },
-
+    // 鍐嶆闅忚鏁版嵁鏇存浛
+    formtidy() {
+      this.form.visitType2 = this.form.visitType;
+      this.form.date2 = this.form.longSendTime;
+      this.form.remark2 = this.form.remark;
+    },
     // 鑾峰彇鎮h�呰褰�
     getTaskservelist(id) {
       if (id) {
@@ -1183,11 +1447,12 @@
           this.form = res.rows[0].serviceSubtaskList.find(
             (item) => item.id == this.id
           );
+          console.log(this.form.serviceType, "serviceType");
+
           this.logsheetlist = res.rows[0].serviceSubtaskList;
           this.templateid = this.logsheetlist[0].templateid;
           const targetDate = new Date(this.form.longSendTime); // 鐩爣鏃ユ湡
           const now = new Date(); // 褰撳墠鏃堕棿
-          this.form.endtime = this.formatTime(this.form.endtime);
           if (now < targetDate && this.form.sendstate == 2) {
             this.$confirm("褰撳墠鏈嶅姟鏈埌鍙戦�佹椂闂磋璋ㄦ厧淇敼", "鎻愮ず", {
               confirmButtonText: "纭畾",
@@ -1263,6 +1528,7 @@
     sendAgain() {
       document.querySelector("#app").scrollTo(0, 0);
       // scrollTo(0, 0)
+      this.formtidy();
       this.dialogFormVisible = true;
     },
     // 鏌ョ湅璇︽儏
@@ -1331,6 +1597,10 @@
     setupsubtask() {
       this.$refs["zcform"].validate((valid) => {
         if (valid) {
+          if (this.form.date1 && new Date(this.form.date1) < new Date()) {
+            this.$message.error("闅忚鏃堕棿涓嶈兘灏忎簬褰撳墠鏃堕棿");
+            return false;
+          }
           this.form.remark =
             this.form.remark + "銆�" + this.getCurrentTime() + "銆�";
           let form = structuredClone(this.form);
@@ -1338,13 +1608,20 @@
           form.finishtime = "";
           if (form.resource) {
             if (form.resource == 2) {
-              form.serviceType = 13;
+              form.visitDeptCode = localStorage.getItem("deptCode");
+              form.visitDeptName = "闅忚涓績";
+            } else {
+              form.visitDeptCode = form.deptcode;
+              form.visitDeptName = form.deptname;
             }
           } else {
             this.$modal.msgError("鏈�夋嫨闅忚鏂瑰紡");
+            return;
           }
           // form.id = null;
           form.sendstate = 2;
+          console.log(form.serviceType, "form.serviceType");
+
           addserviceSubtask(form).then((res) => {
             if (res.code == 200) {
               this.$modal.msgSuccess("鍒涘缓鎴愬姛");
@@ -1354,7 +1631,7 @@
                 });
               } else if (form.serviceType == 2) {
                 this.$router.push({
-                  path: "/followvisit/again",
+                  path: "/logisticsservice/again",
                 });
               }
             } else {
@@ -1558,8 +1835,33 @@
   background-color: #f57676;
   border-color: #f57676;
 }
+.el-icon-phone {
+  transition: all 0.3s;
+}
+.el-button[disabled] .el-icon-phone {
+  color: #c0c4cc;
+}
+.el-button:not([disabled]) .el-icon-phone {
+  color: #409eff;
+}
+.el-button:not([disabled]):hover .el-icon-phone {
+  color: #66b1ff;
+  transform: scale(1.1);
+}
 .mulsz {
   font-size: 25px;
   margin-top: 20px;
 }
+.el-input.is-disabled .el-input__inner {
+  background-color: #fff; /* 鑳屾櫙棰滆壊 */
+  border-color: #dcdfe6; /* 杈规棰滆壊 */
+  color: #080808 !important; /* 鏂囧瓧棰滆壊 */
+  cursor: not-allowed; /* 榧犳爣鏍峰紡 */
+}
+.el-textarea.is-disabled .el-textarea__inner {
+  background-color: #fff; /* 鑳屾櫙棰滆壊 */
+  border-color: #dcdfe6; /* 杈规棰滆壊 */
+  color: #080808 !important; /* 鏂囧瓧棰滆壊 */
+  cursor: not-allowed; /* 榧犳爣鏍峰紡 */
+}
 </style>

--
Gitblit v1.9.3