From dac4393e8af2646f544f6e1ca24dab11b40c8492 Mon Sep 17 00:00:00 2001
From: WXL (wul) <wl_5969728@163.com>
Date: 星期二, 07 四月 2026 15:16:40 +0800
Subject: [PATCH] 测试完成

---
 src/views/index.vue                                                            |   44 
 vue.config.js                                                                  |    8 
 src/components/Assistant/index.vue                                             | 1132 
 src/views/followvisit/zbAgain/index.vue                                        |   21 
 src/views/repositoryai/templateku/configurat/index.vue                         |   17 
 src/api/AiCentre/Qtemplate.js                                                  |   16 
 src/views/followvisit/record/TracingInfo/index.vue                             | 2971 ++
 src/components/SortCheckbox/index.vue                                          |   73 
 src/views/patient/subsequent/index.vue                                         |   12 
 src/views/Satisfaction/configurationmyd/components/DetailsAnomaly.vue          |  923 
 src/views/followvisit/zysatisfaction/index.vue                                 |   13 
 public/jssip-3.10.0.js                                                         | 28403 +++++++++++++++++++++++++++
 src/views/Satisfaction/sfstatistics/components/SatisfactionStatistics.vue      | 1809 +
 src/views/Satisfaction/sfstatistics/components/FollowupStatistics.vue          | 1030 
 src/views/patient/patient/behospitalized.vue                                   |  725 
 src/components/CallButton/index.vue                                            |   62 
 src/views/Satisfaction/configurationmyd/index.vue                              | 2376 ++
 src/store/getters.js                                                           |    1 
 src/views/followvisit/discharge/outpatientService.vue                          |   21 
 src/views/patient/propaganda/Missioncreation.vue                               |  538 
 src/api/AiCentre/questionnaire.js                                              |    9 
 src/views/followvisit/technology/index.vue                                     |   12 
 src/views/patient/physical/index.vue                                           |   12 
 src/api/login.js                                                               |    3 
 src/store/modules/user.js                                                      |   58 
 src/api/AiCentre/SingleTask.js                                                 |   16 
 src/views/followvisit/Tracking/index.vue                                       | 1793 +
 src/views/Satisfaction/configurationmyd/batch.vue                              |  922 
 src/views/followvisit/record/detailpage/index copy.vue                         | 3703 +++
 src/router/index.js                                                            |  237 
 src/views/followvisit/OutpatientAgain/index.vue                                |   97 
 src/views/followvisit/discharge/js/prototype.js                                |    2 
 src/main.js                                                                    |   11 
 src/views/sfstatistics/percentage/index.vue                                    | 1140 +
 src/views/Satisfaction/particulars/index.vue                                   |  889 
 src/views/Satisfaction/sfstatistics/components/components/TopicDialog.vue      |  208 
 src/views/patient/patient/hospital.vue                                         |  669 
 src/views/patient/patient/AwaitingAdmission.vue                                |  224 
 src/views/Satisfaction/sfstatistics/index.vue                                  |   63 
 src/views/Satisfaction/configurationmyd/dispose.vue                            |  980 
 src/views/Satisfaction/sfstatistics/components/components/SeedetailsDialog.vue |  401 
 src/views/followvisit/outpatient/index.vue                                     |   12 
 src/api/AiCentre/phoneCall.js                                                  |    2 
 src/layout/components/Navbar.vue                                               |  132 
 src/views/sfstatistics/ProblemStatistics/index.vue                             |  536 
 src/views/followvisit/satisfaction/index.vue                                   |   25 
 src/views/followvisit/Continue/ContinueFordetails.vue                          | 2389 ++
 src/views/login-sy.vue                                                         |  322 
 src/views/Satisfaction/sfstatistics/components/visitStatistics.vue             | 1030 
 src/views/patient/propaganda/QuestionnaireTask.vue                             |  128 
 src/views/followvisit/mzsatisfaction/index.vue                                 |   13 
 src/views/patient/propaganda/index.vue                                         |   12 
 src/views/followvisit/record/detailpage/index.vue                              | 1423 +
 src/views/knowledge/questionbank/particulars/index.vue                         |  162 
 src/api/AiCentre/Followup.js                                                   |    8 
 src/views/outsideChainwtnew.vue                                                |    7 
 src/views/Satisfaction/sfstatistics/IndicatorStatistics.vue                    |   66 
 src/views/followvisit/complaint/index.vue                                      |   13 
 src/api/smartor/patouthosp.js                                                  |    8 
 src/api/system/user.js                                                         |   31 
 src/views/followvisit/SpecificDisease/index.vue                                |   12 
 src/views/followvisit/again/index.vue                                          |   55 
 src/views/patient/patient/indexls.vue                                          |    6 
 src/utils/sipService.js                                                        |  253 
 src/views/sfstatistics/percentage/satisfaction.vue                             |  408 
 src/store/modules/permission.js                                                |  194 
 src/views/patient/questionnaire/index.vue                                      |   12 
 public/demotel.html                                                            |  203 
 src/views/followvisit/record/index.vue                                         |   90 
 sltd.zip                                                                       |    0 
 src/views/followvisit/Continue/index.vue                                       | 2103 ++
 src/utils/request.js                                                           |    4 
 /dev/null                                                                      |    0 
 src/views/system/user/index.vue                                                |    4 
 src/views/followvisit/record/physical/index.vue                                |    6 
 src/views/login.vue                                                            |    6 
 src/views/followvisit/HistoricalFollow/index.vue                               | 1327 +
 src/components/Regular/index.vue                                               |   22 
 src/views/patient/shadow/index.vue                                             |   12 
 package.json                                                                   |    7 
 src/api/AiCentre/EChartsdata.js                                                |   12 
 src/components/AskRegular/index.vue                                            |   16 
 src/App.vue                                                                    |   29 
 src/views/patient/propaganda/particty.vue                                      |   48 
 src/plugins/auth.js                                                            |   53 
 src/views/followvisit/discharge/index.vue                                      |  189 
 86 files changed, 61,132 insertions(+), 1,902 deletions(-)

diff --git a/SLTD-WL.zip b/SLTD-WL.zip
deleted file mode 100644
index 3ef20a5..0000000
--- a/SLTD-WL.zip
+++ /dev/null
Binary files differ
diff --git a/dist.zip b/dist.zip
deleted file mode 100644
index 5db808c..0000000
--- a/dist.zip
+++ /dev/null
Binary files differ
diff --git a/package.json b/package.json
index 291269c..7b26edc 100644
--- a/package.json
+++ b/package.json
@@ -1,7 +1,7 @@
 {
   "name": "ruoyi",
   "version": "3.8.5",
-  "description": "鏅畞浜烘皯鍖婚櫌鏅烘収闅忚骞冲彴",
+  "description": "涓芥按浜烘皯鍖婚櫌鏅烘収闅忚骞冲彴",
   "author": "鏉柊",
   "license": "MIT",
   "scripts": {
@@ -52,6 +52,7 @@
     "dayjs": "^1.11.7",
     "echarts": "^5.4.2",
     "element-ui": "^2.15.4",
+    "exceljs": "^4.4.0",
     "file-saver": "^2.0.5",
     "fuse.js": "6.4.3",
     "highlight.js": "9.18.5",
@@ -81,11 +82,13 @@
     "vue-count-to": "1.0.13",
     "vue-cropper": "0.5.5",
     "vue-meta": "2.4.0",
+    "vue-print-nb": "^1.7.5",
     "vue-quill-editor": "^3.0.6",
     "vue-router": "3.4.9",
     "vuedraggable": "^2.24.3",
     "vuex": "3.6.0",
-    "xlsx": "^0.18.5"
+    "xlsx": "^0.18.5",
+    "xlsx-js-style": "^1.2.0"
   },
   "devDependencies": {
     "@vue/cli-plugin-babel": "4.4.6",
diff --git a/public/demotel.html b/public/demotel.html
new file mode 100644
index 0000000..4a748ea
--- /dev/null
+++ b/public/demotel.html
@@ -0,0 +1,203 @@
+锘�<!DOCTYPE html>
+<html>
+<head>
+    <meta charset="utf-8" />
+    <title>SIP鐢佃瘽Demo</title>
+    <meta http-equiv="Pragma" content="no-cache">
+    <meta http-equiv="Expires" content="-1">
+    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+    <meta http-equiv="cache-control" content="no-store">
+    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
+    <script language="javascript" type="text/javascript" src="./jssip-3.10.0.js"></script>
+</head>
+<body style="background-color:darkgray;">
+    
+    
+
+    <table border="1" cellspacing="0" bordercolor="gray" style="width:auto;">
+        <tr>
+            <td style="text-align:center;width:120px;">
+                <span> 鏈嶅姟鍣ㄥ湴鍧�:</span>
+            </td>
+            <td style="text-align: center; width: 250px;">
+                <input id="tbServer" type="text" style="width:200px;text-align:left;" value="192.168.1.96" />
+            </td>
+        </tr>
+        <tr>
+            <td style="text-align:center;width:120px;">
+                <span> 鍒嗘満鍙�:</span>
+            </td>
+            <td style="text-align: center; width: 250px;">
+                <input id="tbExtension" type="text" style="width:200px;text-align:left;" value="8005" />
+            </td>
+        </tr>
+        <tr>
+            <td style="text-align:center;width:120px;">
+                <span> 瀵嗙爜:</span>
+            </td>
+            <td style="text-align: center; width: 250px;">
+                <input id="tbPassword" type="text" style="width:200px;text-align:left;" value="8005" />
+            </td>
+        </tr>
+        <tr>
+            <td style="text-align:center;width:120px;" colspan="2">
+                <button onclick="f_register()">娉ㄥ唽</button>
+            </td>            
+        </tr>
+        <tr>
+            <td style="text-align:center;width:120px;">
+                <span> 鍛煎彨鍙风爜:</span>
+            </td>
+            <td style="text-align: center; width: 250px;">
+                <input id="tbPhoneNo" type="text" style="width:200px;text-align:left;" value="013958077789" />
+            </td>
+        </tr>
+        <tr>
+            <td style="text-align:center;width:120px;" colspan="2">
+                <button onclick="f_makecall()">杞鎷�</button>            
+                <button onclick="f_hangup()">鎸傛柇</button>
+            </td>
+        </tr>
+    </table>
+
+
+    <script type="text/javascript">
+        var cur_session = undefined;
+        var ua = null;
+
+        String.prototype.Right = function (i) {
+            return this.slice(this.length - i, this.length);
+        };
+        Date.prototype.Format = function (fmt) { //author: meizz
+            var o = {
+                "M+": this.getMonth() + 1, //鏈堜唤
+                "d+": this.getDate(), //鏃�
+                "h+": this.getHours(), //灏忔椂
+                "m+": this.getMinutes(), //鍒�
+                "s+": this.getSeconds(), //绉�
+                "q+": Math.floor((this.getMonth() + 3) / 3), //瀛e害
+                "S": ('00' + this.getMilliseconds()).Right(3)    //姣
+            };
+            if (/(y+)/.test(fmt)) fmt = fmt.replace(RegExp.$1, (this.getFullYear() + "").substr(4 - RegExp.$1.length));
+            for (var k in o)
+                if (new RegExp("(" + k + ")").test(fmt)) fmt = fmt.replace(RegExp.$1, (RegExp.$1.length == 1) ? (o[k]) : (("00" + o[k]).substr(("" + o[k]).length)));
+            return fmt;
+        };
+
+        function logger_info(message, ...optionalParams) {
+            console.log("[" + new Date().Format("yyyy-MM-dd hh:mm:ss.S") + "]" + message, optionalParams);
+        }
+
+        function f_register() {
+
+            var server = document.getElementById('tbServer').value;
+            var username = document.getElementById('tbExtension').value;
+            var passwd = document.getElementById('tbPassword').value;
+
+            var uristr = 'sip:' + username;
+            if (uristr.indexOf('@') < 1)
+                uristr = uristr + '@' + server;
+            //
+            logger_info(`寮�濮嬫敞鍐屽埌鏈嶅姟鍣�:${server},鍒嗘満鍙�:${username}...`);
+            var socket = new JsSIP.WebSocketInterface('wss://' + server +':7443');
+            var configuration = {
+                sockets: [socket],
+                uri: uristr,
+                password: passwd,
+                display_name: username,
+                iceServers: [
+                    { urls: '' }
+                ]
+            };
+
+            ua = new JsSIP.UA(configuration);
+
+            ua.on('registered', function (e) { logger_info("娉ㄥ唽鎴愬姛銆�", e); });
+            ua.on('unregistered', function (e) { logger_info('鍙栨秷娉ㄥ唽銆�', e); });
+            ua.on('registrationFailed', function (e) { logger_info('娉ㄥ唽澶辫触鐨勩��', e); });
+            ua.on('newRTCSession', function (e) {
+                logger_info('newRTCSession', e);
+                //
+                cur_session = e.session;
+                cur_session.on("accepted", function (e) { logger_info("鍛煎彨宸叉帴閫氥��", e); });
+                cur_session.on("ended", function (e) { logger_info("鍛煎彨缁撴潫銆�", e); });
+
+                cur_session.oniceconnectionstatechange = function () {
+                    if (cur_session.connection.iceConnectionState === 'completed') {
+                        // 鑾峰彇鏈湴SDP
+                        const localSdp = cur_session.connection.localDescription;
+
+                        // 淇敼SDP锛堣繖閲屼互淇敼闊抽缂栬В鐮佸櫒浼樺厛绾т负渚嬶級
+                        const sdp = localSdp.sdp;
+                        const modifiedSdp = sdp.replace(/m=audio (\d+) RTP\/AVP (\d+) (.*)/g, (match, port, payloadTypes, formats) => {
+                            // 鍋囪鎴戜滑鎯冲皢PCMU缂栬В鐮佸櫒鐨勪紭鍏堢骇鎻愰珮
+                            const preferredPayloadType = '0'; // PCMU鐨刾ayload type
+                            const preferredFormat = formats.split(' ').find(format => format.startsWith(preferredPayloadType));
+                            if (preferredFormat) {
+                                const newFormats = formats.split(' ').filter(format => format !== preferredFormat).concat(preferredFormat);
+                                return `m=audio ${port} RTP/AVP ${newFormats.join(' ')}`;
+                            }
+                            return match;
+                        });
+
+                        // 鍒涘缓鏂扮殑RTCSessionDescription瀵硅薄
+                        const newDescription = new RTCSessionDescription({
+                            type: localSdp.type,
+                            sdp: modifiedSdp
+                        });
+
+                        // 璁剧疆淇敼鍚庣殑SDP
+                        cur_session.connection.setLocalDescription(newDescription).catch(error => {
+                            logger_info('Failed to set local description:', error);
+                        });
+                    }
+                }
+                //
+                if (e.originator == "remote")
+                    e.session.answer();
+            });
+            ua.start();
+        }
+
+        function f_hangup() {
+            if (cur_session != undefined) {
+                cur_session.terminate();
+                cur_session = undefined;
+            }
+        }
+
+        function f_makecall() {
+            if (ua == undefined)
+                return;
+            //
+            var eventHandlers = {
+                'progress': function (e) {
+                    logger_info('call is in progress', e);
+                },
+                'failed': function (e) {
+                    logger_info('call failed with cause: ', e);
+                },
+                'ended': function (e) {
+                    logger_info('鍛煎彨缁撴潫锛屾寕鏈哄師鍥�: ', e);
+                },
+                'confirmed': function (e) {
+                    logger_info('call confirmed', e);
+                }
+            };
+
+            var options = {
+                'eventHandlers': eventHandlers,
+                'mediaConstraints': { 'audio': true, 'video': false },
+                sessionTimersExpires: 1800
+            };
+
+            var server = document.getElementById('tbServer').value;
+            var phone = document.getElementById('tbPhoneNo').value;
+            logger_info("寮�濮嬪懠鍙彿鐮侊細", phone);
+            cur_session = ua.call('sip:' + phone + '@' + server, options);
+
+        }
+
+    </script>
+</body>
+</html>
diff --git a/public/jssip-3.10.0.js b/public/jssip-3.10.0.js
new file mode 100644
index 0000000..743304a
--- /dev/null
+++ b/public/jssip-3.10.0.js
@@ -0,0 +1,28403 @@
+/*
+ * JsSIP v3.10.0
+ * the Javascript SIP library
+ * Copyright: 2012-2022 
+ * Homepage: https://jssip.net
+ * License: MIT
+ */
+
+(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.JsSIP = f()}})(function(){var define,module,exports;return (function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i<t.length;i++)o(t[i]);return o}return r})()({1:[function(require,module,exports){
+"use strict";
+
+function _createForOfIteratorHelper(o, allowArrayLike) { var it; if (typeof Symbol === "undefined" || o[Symbol.iterator] == null) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = o[Symbol.iterator](); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it["return"] != null) it["return"](); } finally { if (didErr) throw err; } } }; }
+
+function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
+
+function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; }
+
+var Utils = require('./Utils');
+
+var JsSIP_C = require('./Constants');
+
+var Grammar = require('./Grammar');
+
+var URI = require('./URI');
+
+var Socket = require('./Socket');
+
+var Exceptions = require('./Exceptions'); // Default settings.
+
+
+exports.settings = {
+  // SIP authentication.
+  authorization_user: null,
+  password: null,
+  realm: null,
+  ha1: null,
+  authorization_jwt: null,
+  // SIP account.
+  display_name: null,
+  uri: null,
+  contact_uri: null,
+  // SIP instance id (GRUU).
+  instance_id: null,
+  // Preloaded SIP Route header field.
+  use_preloaded_route: false,
+  // Session parameters.
+  session_timers: true,
+  session_timers_refresh_method: JsSIP_C.UPDATE,
+  session_timers_force_refresher: false,
+  no_answer_timeout: 60,
+  // Registration parameters.
+  register: true,
+  register_expires: 600,
+  registrar_server: null,
+  // Connection options.
+  sockets: null,
+  connection_recovery_max_interval: JsSIP_C.CONNECTION_RECOVERY_MAX_INTERVAL,
+  connection_recovery_min_interval: JsSIP_C.CONNECTION_RECOVERY_MIN_INTERVAL,
+  // Global extra headers, to be added to every request and response
+  extra_headers: null,
+
+  /*
+   * Host address.
+   * Value to be set in Via sent_by and host part of Contact FQDN.
+  */
+  via_host: "".concat(Utils.createRandomToken(12), ".invalid")
+}; // Configuration checks.
+
+var checks = {
+  mandatory: {
+    sockets: function sockets(_sockets2) {
+      /* Allow defining sockets parameter as:
+       *  Socket: socket
+       *  Array of Socket: [socket1, socket2]
+       *  Array of Objects: [{socket: socket1, weight:1}, {socket: Socket2, weight:0}]
+       *  Array of Objects and Socket: [{socket: socket1}, socket2]
+       */
+      var _sockets = [];
+
+      if (Socket.isSocket(_sockets2)) {
+        _sockets.push({
+          socket: _sockets2
+        });
+      } else if (Array.isArray(_sockets2) && _sockets2.length) {
+        var _iterator = _createForOfIteratorHelper(_sockets2),
+            _step;
+
+        try {
+          for (_iterator.s(); !(_step = _iterator.n()).done;) {
+            var socket = _step.value;
+
+            if (Object.prototype.hasOwnProperty.call(socket, 'socket') && Socket.isSocket(socket.socket)) {
+              _sockets.push(socket);
+            } else if (Socket.isSocket(socket)) {
+              _sockets.push({
+                socket: socket
+              });
+            }
+          }
+        } catch (err) {
+          _iterator.e(err);
+        } finally {
+          _iterator.f();
+        }
+      } else {
+        return;
+      }
+
+      return _sockets;
+    },
+    uri: function uri(_uri) {
+      if (!/^sip:/i.test(_uri)) {
+        _uri = "".concat(JsSIP_C.SIP, ":").concat(_uri);
+      }
+
+      var parsed = URI.parse(_uri);
+
+      if (!parsed) {
+        return;
+      } else if (!parsed.user) {
+        return;
+      } else {
+        return parsed;
+      }
+    }
+  },
+  optional: {
+    authorization_user: function authorization_user(_authorization_user) {
+      if (Grammar.parse("\"".concat(_authorization_user, "\""), 'quoted_string') === -1) {
+        return;
+      } else {
+        return _authorization_user;
+      }
+    },
+    authorization_jwt: function authorization_jwt(_authorization_jwt) {
+      if (typeof _authorization_jwt === 'string') {
+        return _authorization_jwt;
+      }
+    },
+    user_agent: function user_agent(_user_agent) {
+      if (typeof _user_agent === 'string') {
+        return _user_agent;
+      }
+    },
+    connection_recovery_max_interval: function connection_recovery_max_interval(_connection_recovery_max_interval) {
+      if (Utils.isDecimal(_connection_recovery_max_interval)) {
+        var value = Number(_connection_recovery_max_interval);
+
+        if (value > 0) {
+          return value;
+        }
+      }
+    },
+    connection_recovery_min_interval: function connection_recovery_min_interval(_connection_recovery_min_interval) {
+      if (Utils.isDecimal(_connection_recovery_min_interval)) {
+        var value = Number(_connection_recovery_min_interval);
+
+        if (value > 0) {
+          return value;
+        }
+      }
+    },
+    contact_uri: function contact_uri(_contact_uri) {
+      if (typeof _contact_uri === 'string') {
+        var uri = Grammar.parse(_contact_uri, 'SIP_URI');
+
+        if (uri !== -1) {
+          return uri;
+        }
+      }
+    },
+    display_name: function display_name(_display_name) {
+      return _display_name;
+    },
+    instance_id: function instance_id(_instance_id) {
+      if (/^uuid:/i.test(_instance_id)) {
+        _instance_id = _instance_id.substr(5);
+      }
+
+      if (Grammar.parse(_instance_id, 'uuid') === -1) {
+        return;
+      } else {
+        return _instance_id;
+      }
+    },
+    no_answer_timeout: function no_answer_timeout(_no_answer_timeout) {
+      if (Utils.isDecimal(_no_answer_timeout)) {
+        var value = Number(_no_answer_timeout);
+
+        if (value > 0) {
+          return value;
+        }
+      }
+    },
+    session_timers: function session_timers(_session_timers) {
+      if (typeof _session_timers === 'boolean') {
+        return _session_timers;
+      }
+    },
+    session_timers_refresh_method: function session_timers_refresh_method(method) {
+      if (typeof method === 'string') {
+        method = method.toUpperCase();
+
+        if (method === JsSIP_C.INVITE || method === JsSIP_C.UPDATE) {
+          return method;
+        }
+      }
+    },
+    session_timers_force_refresher: function session_timers_force_refresher(_session_timers_force_refresher) {
+      if (typeof _session_timers_force_refresher === 'boolean') {
+        return _session_timers_force_refresher;
+      }
+    },
+    password: function password(_password) {
+      return String(_password);
+    },
+    realm: function realm(_realm) {
+      return String(_realm);
+    },
+    ha1: function ha1(_ha) {
+      return String(_ha);
+    },
+    register: function register(_register) {
+      if (typeof _register === 'boolean') {
+        return _register;
+      }
+    },
+    register_expires: function register_expires(_register_expires) {
+      if (Utils.isDecimal(_register_expires)) {
+        var value = Number(_register_expires);
+
+        if (value > 0) {
+          return value;
+        }
+      }
+    },
+    registrar_server: function registrar_server(_registrar_server) {
+      if (!/^sip:/i.test(_registrar_server)) {
+        _registrar_server = "".concat(JsSIP_C.SIP, ":").concat(_registrar_server);
+      }
+
+      var parsed = URI.parse(_registrar_server);
+
+      if (!parsed) {
+        return;
+      } else if (parsed.user) {
+        return;
+      } else {
+        return parsed;
+      }
+    },
+    use_preloaded_route: function use_preloaded_route(_use_preloaded_route) {
+      if (typeof _use_preloaded_route === 'boolean') {
+        return _use_preloaded_route;
+      }
+    },
+    extra_headers: function extra_headers(_extra_headers) {
+      var _extraHeaders = [];
+
+      if (Array.isArray(_extra_headers) && _extra_headers.length) {
+        var _iterator2 = _createForOfIteratorHelper(_extra_headers),
+            _step2;
+
+        try {
+          for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
+            var header = _step2.value;
+
+            if (typeof header === 'string') {
+              _extraHeaders.push(header);
+            }
+          }
+        } catch (err) {
+          _iterator2.e(err);
+        } finally {
+          _iterator2.f();
+        }
+      } else {
+        return;
+      }
+
+      return _extraHeaders;
+    }
+  }
+};
+
+exports.load = function (dst, src) {
+  // Check Mandatory parameters.
+  for (var parameter in checks.mandatory) {
+    if (!src.hasOwnProperty(parameter)) {
+      throw new Exceptions.ConfigurationError(parameter);
+    } else {
+      var value = src[parameter];
+      var checked_value = checks.mandatory[parameter](value);
+
+      if (checked_value !== undefined) {
+        dst[parameter] = checked_value;
+      } else {
+        throw new Exceptions.ConfigurationError(parameter, value);
+      }
+    }
+  } // Check Optional parameters.
+
+
+  for (var _parameter in checks.optional) {
+    if (src.hasOwnProperty(_parameter)) {
+      var _value = src[_parameter];
+      /* If the parameter value is null, empty string, undefined, empty array
+       * or it's a number with NaN value, then apply its default value.
+       */
+
+      if (Utils.isEmpty(_value)) {
+        continue;
+      }
+
+      var _checked_value = checks.optional[_parameter](_value);
+
+      if (_checked_value !== undefined) {
+        dst[_parameter] = _checked_value;
+      } else {
+        throw new Exceptions.ConfigurationError(_parameter, _value);
+      }
+    }
+  }
+};
+},{"./Constants":2,"./Exceptions":6,"./Grammar":7,"./Socket":22,"./URI":27,"./Utils":28}],2:[function(require,module,exports){
+"use strict";
+
+var pkg = require('../package.json');
+
+module.exports = {
+  USER_AGENT: "".concat(pkg.title, " ").concat(pkg.version),
+  // SIP scheme.
+  SIP: 'sip',
+  SIPS: 'sips',
+  // End and Failure causes.
+  causes: {
+    // Generic error causes.
+    CONNECTION_ERROR: 'Connection Error',
+    REQUEST_TIMEOUT: 'Request Timeout',
+    SIP_FAILURE_CODE: 'SIP Failure Code',
+    INTERNAL_ERROR: 'Internal Error',
+    // SIP error causes.
+    BUSY: 'Busy',
+    REJECTED: 'Rejected',
+    REDIRECTED: 'Redirected',
+    UNAVAILABLE: 'Unavailable',
+    NOT_FOUND: 'Not Found',
+    ADDRESS_INCOMPLETE: 'Address Incomplete',
+    INCOMPATIBLE_SDP: 'Incompatible SDP',
+    MISSING_SDP: 'Missing SDP',
+    AUTHENTICATION_ERROR: 'Authentication Error',
+    // Session error causes.
+    BYE: 'Terminated',
+    WEBRTC_ERROR: 'WebRTC Error',
+    CANCELED: 'Canceled',
+    NO_ANSWER: 'No Answer',
+    EXPIRES: 'Expires',
+    NO_ACK: 'No ACK',
+    DIALOG_ERROR: 'Dialog Error',
+    USER_DENIED_MEDIA_ACCESS: 'User Denied Media Access',
+    BAD_MEDIA_DESCRIPTION: 'Bad Media Description',
+    RTP_TIMEOUT: 'RTP Timeout'
+  },
+  SIP_ERROR_CAUSES: {
+    REDIRECTED: [300, 301, 302, 305, 380],
+    BUSY: [486, 600],
+    REJECTED: [403, 603],
+    NOT_FOUND: [404, 604],
+    UNAVAILABLE: [480, 410, 408, 430],
+    ADDRESS_INCOMPLETE: [484, 424],
+    INCOMPATIBLE_SDP: [488, 606],
+    AUTHENTICATION_ERROR: [401, 407]
+  },
+  // SIP Methods.
+  ACK: 'ACK',
+  BYE: 'BYE',
+  CANCEL: 'CANCEL',
+  INFO: 'INFO',
+  INVITE: 'INVITE',
+  MESSAGE: 'MESSAGE',
+  NOTIFY: 'NOTIFY',
+  OPTIONS: 'OPTIONS',
+  REGISTER: 'REGISTER',
+  REFER: 'REFER',
+  UPDATE: 'UPDATE',
+  SUBSCRIBE: 'SUBSCRIBE',
+  // DTMF transport methods.
+  DTMF_TRANSPORT: {
+    INFO: 'INFO',
+    RFC2833: 'RFC2833'
+  },
+
+  /* SIP Response Reasons
+   * DOC: https://www.iana.org/assignments/sip-parameters
+   * Copied from https://github.com/versatica/OverSIP/blob/master/lib/oversip/sip/constants.rb#L7
+   */
+  REASON_PHRASE: {
+    100: 'Trying',
+    180: 'Ringing',
+    181: 'Call Is Being Forwarded',
+    182: 'Queued',
+    183: 'Session Progress',
+    199: 'Early Dialog Terminated',
+    // draft-ietf-sipcore-199
+    200: 'OK',
+    202: 'Accepted',
+    // RFC 3265
+    204: 'No Notification',
+    // RFC 5839
+    300: 'Multiple Choices',
+    301: 'Moved Permanently',
+    302: 'Moved Temporarily',
+    305: 'Use Proxy',
+    380: 'Alternative Service',
+    400: 'Bad Request',
+    401: 'Unauthorized',
+    402: 'Payment Required',
+    403: 'Forbidden',
+    404: 'Not Found',
+    405: 'Method Not Allowed',
+    406: 'Not Acceptable',
+    407: 'Proxy Authentication Required',
+    408: 'Request Timeout',
+    410: 'Gone',
+    412: 'Conditional Request Failed',
+    // RFC 3903
+    413: 'Request Entity Too Large',
+    414: 'Request-URI Too Long',
+    415: 'Unsupported Media Type',
+    416: 'Unsupported URI Scheme',
+    417: 'Unknown Resource-Priority',
+    // RFC 4412
+    420: 'Bad Extension',
+    421: 'Extension Required',
+    422: 'Session Interval Too Small',
+    // RFC 4028
+    423: 'Interval Too Brief',
+    424: 'Bad Location Information',
+    // RFC 6442
+    428: 'Use Identity Header',
+    // RFC 4474
+    429: 'Provide Referrer Identity',
+    // RFC 3892
+    430: 'Flow Failed',
+    // RFC 5626
+    433: 'Anonymity Disallowed',
+    // RFC 5079
+    436: 'Bad Identity-Info',
+    // RFC 4474
+    437: 'Unsupported Certificate',
+    // RFC 4744
+    438: 'Invalid Identity Header',
+    // RFC 4744
+    439: 'First Hop Lacks Outbound Support',
+    // RFC 5626
+    440: 'Max-Breadth Exceeded',
+    // RFC 5393
+    469: 'Bad Info Package',
+    // draft-ietf-sipcore-info-events
+    470: 'Consent Needed',
+    // RFC 5360
+    478: 'Unresolvable Destination',
+    // Custom code copied from Kamailio.
+    480: 'Temporarily Unavailable',
+    481: 'Call/Transaction Does Not Exist',
+    482: 'Loop Detected',
+    483: 'Too Many Hops',
+    484: 'Address Incomplete',
+    485: 'Ambiguous',
+    486: 'Busy Here',
+    487: 'Request Terminated',
+    488: 'Not Acceptable Here',
+    489: 'Bad Event',
+    // RFC 3265
+    491: 'Request Pending',
+    493: 'Undecipherable',
+    494: 'Security Agreement Required',
+    // RFC 3329
+    500: 'JsSIP Internal Error',
+    501: 'Not Implemented',
+    502: 'Bad Gateway',
+    503: 'Service Unavailable',
+    504: 'Server Time-out',
+    505: 'Version Not Supported',
+    513: 'Message Too Large',
+    580: 'Precondition Failure',
+    // RFC 3312
+    600: 'Busy Everywhere',
+    603: 'Decline',
+    604: 'Does Not Exist Anywhere',
+    606: 'Not Acceptable'
+  },
+  ALLOWED_METHODS: 'INVITE,ACK,CANCEL,BYE,UPDATE,MESSAGE,OPTIONS,REFER,INFO,NOTIFY',
+  ACCEPTED_BODY_TYPES: 'application/sdp, application/dtmf-relay',
+  MAX_FORWARDS: 69,
+  SESSION_EXPIRES: 90,
+  MIN_SESSION_EXPIRES: 60,
+  CONNECTION_RECOVERY_MAX_INTERVAL: 30,
+  CONNECTION_RECOVERY_MIN_INTERVAL: 2
+};
+},{"../package.json":40}],3:[function(require,module,exports){
+"use strict";
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
+
+function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
+
+var Logger = require('./Logger');
+
+var SIPMessage = require('./SIPMessage');
+
+var JsSIP_C = require('./Constants');
+
+var Transactions = require('./Transactions');
+
+var Dialog_RequestSender = require('./Dialog/RequestSender');
+
+var Utils = require('./Utils');
+
+var logger = new Logger('Dialog');
+var C = {
+  // Dialog states.
+  STATUS_EARLY: 1,
+  STATUS_CONFIRMED: 2,
+  STATUS_TERMINATED: 3
+}; // RFC 3261 12.1.
+
+module.exports = /*#__PURE__*/function () {
+  _createClass(Dialog, null, [{
+    key: "C",
+    // Expose C object.
+    get: function get() {
+      return C;
+    }
+  }]);
+
+  function Dialog(owner, message, type) {
+    var state = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : C.STATUS_CONFIRMED;
+
+    _classCallCheck(this, Dialog);
+
+    this._owner = owner;
+    this._ua = owner._ua;
+    this._uac_pending_reply = false;
+    this._uas_pending_reply = false;
+
+    if (!message.hasHeader('contact')) {
+      return {
+        error: 'unable to create a Dialog without Contact header field'
+      };
+    }
+
+    if (message instanceof SIPMessage.IncomingResponse) {
+      state = message.status_code < 200 ? C.STATUS_EARLY : C.STATUS_CONFIRMED;
+    }
+
+    var contact = message.parseHeader('contact'); // RFC 3261 12.1.1.
+
+    if (type === 'UAS') {
+      this._id = {
+        call_id: message.call_id,
+        local_tag: message.to_tag,
+        remote_tag: message.from_tag,
+        toString: function toString() {
+          return this.call_id + this.local_tag + this.remote_tag;
+        }
+      };
+      this._state = state;
+      this._remote_seqnum = message.cseq;
+      this._local_uri = message.parseHeader('to').uri;
+      this._remote_uri = message.parseHeader('from').uri;
+      this._remote_target = contact.uri;
+      this._route_set = message.getHeaders('record-route');
+      this._ack_seqnum = this._remote_seqnum;
+    } // RFC 3261 12.1.2.
+    else if (type === 'UAC') {
+        this._id = {
+          call_id: message.call_id,
+          local_tag: message.from_tag,
+          remote_tag: message.to_tag,
+          toString: function toString() {
+            return this.call_id + this.local_tag + this.remote_tag;
+          }
+        };
+        this._state = state;
+        this._local_seqnum = message.cseq;
+        this._local_uri = message.parseHeader('from').uri;
+        this._remote_uri = message.parseHeader('to').uri;
+        this._remote_target = contact.uri;
+        this._route_set = message.getHeaders('record-route').reverse();
+        this._ack_seqnum = null;
+      }
+
+    this._ua.newDialog(this);
+
+    logger.debug("new ".concat(type, " dialog created with status ").concat(this._state === C.STATUS_EARLY ? 'EARLY' : 'CONFIRMED'));
+  }
+
+  _createClass(Dialog, [{
+    key: "isTerminated",
+    value: function isTerminated() {
+      return this._status === C.STATUS_TERMINATED;
+    }
+  }, {
+    key: "update",
+    value: function update(message, type) {
+      this._state = C.STATUS_CONFIRMED;
+      logger.debug("dialog ".concat(this._id.toString(), "  changed to CONFIRMED state"));
+
+      if (type === 'UAC') {
+        // RFC 3261 13.2.2.4.
+        this._route_set = message.getHeaders('record-route').reverse();
+      }
+    }
+  }, {
+    key: "terminate",
+    value: function terminate() {
+      logger.debug("dialog ".concat(this._id.toString(), " deleted"));
+
+      this._ua.destroyDialog(this);
+
+      this._state = C.STATUS_TERMINATED;
+    }
+  }, {
+    key: "sendRequest",
+    value: function sendRequest(method) {
+      var _this = this;
+
+      var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
+      var extraHeaders = Utils.cloneArray(options.extraHeaders);
+      var eventHandlers = Utils.cloneObject(options.eventHandlers);
+      var body = options.body || null;
+
+      var request = this._createRequest(method, extraHeaders, body); // Increase the local CSeq on authentication.
+
+
+      eventHandlers.onAuthenticated = function () {
+        _this._local_seqnum += 1;
+      };
+
+      var request_sender = new Dialog_RequestSender(this, request, eventHandlers);
+      request_sender.send(); // Return the instance of OutgoingRequest.
+
+      return request;
+    }
+  }, {
+    key: "receiveRequest",
+    value: function receiveRequest(request) {
+      // Check in-dialog request.
+      if (!this._checkInDialogRequest(request)) {
+        return;
+      } // ACK received. Cleanup this._ack_seqnum.
+
+
+      if (request.method === JsSIP_C.ACK && this._ack_seqnum !== null) {
+        this._ack_seqnum = null;
+      } // INVITE received. Set this._ack_seqnum.
+      else if (request.method === JsSIP_C.INVITE) {
+          this._ack_seqnum = request.cseq;
+        }
+
+      this._owner.receiveRequest(request);
+    } // RFC 3261 12.2.1.1.
+
+  }, {
+    key: "_createRequest",
+    value: function _createRequest(method, extraHeaders, body) {
+      extraHeaders = Utils.cloneArray(extraHeaders);
+
+      if (!this._local_seqnum) {
+        this._local_seqnum = Math.floor(Math.random() * 10000);
+      }
+
+      var cseq = method === JsSIP_C.CANCEL || method === JsSIP_C.ACK ? this._local_seqnum : this._local_seqnum += 1;
+      var request = new SIPMessage.OutgoingRequest(method, this._remote_target, this._ua, {
+        'cseq': cseq,
+        'call_id': this._id.call_id,
+        'from_uri': this._local_uri,
+        'from_tag': this._id.local_tag,
+        'to_uri': this._remote_uri,
+        'to_tag': this._id.remote_tag,
+        'route_set': this._route_set
+      }, extraHeaders, body);
+      return request;
+    } // RFC 3261 12.2.2.
+
+  }, {
+    key: "_checkInDialogRequest",
+    value: function _checkInDialogRequest(request) {
+      var _this2 = this;
+
+      if (!this._remote_seqnum) {
+        this._remote_seqnum = request.cseq;
+      } else if (request.cseq < this._remote_seqnum) {
+        if (request.method === JsSIP_C.ACK) {
+          // We are not expecting any ACK with lower seqnum than the current one.
+          // Or this is not the ACK we are waiting for.
+          if (this._ack_seqnum === null || request.cseq !== this._ack_seqnum) {
+            return false;
+          }
+        } else {
+          request.reply(500);
+          return false;
+        }
+      } else if (request.cseq > this._remote_seqnum) {
+        this._remote_seqnum = request.cseq;
+      } // RFC3261 14.2 Modifying an Existing Session -UAS BEHAVIOR-.
+
+
+      if (request.method === JsSIP_C.INVITE || request.method === JsSIP_C.UPDATE && request.body) {
+        if (this._uac_pending_reply === true) {
+          request.reply(491);
+        } else if (this._uas_pending_reply === true) {
+          var retryAfter = (Math.random() * 10 | 0) + 1;
+          request.reply(500, null, ["Retry-After:".concat(retryAfter)]);
+          return false;
+        } else {
+          this._uas_pending_reply = true;
+
+          var stateChanged = function stateChanged() {
+            if (request.server_transaction.state === Transactions.C.STATUS_ACCEPTED || request.server_transaction.state === Transactions.C.STATUS_COMPLETED || request.server_transaction.state === Transactions.C.STATUS_TERMINATED) {
+              request.server_transaction.removeListener('stateChanged', stateChanged);
+              _this2._uas_pending_reply = false;
+            }
+          };
+
+          request.server_transaction.on('stateChanged', stateChanged);
+        } // RFC3261 12.2.2 Replace the dialog`s remote target URI if the request is accepted.
+
+
+        if (request.hasHeader('contact')) {
+          request.server_transaction.on('stateChanged', function () {
+            if (request.server_transaction.state === Transactions.C.STATUS_ACCEPTED) {
+              _this2._remote_target = request.parseHeader('contact').uri;
+            }
+          });
+        }
+      } else if (request.method === JsSIP_C.NOTIFY) {
+        // RFC6665 3.2 Replace the dialog`s remote target URI if the request is accepted.
+        if (request.hasHeader('contact')) {
+          request.server_transaction.on('stateChanged', function () {
+            if (request.server_transaction.state === Transactions.C.STATUS_COMPLETED) {
+              _this2._remote_target = request.parseHeader('contact').uri;
+            }
+          });
+        }
+      }
+
+      return true;
+    }
+  }, {
+    key: "id",
+    get: function get() {
+      return this._id;
+    }
+  }, {
+    key: "local_seqnum",
+    get: function get() {
+      return this._local_seqnum;
+    },
+    set: function set(num) {
+      this._local_seqnum = num;
+    }
+  }, {
+    key: "owner",
+    get: function get() {
+      return this._owner;
+    }
+  }, {
+    key: "uac_pending_reply",
+    get: function get() {
+      return this._uac_pending_reply;
+    },
+    set: function set(pending) {
+      this._uac_pending_reply = pending;
+    }
+  }, {
+    key: "uas_pending_reply",
+    get: function get() {
+      return this._uas_pending_reply;
+    }
+  }]);
+
+  return Dialog;
+}();
+},{"./Constants":2,"./Dialog/RequestSender":4,"./Logger":9,"./SIPMessage":21,"./Transactions":24,"./Utils":28}],4:[function(require,module,exports){
+"use strict";
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
+
+function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
+
+var JsSIP_C = require('../Constants');
+
+var Transactions = require('../Transactions');
+
+var RequestSender = require('../RequestSender'); // Default event handlers.
+
+
+var EventHandlers = {
+  onRequestTimeout: function onRequestTimeout() {},
+  onTransportError: function onTransportError() {},
+  onSuccessResponse: function onSuccessResponse() {},
+  onErrorResponse: function onErrorResponse() {},
+  onAuthenticated: function onAuthenticated() {},
+  onDialogError: function onDialogError() {}
+};
+
+module.exports = /*#__PURE__*/function () {
+  function DialogRequestSender(dialog, request, eventHandlers) {
+    _classCallCheck(this, DialogRequestSender);
+
+    this._dialog = dialog;
+    this._ua = dialog._ua;
+    this._request = request;
+    this._eventHandlers = eventHandlers; // RFC3261 14.1 Modifying an Existing Session. UAC Behavior.
+
+    this._reattempt = false;
+    this._reattemptTimer = null; // Define the undefined handlers.
+
+    for (var handler in EventHandlers) {
+      if (Object.prototype.hasOwnProperty.call(EventHandlers, handler)) {
+        if (!this._eventHandlers[handler]) {
+          this._eventHandlers[handler] = EventHandlers[handler];
+        }
+      }
+    }
+  }
+
+  _createClass(DialogRequestSender, [{
+    key: "send",
+    value: function send() {
+      var _this = this;
+
+      var request_sender = new RequestSender(this._ua, this._request, {
+        onRequestTimeout: function onRequestTimeout() {
+          _this._eventHandlers.onRequestTimeout();
+        },
+        onTransportError: function onTransportError() {
+          _this._eventHandlers.onTransportError();
+        },
+        onAuthenticated: function onAuthenticated(request) {
+          _this._eventHandlers.onAuthenticated(request);
+        },
+        onReceiveResponse: function onReceiveResponse(response) {
+          _this._receiveResponse(response);
+        }
+      });
+      request_sender.send(); // RFC3261 14.2 Modifying an Existing Session -UAC BEHAVIOR-.
+
+      if ((this._request.method === JsSIP_C.INVITE || this._request.method === JsSIP_C.UPDATE && this._request.body) && request_sender.clientTransaction.state !== Transactions.C.STATUS_TERMINATED) {
+        this._dialog.uac_pending_reply = true;
+
+        var stateChanged = function stateChanged() {
+          if (request_sender.clientTransaction.state === Transactions.C.STATUS_ACCEPTED || request_sender.clientTransaction.state === Transactions.C.STATUS_COMPLETED || request_sender.clientTransaction.state === Transactions.C.STATUS_TERMINATED) {
+            request_sender.clientTransaction.removeListener('stateChanged', stateChanged);
+            _this._dialog.uac_pending_reply = false;
+          }
+        };
+
+        request_sender.clientTransaction.on('stateChanged', stateChanged);
+      }
+    }
+  }, {
+    key: "_receiveResponse",
+    value: function _receiveResponse(response) {
+      var _this2 = this;
+
+      // RFC3261 12.2.1.2 408 or 481 is received for a request within a dialog.
+      if (response.status_code === 408 || response.status_code === 481) {
+        this._eventHandlers.onDialogError(response);
+      } else if (response.method === JsSIP_C.INVITE && response.status_code === 491) {
+        if (this._reattempt) {
+          if (response.status_code >= 200 && response.status_code < 300) {
+            this._eventHandlers.onSuccessResponse(response);
+          } else if (response.status_code >= 300) {
+            this._eventHandlers.onErrorResponse(response);
+          }
+        } else {
+          this._request.cseq = this._dialog.local_seqnum += 1;
+          this._reattemptTimer = setTimeout(function () {
+            if (!_this2._dialog.isTerminated()) {
+              _this2._reattempt = true;
+
+              _this2.send();
+            }
+          }, 1000);
+        }
+      } else if (response.status_code >= 200 && response.status_code < 300) {
+        this._eventHandlers.onSuccessResponse(response);
+      } else if (response.status_code >= 300) {
+        this._eventHandlers.onErrorResponse(response);
+      }
+    }
+  }, {
+    key: "request",
+    get: function get() {
+      return this._request;
+    }
+  }]);
+
+  return DialogRequestSender;
+}();
+},{"../Constants":2,"../RequestSender":20,"../Transactions":24}],5:[function(require,module,exports){
+"use strict";
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
+
+function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
+
+var Logger = require('./Logger');
+
+var Utils = require('./Utils');
+
+var logger = new Logger('DigestAuthentication');
+
+module.exports = /*#__PURE__*/function () {
+  function DigestAuthentication(credentials) {
+    _classCallCheck(this, DigestAuthentication);
+
+    this._credentials = credentials;
+    this._cnonce = null;
+    this._nc = 0;
+    this._ncHex = '00000000';
+    this._algorithm = null;
+    this._realm = null;
+    this._nonce = null;
+    this._opaque = null;
+    this._stale = null;
+    this._qop = null;
+    this._method = null;
+    this._uri = null;
+    this._ha1 = null;
+    this._response = null;
+  }
+
+  _createClass(DigestAuthentication, [{
+    key: "get",
+    value: function get(parameter) {
+      switch (parameter) {
+        case 'realm':
+          return this._realm;
+
+        case 'ha1':
+          return this._ha1;
+
+        default:
+          logger.warn('get() | cannot get "%s" parameter', parameter);
+          return undefined;
+      }
+    }
+    /**
+    * Performs Digest authentication given a SIP request and the challenge
+    * received in a response to that request.
+    * Returns true if auth was successfully generated, false otherwise.
+    */
+
+  }, {
+    key: "authenticate",
+    value: function authenticate(_ref, challenge)
+    /* test interface */
+    {
+      var method = _ref.method,
+          ruri = _ref.ruri,
+          body = _ref.body;
+      var cnonce = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null;
+      this._algorithm = challenge.algorithm;
+      this._realm = challenge.realm;
+      this._nonce = challenge.nonce;
+      this._opaque = challenge.opaque;
+      this._stale = challenge.stale;
+
+      if (this._algorithm) {
+        if (this._algorithm !== 'MD5') {
+          logger.warn('authenticate() | challenge with Digest algorithm different than "MD5", authentication aborted');
+          return false;
+        }
+      } else {
+        this._algorithm = 'MD5';
+      }
+
+      if (!this._nonce) {
+        logger.warn('authenticate() | challenge without Digest nonce, authentication aborted');
+        return false;
+      }
+
+      if (!this._realm) {
+        logger.warn('authenticate() | challenge without Digest realm, authentication aborted');
+        return false;
+      } // If no plain SIP password is provided.
+
+
+      if (!this._credentials.password) {
+        // If ha1 is not provided we cannot authenticate.
+        if (!this._credentials.ha1) {
+          logger.warn('authenticate() | no plain SIP password nor ha1 provided, authentication aborted');
+          return false;
+        } // If the realm does not match the stored realm we cannot authenticate.
+
+
+        if (this._credentials.realm !== this._realm) {
+          logger.warn('authenticate() | no plain SIP password, and stored `realm` does not match the given `realm`, cannot authenticate [stored:"%s", given:"%s"]', this._credentials.realm, this._realm);
+          return false;
+        }
+      } // 'qop' can contain a list of values (Array). Let's choose just one.
+
+
+      if (challenge.qop) {
+        if (challenge.qop.indexOf('auth-int') > -1) {
+          this._qop = 'auth-int';
+        } else if (challenge.qop.indexOf('auth') > -1) {
+          this._qop = 'auth';
+        } else {
+          // Otherwise 'qop' is present but does not contain 'auth' or 'auth-int', so abort here.
+          logger.warn('authenticate() | challenge without Digest qop different than "auth" or "auth-int", authentication aborted');
+          return false;
+        }
+      } else {
+        this._qop = null;
+      } // Fill other attributes.
+
+
+      this._method = method;
+      this._uri = ruri;
+      this._cnonce = cnonce || Utils.createRandomToken(12);
+      this._nc += 1;
+      var hex = Number(this._nc).toString(16);
+      this._ncHex = '00000000'.substr(0, 8 - hex.length) + hex; // Nc-value = 8LHEX. Max value = 'FFFFFFFF'.
+
+      if (this._nc === 4294967296) {
+        this._nc = 1;
+        this._ncHex = '00000001';
+      } // Calculate the Digest "response" value.
+      // If we have plain SIP password then regenerate ha1.
+
+
+      if (this._credentials.password) {
+        // HA1 = MD5(A1) = MD5(username:realm:password).
+        this._ha1 = Utils.calculateMD5("".concat(this._credentials.username, ":").concat(this._realm, ":").concat(this._credentials.password));
+      } // Otherwise reuse the stored ha1.
+      else {
+          this._ha1 = this._credentials.ha1;
+        }
+
+      var a2;
+      var ha2;
+
+      if (this._qop === 'auth') {
+        // HA2 = MD5(A2) = MD5(method:digestURI).
+        a2 = "".concat(this._method, ":").concat(this._uri);
+        ha2 = Utils.calculateMD5(a2);
+        logger.debug('authenticate() | using qop=auth [a2:"%s"]', a2); // Response = MD5(HA1:nonce:nonceCount:credentialsNonce:qop:HA2).
+
+        this._response = Utils.calculateMD5("".concat(this._ha1, ":").concat(this._nonce, ":").concat(this._ncHex, ":").concat(this._cnonce, ":auth:").concat(ha2));
+      } else if (this._qop === 'auth-int') {
+        // HA2 = MD5(A2) = MD5(method:digestURI:MD5(entityBody)).
+        a2 = "".concat(this._method, ":").concat(this._uri, ":").concat(Utils.calculateMD5(body ? body : ''));
+        ha2 = Utils.calculateMD5(a2);
+        logger.debug('authenticate() | using qop=auth-int [a2:"%s"]', a2); // Response = MD5(HA1:nonce:nonceCount:credentialsNonce:qop:HA2).
+
+        this._response = Utils.calculateMD5("".concat(this._ha1, ":").concat(this._nonce, ":").concat(this._ncHex, ":").concat(this._cnonce, ":auth-int:").concat(ha2));
+      } else if (this._qop === null) {
+        // HA2 = MD5(A2) = MD5(method:digestURI).
+        a2 = "".concat(this._method, ":").concat(this._uri);
+        ha2 = Utils.calculateMD5(a2);
+        logger.debug('authenticate() | using qop=null [a2:"%s"]', a2); // Response = MD5(HA1:nonce:HA2).
+
+        this._response = Utils.calculateMD5("".concat(this._ha1, ":").concat(this._nonce, ":").concat(ha2));
+      }
+
+      logger.debug('authenticate() | response generated');
+      return true;
+    }
+    /**
+    * Return the Proxy-Authorization or WWW-Authorization header value.
+    */
+
+  }, {
+    key: "toString",
+    value: function toString() {
+      var auth_params = [];
+
+      if (!this._response) {
+        throw new Error('response field does not exist, cannot generate Authorization header');
+      }
+
+      auth_params.push("algorithm=".concat(this._algorithm));
+      auth_params.push("username=\"".concat(this._credentials.username, "\""));
+      auth_params.push("realm=\"".concat(this._realm, "\""));
+      auth_params.push("nonce=\"".concat(this._nonce, "\""));
+      auth_params.push("uri=\"".concat(this._uri, "\""));
+      auth_params.push("response=\"".concat(this._response, "\""));
+
+      if (this._opaque) {
+        auth_params.push("opaque=\"".concat(this._opaque, "\""));
+      }
+
+      if (this._qop) {
+        auth_params.push("qop=".concat(this._qop));
+        auth_params.push("cnonce=\"".concat(this._cnonce, "\""));
+        auth_params.push("nc=".concat(this._ncHex));
+      }
+
+      return "Digest ".concat(auth_params.join(', '));
+    }
+  }]);
+
+  return DigestAuthentication;
+}();
+},{"./Logger":9,"./Utils":28}],6:[function(require,module,exports){
+"use strict";
+
+function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); }
+
+function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; }
+
+function _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } return _assertThisInitialized(self); }
+
+function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; }
+
+function _wrapNativeSuper(Class) { var _cache = typeof Map === "function" ? new Map() : undefined; _wrapNativeSuper = function _wrapNativeSuper(Class) { if (Class === null || !_isNativeFunction(Class)) return Class; if (typeof Class !== "function") { throw new TypeError("Super expression must either be null or a function"); } if (typeof _cache !== "undefined") { if (_cache.has(Class)) return _cache.get(Class); _cache.set(Class, Wrapper); } function Wrapper() { return _construct(Class, arguments, _getPrototypeOf(this).constructor); } Wrapper.prototype = Object.create(Class.prototype, { constructor: { value: Wrapper, enumerable: false, writable: true, configurable: true } }); return _setPrototypeOf(Wrapper, Class); }; return _wrapNativeSuper(Class); }
+
+function _construct(Parent, args, Class) { if (_isNativeReflectConstruct()) { _construct = Reflect.construct; } else { _construct = function _construct(Parent, args, Class) { var a = [null]; a.push.apply(a, args); var Constructor = Function.bind.apply(Parent, a); var instance = new Constructor(); if (Class) _setPrototypeOf(instance, Class.prototype); return instance; }; } return _construct.apply(null, arguments); }
+
+function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Date.prototype.toString.call(Reflect.construct(Date, [], function () {})); return true; } catch (e) { return false; } }
+
+function _isNativeFunction(fn) { return Function.toString.call(fn).indexOf("[native code]") !== -1; }
+
+function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }
+
+function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }
+
+var ConfigurationError = /*#__PURE__*/function (_Error) {
+  _inherits(ConfigurationError, _Error);
+
+  var _super = _createSuper(ConfigurationError);
+
+  function ConfigurationError(parameter, value) {
+    var _this;
+
+    _classCallCheck(this, ConfigurationError);
+
+    _this = _super.call(this);
+    _this.code = 1;
+    _this.name = 'CONFIGURATION_ERROR';
+    _this.parameter = parameter;
+    _this.value = value;
+    _this.message = !_this.value ? "Missing parameter: ".concat(_this.parameter) : "Invalid value ".concat(JSON.stringify(_this.value), " for parameter \"").concat(_this.parameter, "\"");
+    return _this;
+  }
+
+  return ConfigurationError;
+}( /*#__PURE__*/_wrapNativeSuper(Error));
+
+var InvalidStateError = /*#__PURE__*/function (_Error2) {
+  _inherits(InvalidStateError, _Error2);
+
+  var _super2 = _createSuper(InvalidStateError);
+
+  function InvalidStateError(status) {
+    var _this2;
+
+    _classCallCheck(this, InvalidStateError);
+
+    _this2 = _super2.call(this);
+    _this2.code = 2;
+    _this2.name = 'INVALID_STATE_ERROR';
+    _this2.status = status;
+    _this2.message = "Invalid status: ".concat(status);
+    return _this2;
+  }
+
+  return InvalidStateError;
+}( /*#__PURE__*/_wrapNativeSuper(Error));
+
+var NotSupportedError = /*#__PURE__*/function (_Error3) {
+  _inherits(NotSupportedError, _Error3);
+
+  var _super3 = _createSuper(NotSupportedError);
+
+  function NotSupportedError(message) {
+    var _this3;
+
+    _classCallCheck(this, NotSupportedError);
+
+    _this3 = _super3.call(this);
+    _this3.code = 3;
+    _this3.name = 'NOT_SUPPORTED_ERROR';
+    _this3.message = message;
+    return _this3;
+  }
+
+  return NotSupportedError;
+}( /*#__PURE__*/_wrapNativeSuper(Error));
+
+var NotReadyError = /*#__PURE__*/function (_Error4) {
+  _inherits(NotReadyError, _Error4);
+
+  var _super4 = _createSuper(NotReadyError);
+
+  function NotReadyError(message) {
+    var _this4;
+
+    _classCallCheck(this, NotReadyError);
+
+    _this4 = _super4.call(this);
+    _this4.code = 4;
+    _this4.name = 'NOT_READY_ERROR';
+    _this4.message = message;
+    return _this4;
+  }
+
+  return NotReadyError;
+}( /*#__PURE__*/_wrapNativeSuper(Error));
+
+module.exports = {
+  ConfigurationError: ConfigurationError,
+  InvalidStateError: InvalidStateError,
+  NotSupportedError: NotSupportedError,
+  NotReadyError: NotReadyError
+};
+},{}],7:[function(require,module,exports){
+"use strict";
+
+module.exports = function () {
+  /*
+   * Generated by PEG.js 0.7.0.
+   *
+   * http://pegjs.majda.cz/
+   */
+  function quote(s) {
+    /*
+     * ECMA-262, 5th ed., 7.8.4: All characters may appear literally in a
+     * string literal except for the closing quote character, backslash,
+     * carriage return, line separator, paragraph separator, and line feed.
+     * Any character may appear in the form of an escape sequence.
+     *
+     * For portability, we also escape escape all control and non-ASCII
+     * characters. Note that "\0" and "\v" escape sequences are not used
+     * because JSHint does not like the first and IE the second.
+     */
+    return '"' + s.replace(/\\/g, '\\\\') // backslash
+    .replace(/"/g, '\\"') // closing quote character
+    .replace(/\x08/g, '\\b') // backspace
+    .replace(/\t/g, '\\t') // horizontal tab
+    .replace(/\n/g, '\\n') // line feed
+    .replace(/\f/g, '\\f') // form feed
+    .replace(/\r/g, '\\r') // carriage return
+    .replace(/[\x00-\x07\x0B\x0E-\x1F\x80-\uFFFF]/g, escape) + '"';
+  }
+
+  var result = {
+    /*
+     * Parses the input with a generated parser. If the parsing is successfull,
+     * returns a value explicitly or implicitly specified by the grammar from
+     * which the parser was generated (see |PEG.buildParser|). If the parsing is
+     * unsuccessful, throws |PEG.parser.SyntaxError| describing the error.
+     */
+    parse: function parse(input, startRule) {
+      var parseFunctions = {
+        "CRLF": parse_CRLF,
+        "DIGIT": parse_DIGIT,
+        "ALPHA": parse_ALPHA,
+        "HEXDIG": parse_HEXDIG,
+        "WSP": parse_WSP,
+        "OCTET": parse_OCTET,
+        "DQUOTE": parse_DQUOTE,
+        "SP": parse_SP,
+        "HTAB": parse_HTAB,
+        "alphanum": parse_alphanum,
+        "reserved": parse_reserved,
+        "unreserved": parse_unreserved,
+        "mark": parse_mark,
+        "escaped": parse_escaped,
+        "LWS": parse_LWS,
+        "SWS": parse_SWS,
+        "HCOLON": parse_HCOLON,
+        "TEXT_UTF8_TRIM": parse_TEXT_UTF8_TRIM,
+        "TEXT_UTF8char": parse_TEXT_UTF8char,
+        "UTF8_NONASCII": parse_UTF8_NONASCII,
+        "UTF8_CONT": parse_UTF8_CONT,
+        "LHEX": parse_LHEX,
+        "token": parse_token,
+        "token_nodot": parse_token_nodot,
+        "separators": parse_separators,
+        "word": parse_word,
+        "STAR": parse_STAR,
+        "SLASH": parse_SLASH,
+        "EQUAL": parse_EQUAL,
+        "LPAREN": parse_LPAREN,
+        "RPAREN": parse_RPAREN,
+        "RAQUOT": parse_RAQUOT,
+        "LAQUOT": parse_LAQUOT,
+        "COMMA": parse_COMMA,
+        "SEMI": parse_SEMI,
+        "COLON": parse_COLON,
+        "LDQUOT": parse_LDQUOT,
+        "RDQUOT": parse_RDQUOT,
+        "comment": parse_comment,
+        "ctext": parse_ctext,
+        "quoted_string": parse_quoted_string,
+        "quoted_string_clean": parse_quoted_string_clean,
+        "qdtext": parse_qdtext,
+        "quoted_pair": parse_quoted_pair,
+        "SIP_URI_noparams": parse_SIP_URI_noparams,
+        "SIP_URI": parse_SIP_URI,
+        "uri_scheme": parse_uri_scheme,
+        "uri_scheme_sips": parse_uri_scheme_sips,
+        "uri_scheme_sip": parse_uri_scheme_sip,
+        "userinfo": parse_userinfo,
+        "user": parse_user,
+        "user_unreserved": parse_user_unreserved,
+        "password": parse_password,
+        "hostport": parse_hostport,
+        "host": parse_host,
+        "hostname": parse_hostname,
+        "domainlabel": parse_domainlabel,
+        "toplabel": parse_toplabel,
+        "IPv6reference": parse_IPv6reference,
+        "IPv6address": parse_IPv6address,
+        "h16": parse_h16,
+        "ls32": parse_ls32,
+        "IPv4address": parse_IPv4address,
+        "dec_octet": parse_dec_octet,
+        "port": parse_port,
+        "uri_parameters": parse_uri_parameters,
+        "uri_parameter": parse_uri_parameter,
+        "transport_param": parse_transport_param,
+        "user_param": parse_user_param,
+        "method_param": parse_method_param,
+        "ttl_param": parse_ttl_param,
+        "maddr_param": parse_maddr_param,
+        "lr_param": parse_lr_param,
+        "other_param": parse_other_param,
+        "pname": parse_pname,
+        "pvalue": parse_pvalue,
+        "paramchar": parse_paramchar,
+        "param_unreserved": parse_param_unreserved,
+        "headers": parse_headers,
+        "header": parse_header,
+        "hname": parse_hname,
+        "hvalue": parse_hvalue,
+        "hnv_unreserved": parse_hnv_unreserved,
+        "Request_Response": parse_Request_Response,
+        "Request_Line": parse_Request_Line,
+        "Request_URI": parse_Request_URI,
+        "absoluteURI": parse_absoluteURI,
+        "hier_part": parse_hier_part,
+        "net_path": parse_net_path,
+        "abs_path": parse_abs_path,
+        "opaque_part": parse_opaque_part,
+        "uric": parse_uric,
+        "uric_no_slash": parse_uric_no_slash,
+        "path_segments": parse_path_segments,
+        "segment": parse_segment,
+        "param": parse_param,
+        "pchar": parse_pchar,
+        "scheme": parse_scheme,
+        "authority": parse_authority,
+        "srvr": parse_srvr,
+        "reg_name": parse_reg_name,
+        "query": parse_query,
+        "SIP_Version": parse_SIP_Version,
+        "INVITEm": parse_INVITEm,
+        "ACKm": parse_ACKm,
+        "OPTIONSm": parse_OPTIONSm,
+        "BYEm": parse_BYEm,
+        "CANCELm": parse_CANCELm,
+        "REGISTERm": parse_REGISTERm,
+        "SUBSCRIBEm": parse_SUBSCRIBEm,
+        "NOTIFYm": parse_NOTIFYm,
+        "REFERm": parse_REFERm,
+        "Method": parse_Method,
+        "Status_Line": parse_Status_Line,
+        "Status_Code": parse_Status_Code,
+        "extension_code": parse_extension_code,
+        "Reason_Phrase": parse_Reason_Phrase,
+        "Allow_Events": parse_Allow_Events,
+        "Call_ID": parse_Call_ID,
+        "Contact": parse_Contact,
+        "contact_param": parse_contact_param,
+        "name_addr": parse_name_addr,
+        "display_name": parse_display_name,
+        "contact_params": parse_contact_params,
+        "c_p_q": parse_c_p_q,
+        "c_p_expires": parse_c_p_expires,
+        "delta_seconds": parse_delta_seconds,
+        "qvalue": parse_qvalue,
+        "generic_param": parse_generic_param,
+        "gen_value": parse_gen_value,
+        "Content_Disposition": parse_Content_Disposition,
+        "disp_type": parse_disp_type,
+        "disp_param": parse_disp_param,
+        "handling_param": parse_handling_param,
+        "Content_Encoding": parse_Content_Encoding,
+        "Content_Length": parse_Content_Length,
+        "Content_Type": parse_Content_Type,
+        "media_type": parse_media_type,
+        "m_type": parse_m_type,
+        "discrete_type": parse_discrete_type,
+        "composite_type": parse_composite_type,
+        "extension_token": parse_extension_token,
+        "x_token": parse_x_token,
+        "m_subtype": parse_m_subtype,
+        "m_parameter": parse_m_parameter,
+        "m_value": parse_m_value,
+        "CSeq": parse_CSeq,
+        "CSeq_value": parse_CSeq_value,
+        "Expires": parse_Expires,
+        "Event": parse_Event,
+        "event_type": parse_event_type,
+        "From": parse_From,
+        "from_param": parse_from_param,
+        "tag_param": parse_tag_param,
+        "Max_Forwards": parse_Max_Forwards,
+        "Min_Expires": parse_Min_Expires,
+        "Name_Addr_Header": parse_Name_Addr_Header,
+        "Proxy_Authenticate": parse_Proxy_Authenticate,
+        "challenge": parse_challenge,
+        "other_challenge": parse_other_challenge,
+        "auth_param": parse_auth_param,
+        "digest_cln": parse_digest_cln,
+        "realm": parse_realm,
+        "realm_value": parse_realm_value,
+        "domain": parse_domain,
+        "URI": parse_URI,
+        "nonce": parse_nonce,
+        "nonce_value": parse_nonce_value,
+        "opaque": parse_opaque,
+        "stale": parse_stale,
+        "algorithm": parse_algorithm,
+        "qop_options": parse_qop_options,
+        "qop_value": parse_qop_value,
+        "Proxy_Require": parse_Proxy_Require,
+        "Record_Route": parse_Record_Route,
+        "rec_route": parse_rec_route,
+        "Reason": parse_Reason,
+        "reason_param": parse_reason_param,
+        "reason_cause": parse_reason_cause,
+        "Require": parse_Require,
+        "Route": parse_Route,
+        "route_param": parse_route_param,
+        "Subscription_State": parse_Subscription_State,
+        "substate_value": parse_substate_value,
+        "subexp_params": parse_subexp_params,
+        "event_reason_value": parse_event_reason_value,
+        "Subject": parse_Subject,
+        "Supported": parse_Supported,
+        "To": parse_To,
+        "to_param": parse_to_param,
+        "Via": parse_Via,
+        "via_param": parse_via_param,
+        "via_params": parse_via_params,
+        "via_ttl": parse_via_ttl,
+        "via_maddr": parse_via_maddr,
+        "via_received": parse_via_received,
+        "via_branch": parse_via_branch,
+        "response_port": parse_response_port,
+        "rport": parse_rport,
+        "sent_protocol": parse_sent_protocol,
+        "protocol_name": parse_protocol_name,
+        "transport": parse_transport,
+        "sent_by": parse_sent_by,
+        "via_host": parse_via_host,
+        "via_port": parse_via_port,
+        "ttl": parse_ttl,
+        "WWW_Authenticate": parse_WWW_Authenticate,
+        "Session_Expires": parse_Session_Expires,
+        "s_e_expires": parse_s_e_expires,
+        "s_e_params": parse_s_e_params,
+        "s_e_refresher": parse_s_e_refresher,
+        "extension_header": parse_extension_header,
+        "header_value": parse_header_value,
+        "message_body": parse_message_body,
+        "uuid_URI": parse_uuid_URI,
+        "uuid": parse_uuid,
+        "hex4": parse_hex4,
+        "hex8": parse_hex8,
+        "hex12": parse_hex12,
+        "Refer_To": parse_Refer_To,
+        "Replaces": parse_Replaces,
+        "call_id": parse_call_id,
+        "replaces_param": parse_replaces_param,
+        "to_tag": parse_to_tag,
+        "from_tag": parse_from_tag,
+        "early_flag": parse_early_flag
+      };
+
+      if (startRule !== undefined) {
+        if (parseFunctions[startRule] === undefined) {
+          throw new Error("Invalid rule name: " + quote(startRule) + ".");
+        }
+      } else {
+        startRule = "CRLF";
+      }
+
+      var pos = 0;
+      var reportFailures = 0;
+      var rightmostFailuresPos = 0;
+      var rightmostFailuresExpected = [];
+
+      function padLeft(input, padding, length) {
+        var result = input;
+        var padLength = length - input.length;
+
+        for (var i = 0; i < padLength; i++) {
+          result = padding + result;
+        }
+
+        return result;
+      }
+
+      function escape(ch) {
+        var charCode = ch.charCodeAt(0);
+        var escapeChar;
+        var length;
+
+        if (charCode <= 0xFF) {
+          escapeChar = 'x';
+          length = 2;
+        } else {
+          escapeChar = 'u';
+          length = 4;
+        }
+
+        return '\\' + escapeChar + padLeft(charCode.toString(16).toUpperCase(), '0', length);
+      }
+
+      function matchFailed(failure) {
+        if (pos < rightmostFailuresPos) {
+          return;
+        }
+
+        if (pos > rightmostFailuresPos) {
+          rightmostFailuresPos = pos;
+          rightmostFailuresExpected = [];
+        }
+
+        rightmostFailuresExpected.push(failure);
+      }
+
+      function parse_CRLF() {
+        var result0;
+
+        if (input.substr(pos, 2) === "\r\n") {
+          result0 = "\r\n";
+          pos += 2;
+        } else {
+          result0 = null;
+
+          if (reportFailures === 0) {
+            matchFailed("\"\\r\\n\"");
+          }
+        }
+
+        return result0;
+      }
+
+      function parse_DIGIT() {
+        var result0;
+
+        if (/^[0-9]/.test(input.charAt(pos))) {
+          result0 = input.charAt(pos);
+          pos++;
+        } else {
+          result0 = null;
+
+          if (reportFailures === 0) {
+            matchFailed("[0-9]");
+          }
+        }
+
+        return result0;
+      }
+
+      function parse_ALPHA() {
+        var result0;
+
+        if (/^[a-zA-Z]/.test(input.charAt(pos))) {
+          result0 = input.charAt(pos);
+          pos++;
+        } else {
+          result0 = null;
+
+          if (reportFailures === 0) {
+            matchFailed("[a-zA-Z]");
+          }
+        }
+
+        return result0;
+      }
+
+      function parse_HEXDIG() {
+        var result0;
+
+        if (/^[0-9a-fA-F]/.test(input.charAt(pos))) {
+          result0 = input.charAt(pos);
+          pos++;
+        } else {
+          result0 = null;
+
+          if (reportFailures === 0) {
+            matchFailed("[0-9a-fA-F]");
+          }
+        }
+
+        return result0;
+      }
+
+      function parse_WSP() {
+        var result0;
+        result0 = parse_SP();
+
+        if (result0 === null) {
+          result0 = parse_HTAB();
+        }
+
+        return result0;
+      }
+
+      function parse_OCTET() {
+        var result0;
+
+        if (/^[\0-\xFF]/.test(input.charAt(pos))) {
+          result0 = input.charAt(pos);
+          pos++;
+        } else {
+          result0 = null;
+
+          if (reportFailures === 0) {
+            matchFailed("[\\0-\\xFF]");
+          }
+        }
+
+        return result0;
+      }
+
+      function parse_DQUOTE() {
+        var result0;
+
+        if (/^["]/.test(input.charAt(pos))) {
+          result0 = input.charAt(pos);
+          pos++;
+        } else {
+          result0 = null;
+
+          if (reportFailures === 0) {
+            matchFailed("[\"]");
+          }
+        }
+
+        return result0;
+      }
+
+      function parse_SP() {
+        var result0;
+
+        if (input.charCodeAt(pos) === 32) {
+          result0 = " ";
+          pos++;
+        } else {
+          result0 = null;
+
+          if (reportFailures === 0) {
+            matchFailed("\" \"");
+          }
+        }
+
+        return result0;
+      }
+
+      function parse_HTAB() {
+        var result0;
+
+        if (input.charCodeAt(pos) === 9) {
+          result0 = "\t";
+          pos++;
+        } else {
+          result0 = null;
+
+          if (reportFailures === 0) {
+            matchFailed("\"\\t\"");
+          }
+        }
+
+        return result0;
+      }
+
+      function parse_alphanum() {
+        var result0;
+
+        if (/^[a-zA-Z0-9]/.test(input.charAt(pos))) {
+          result0 = input.charAt(pos);
+          pos++;
+        } else {
+          result0 = null;
+
+          if (reportFailures === 0) {
+            matchFailed("[a-zA-Z0-9]");
+          }
+        }
+
+        return result0;
+      }
+
+      function parse_reserved() {
+        var result0;
+
+        if (input.charCodeAt(pos) === 59) {
+          result0 = ";";
+          pos++;
+        } else {
+          result0 = null;
+
+          if (reportFailures === 0) {
+            matchFailed("\";\"");
+          }
+        }
+
+        if (result0 === null) {
+          if (input.charCodeAt(pos) === 47) {
+            result0 = "/";
+            pos++;
+          } else {
+            result0 = null;
+
+            if (reportFailures === 0) {
+              matchFailed("\"/\"");
+            }
+          }
+
+          if (result0 === null) {
+            if (input.charCodeAt(pos) === 63) {
+              result0 = "?";
+              pos++;
+            } else {
+              result0 = null;
+
+              if (reportFailures === 0) {
+                matchFailed("\"?\"");
+              }
+            }
+
+            if (result0 === null) {
+              if (input.charCodeAt(pos) === 58) {
+                result0 = ":";
+                pos++;
+              } else {
+                result0 = null;
+
+                if (reportFailures === 0) {
+                  matchFailed("\":\"");
+                }
+              }
+
+              if (result0 === null) {
+                if (input.charCodeAt(pos) === 64) {
+                  result0 = "@";
+                  pos++;
+                } else {
+                  result0 = null;
+
+                  if (reportFailures === 0) {
+                    matchFailed("\"@\"");
+                  }
+                }
+
+                if (result0 === null) {
+                  if (input.charCodeAt(pos) === 38) {
+                    result0 = "&";
+                    pos++;
+                  } else {
+                    result0 = null;
+
+                    if (reportFailures === 0) {
+                      matchFailed("\"&\"");
+                    }
+                  }
+
+                  if (result0 === null) {
+                    if (input.charCodeAt(pos) === 61) {
+                      result0 = "=";
+                      pos++;
+                    } else {
+                      result0 = null;
+
+                      if (reportFailures === 0) {
+                        matchFailed("\"=\"");
+                      }
+                    }
+
+                    if (result0 === null) {
+                      if (input.charCodeAt(pos) === 43) {
+                        result0 = "+";
+                        pos++;
+                      } else {
+                        result0 = null;
+
+                        if (reportFailures === 0) {
+                          matchFailed("\"+\"");
+                        }
+                      }
+
+                      if (result0 === null) {
+                        if (input.charCodeAt(pos) === 36) {
+                          result0 = "$";
+                          pos++;
+                        } else {
+                          result0 = null;
+
+                          if (reportFailures === 0) {
+                            matchFailed("\"$\"");
+                          }
+                        }
+
+                        if (result0 === null) {
+                          if (input.charCodeAt(pos) === 44) {
+                            result0 = ",";
+                            pos++;
+                          } else {
+                            result0 = null;
+
+                            if (reportFailures === 0) {
+                              matchFailed("\",\"");
+                            }
+                          }
+                        }
+                      }
+                    }
+                  }
+                }
+              }
+            }
+          }
+        }
+
+        return result0;
+      }
+
+      function parse_unreserved() {
+        var result0;
+        result0 = parse_alphanum();
+
+        if (result0 === null) {
+          result0 = parse_mark();
+        }
+
+        return result0;
+      }
+
+      function parse_mark() {
+        var result0;
+
+        if (input.charCodeAt(pos) === 45) {
+          result0 = "-";
+          pos++;
+        } else {
+          result0 = null;
+
+          if (reportFailures === 0) {
+            matchFailed("\"-\"");
+          }
+        }
+
+        if (result0 === null) {
+          if (input.charCodeAt(pos) === 95) {
+            result0 = "_";
+            pos++;
+          } else {
+            result0 = null;
+
+            if (reportFailures === 0) {
+              matchFailed("\"_\"");
+            }
+          }
+
+          if (result0 === null) {
+            if (input.charCodeAt(pos) === 46) {
+              result0 = ".";
+              pos++;
+            } else {
+              result0 = null;
+
+              if (reportFailures === 0) {
+                matchFailed("\".\"");
+              }
+            }
+
+            if (result0 === null) {
+              if (input.charCodeAt(pos) === 33) {
+                result0 = "!";
+                pos++;
+              } else {
+                result0 = null;
+
+                if (reportFailures === 0) {
+                  matchFailed("\"!\"");
+                }
+              }
+
+              if (result0 === null) {
+                if (input.charCodeAt(pos) === 126) {
+                  result0 = "~";
+                  pos++;
+                } else {
+                  result0 = null;
+
+                  if (reportFailures === 0) {
+                    matchFailed("\"~\"");
+                  }
+                }
+
+                if (result0 === null) {
+                  if (input.charCodeAt(pos) === 42) {
+                    result0 = "*";
+                    pos++;
+                  } else {
+                    result0 = null;
+
+                    if (reportFailures === 0) {
+                      matchFailed("\"*\"");
+                    }
+                  }
+
+                  if (result0 === null) {
+                    if (input.charCodeAt(pos) === 39) {
+                      result0 = "'";
+                      pos++;
+                    } else {
+                      result0 = null;
+
+                      if (reportFailures === 0) {
+                        matchFailed("\"'\"");
+                      }
+                    }
+
+                    if (result0 === null) {
+                      if (input.charCodeAt(pos) === 40) {
+                        result0 = "(";
+                        pos++;
+                      } else {
+                        result0 = null;
+
+                        if (reportFailures === 0) {
+                          matchFailed("\"(\"");
+                        }
+                      }
+
+                      if (result0 === null) {
+                        if (input.charCodeAt(pos) === 41) {
+                          result0 = ")";
+                          pos++;
+                        } else {
+                          result0 = null;
+
+                          if (reportFailures === 0) {
+                            matchFailed("\")\"");
+                          }
+                        }
+                      }
+                    }
+                  }
+                }
+              }
+            }
+          }
+        }
+
+        return result0;
+      }
+
+      function parse_escaped() {
+        var result0, result1, result2;
+        var pos0, pos1;
+        pos0 = pos;
+        pos1 = pos;
+
+        if (input.charCodeAt(pos) === 37) {
+          result0 = "%";
+          pos++;
+        } else {
+          result0 = null;
+
+          if (reportFailures === 0) {
+            matchFailed("\"%\"");
+          }
+        }
+
+        if (result0 !== null) {
+          result1 = parse_HEXDIG();
+
+          if (result1 !== null) {
+            result2 = parse_HEXDIG();
+
+            if (result2 !== null) {
+              result0 = [result0, result1, result2];
+            } else {
+              result0 = null;
+              pos = pos1;
+            }
+          } else {
+            result0 = null;
+            pos = pos1;
+          }
+        } else {
+          result0 = null;
+          pos = pos1;
+        }
+
+        if (result0 !== null) {
+          result0 = function (offset, escaped) {
+            return escaped.join('');
+          }(pos0, result0);
+        }
+
+        if (result0 === null) {
+          pos = pos0;
+        }
+
+        return result0;
+      }
+
+      function parse_LWS() {
+        var result0, result1, result2;
+        var pos0, pos1, pos2;
+        pos0 = pos;
+        pos1 = pos;
+        pos2 = pos;
+        result0 = [];
+        result1 = parse_WSP();
+
+        while (result1 !== null) {
+          result0.push(result1);
+          result1 = parse_WSP();
+        }
+
+        if (result0 !== null) {
+          result1 = parse_CRLF();
+
+          if (result1 !== null) {
+            result0 = [result0, result1];
+          } else {
+            result0 = null;
+            pos = pos2;
+          }
+        } else {
+          result0 = null;
+          pos = pos2;
+        }
+
+        result0 = result0 !== null ? result0 : "";
+
+        if (result0 !== null) {
+          result2 = parse_WSP();
+
+          if (result2 !== null) {
+            result1 = [];
+
+            while (result2 !== null) {
+              result1.push(result2);
+              result2 = parse_WSP();
+            }
+          } else {
+            result1 = null;
+          }
+
+          if (result1 !== null) {
+            result0 = [result0, result1];
+          } else {
+            result0 = null;
+            pos = pos1;
+          }
+        } else {
+          result0 = null;
+          pos = pos1;
+        }
+
+        if (result0 !== null) {
+          result0 = function (offset) {
+            return " ";
+          }(pos0);
+        }
+
+        if (result0 === null) {
+          pos = pos0;
+        }
+
+        return result0;
+      }
+
+      function parse_SWS() {
+        var result0;
+        result0 = parse_LWS();
+        result0 = result0 !== null ? result0 : "";
+        return result0;
+      }
+
+      function parse_HCOLON() {
+        var result0, result1, result2;
+        var pos0, pos1;
+        pos0 = pos;
+        pos1 = pos;
+        result0 = [];
+        result1 = parse_SP();
+
+        if (result1 === null) {
+          result1 = parse_HTAB();
+        }
+
+        while (result1 !== null) {
+          result0.push(result1);
+          result1 = parse_SP();
+
+          if (result1 === null) {
+            result1 = parse_HTAB();
+          }
+        }
+
+        if (result0 !== null) {
+          if (input.charCodeAt(pos) === 58) {
+            result1 = ":";
+            pos++;
+          } else {
+            result1 = null;
+
+            if (reportFailures === 0) {
+              matchFailed("\":\"");
+            }
+          }
+
+          if (result1 !== null) {
+            result2 = parse_SWS();
+
+            if (result2 !== null) {
+              result0 = [result0, result1, result2];
+            } else {
+              result0 = null;
+              pos = pos1;
+            }
+          } else {
+            result0 = null;
+            pos = pos1;
+          }
+        } else {
+          result0 = null;
+          pos = pos1;
+        }
+
+        if (result0 !== null) {
+          result0 = function (offset) {
+            return ':';
+          }(pos0);
+        }
+
+        if (result0 === null) {
+          pos = pos0;
+        }
+
+        return result0;
+      }
+
+      function parse_TEXT_UTF8_TRIM() {
+        var result0, result1, result2, result3;
+        var pos0, pos1, pos2;
+        pos0 = pos;
+        pos1 = pos;
+        result1 = parse_TEXT_UTF8char();
+
+        if (result1 !== null) {
+          result0 = [];
+
+          while (result1 !== null) {
+            result0.push(result1);
+            result1 = parse_TEXT_UTF8char();
+          }
+        } else {
+          result0 = null;
+        }
+
+        if (result0 !== null) {
+          result1 = [];
+          pos2 = pos;
+          result2 = [];
+          result3 = parse_LWS();
+
+          while (result3 !== null) {
+            result2.push(result3);
+            result3 = parse_LWS();
+          }
+
+          if (result2 !== null) {
+            result3 = parse_TEXT_UTF8char();
+
+            if (result3 !== null) {
+              result2 = [result2, result3];
+            } else {
+              result2 = null;
+              pos = pos2;
+            }
+          } else {
+            result2 = null;
+            pos = pos2;
+          }
+
+          while (result2 !== null) {
+            result1.push(result2);
+            pos2 = pos;
+            result2 = [];
+            result3 = parse_LWS();
+
+            while (result3 !== null) {
+              result2.push(result3);
+              result3 = parse_LWS();
+            }
+
+            if (result2 !== null) {
+              result3 = parse_TEXT_UTF8char();
+
+              if (result3 !== null) {
+                result2 = [result2, result3];
+              } else {
+                result2 = null;
+                pos = pos2;
+              }
+            } else {
+              result2 = null;
+              pos = pos2;
+            }
+          }
+
+          if (result1 !== null) {
+            result0 = [result0, result1];
+          } else {
+            result0 = null;
+            pos = pos1;
+          }
+        } else {
+          result0 = null;
+          pos = pos1;
+        }
+
+        if (result0 !== null) {
+          result0 = function (offset) {
+            return input.substring(pos, offset);
+          }(pos0);
+        }
+
+        if (result0 === null) {
+          pos = pos0;
+        }
+
+        return result0;
+      }
+
+      function parse_TEXT_UTF8char() {
+        var result0;
+
+        if (/^[!-~]/.test(input.charAt(pos))) {
+          result0 = input.charAt(pos);
+          pos++;
+        } else {
+          result0 = null;
+
+          if (reportFailures === 0) {
+            matchFailed("[!-~]");
+          }
+        }
+
+        if (result0 === null) {
+          result0 = parse_UTF8_NONASCII();
+        }
+
+        return result0;
+      }
+
+      function parse_UTF8_NONASCII() {
+        var result0;
+
+        if (/^[\x80-\uFFFF]/.test(input.charAt(pos))) {
+          result0 = input.charAt(pos);
+          pos++;
+        } else {
+          result0 = null;
+
+          if (reportFailures === 0) {
+            matchFailed("[\\x80-\\uFFFF]");
+          }
+        }
+
+        return result0;
+      }
+
+      function parse_UTF8_CONT() {
+        var result0;
+
+        if (/^[\x80-\xBF]/.test(input.charAt(pos))) {
+          result0 = input.charAt(pos);
+          pos++;
+        } else {
+          result0 = null;
+
+          if (reportFailures === 0) {
+            matchFailed("[\\x80-\\xBF]");
+          }
+        }
+
+        return result0;
+      }
+
+      function parse_LHEX() {
+        var result0;
+        result0 = parse_DIGIT();
+
+        if (result0 === null) {
+          if (/^[a-f]/.test(input.charAt(pos))) {
+            result0 = input.charAt(pos);
+            pos++;
+          } else {
+            result0 = null;
+
+            if (reportFailures === 0) {
+              matchFailed("[a-f]");
+            }
+          }
+        }
+
+        return result0;
+      }
+
+      function parse_token() {
+        var result0, result1;
+        var pos0;
+        pos0 = pos;
+        result1 = parse_alphanum();
+
+        if (result1 === null) {
+          if (input.charCodeAt(pos) === 45) {
+            result1 = "-";
+            pos++;
+          } else {
+            result1 = null;
+
+            if (reportFailures === 0) {
+              matchFailed("\"-\"");
+            }
+          }
+
+          if (result1 === null) {
+            if (input.charCodeAt(pos) === 46) {
+              result1 = ".";
+              pos++;
+            } else {
+              result1 = null;
+
+              if (reportFailures === 0) {
+                matchFailed("\".\"");
+              }
+            }
+
+            if (result1 === null) {
+              if (input.charCodeAt(pos) === 33) {
+                result1 = "!";
+                pos++;
+              } else {
+                result1 = null;
+
+                if (reportFailures === 0) {
+                  matchFailed("\"!\"");
+                }
+              }
+
+              if (result1 === null) {
+                if (input.charCodeAt(pos) === 37) {
+                  result1 = "%";
+                  pos++;
+                } else {
+                  result1 = null;
+
+                  if (reportFailures === 0) {
+                    matchFailed("\"%\"");
+                  }
+                }
+
+                if (result1 === null) {
+                  if (input.charCodeAt(pos) === 42) {
+                    result1 = "*";
+                    pos++;
+                  } else {
+                    result1 = null;
+
+                    if (reportFailures === 0) {
+                      matchFailed("\"*\"");
+                    }
+                  }
+
+                  if (result1 === null) {
+                    if (input.charCodeAt(pos) === 95) {
+                      result1 = "_";
+                      pos++;
+                    } else {
+                      result1 = null;
+
+                      if (reportFailures === 0) {
+                        matchFailed("\"_\"");
+                      }
+                    }
+
+                    if (result1 === null) {
+                      if (input.charCodeAt(pos) === 43) {
+                        result1 = "+";
+                        pos++;
+                      } else {
+                        result1 = null;
+
+                        if (reportFailures === 0) {
+                          matchFailed("\"+\"");
+                        }
+                      }
+
+                      if (result1 === null) {
+                        if (input.charCodeAt(pos) === 96) {
+                          result1 = "`";
+                          pos++;
+                        } else {
+                          result1 = null;
+
+                          if (reportFailures === 0) {
+                            matchFailed("\"`\"");
+                          }
+                        }
+
+                        if (result1 === null) {
+                          if (input.charCodeAt(pos) === 39) {
+                            result1 = "'";
+                            pos++;
+                          } else {
+                            result1 = null;
+
+                            if (reportFailures === 0) {
+                              matchFailed("\"'\"");
+                            }
+                          }
+
+                          if (result1 === null) {
+                            if (input.charCodeAt(pos) === 126) {
+                              result1 = "~";
+                              pos++;
+                            } else {
+                              result1 = null;
+
+                              if (reportFailures === 0) {
+                                matchFailed("\"~\"");
+                              }
+                            }
+                          }
+                        }
+                      }
+                    }
+                  }
+                }
+              }
+            }
+          }
+        }
+
+        if (result1 !== null) {
+          result0 = [];
+
+          while (result1 !== null) {
+            result0.push(result1);
+            result1 = parse_alphanum();
+
+            if (result1 === null) {
+              if (input.charCodeAt(pos) === 45) {
+                result1 = "-";
+                pos++;
+              } else {
+                result1 = null;
+
+                if (reportFailures === 0) {
+                  matchFailed("\"-\"");
+                }
+              }
+
+              if (result1 === null) {
+                if (input.charCodeAt(pos) === 46) {
+                  result1 = ".";
+                  pos++;
+                } else {
+                  result1 = null;
+
+                  if (reportFailures === 0) {
+                    matchFailed("\".\"");
+                  }
+                }
+
+                if (result1 === null) {
+                  if (input.charCodeAt(pos) === 33) {
+                    result1 = "!";
+                    pos++;
+                  } else {
+                    result1 = null;
+
+                    if (reportFailures === 0) {
+                      matchFailed("\"!\"");
+                    }
+                  }
+
+                  if (result1 === null) {
+                    if (input.charCodeAt(pos) === 37) {
+                      result1 = "%";
+                      pos++;
+                    } else {
+                      result1 = null;
+
+                      if (reportFailures === 0) {
+                        matchFailed("\"%\"");
+                      }
+                    }
+
+                    if (result1 === null) {
+                      if (input.charCodeAt(pos) === 42) {
+                        result1 = "*";
+                        pos++;
+                      } else {
+                        result1 = null;
+
+                        if (reportFailures === 0) {
+                          matchFailed("\"*\"");
+                        }
+                      }
+
+                      if (result1 === null) {
+                        if (input.charCodeAt(pos) === 95) {
+                          result1 = "_";
+                          pos++;
+                        } else {
+                          result1 = null;
+
+                          if (reportFailures === 0) {
+                            matchFailed("\"_\"");
+                          }
+                        }
+
+                        if (result1 === null) {
+                          if (input.charCodeAt(pos) === 43) {
+                            result1 = "+";
+                            pos++;
+                          } else {
+                            result1 = null;
+
+                            if (reportFailures === 0) {
+                              matchFailed("\"+\"");
+                            }
+                          }
+
+                          if (result1 === null) {
+                            if (input.charCodeAt(pos) === 96) {
+                              result1 = "`";
+                              pos++;
+                            } else {
+                              result1 = null;
+
+                              if (reportFailures === 0) {
+                                matchFailed("\"`\"");
+                              }
+                            }
+
+                            if (result1 === null) {
+                              if (input.charCodeAt(pos) === 39) {
+                                result1 = "'";
+                                pos++;
+                              } else {
+                                result1 = null;
+
+                                if (reportFailures === 0) {
+                                  matchFailed("\"'\"");
+                                }
+                              }
+
+                              if (result1 === null) {
+                                if (input.charCodeAt(pos) === 126) {
+                                  result1 = "~";
+                                  pos++;
+                                } else {
+                                  result1 = null;
+
+                                  if (reportFailures === 0) {
+                                    matchFailed("\"~\"");
+                                  }
+                                }
+                              }
+                            }
+                          }
+                        }
+                      }
+                    }
+                  }
+                }
+              }
+            }
+          }
+        } else {
+          result0 = null;
+        }
+
+        if (result0 !== null) {
+          result0 = function (offset) {
+            return input.substring(pos, offset);
+          }(pos0);
+        }
+
+        if (result0 === null) {
+          pos = pos0;
+        }
+
+        return result0;
+      }
+
+      function parse_token_nodot() {
+        var result0, result1;
+        var pos0;
+        pos0 = pos;
+        result1 = parse_alphanum();
+
+        if (result1 === null) {
+          if (input.charCodeAt(pos) === 45) {
+            result1 = "-";
+            pos++;
+          } else {
+            result1 = null;
+
+            if (reportFailures === 0) {
+              matchFailed("\"-\"");
+            }
+          }
+
+          if (result1 === null) {
+            if (input.charCodeAt(pos) === 33) {
+              result1 = "!";
+              pos++;
+            } else {
+              result1 = null;
+
+              if (reportFailures === 0) {
+                matchFailed("\"!\"");
+              }
+            }
+
+            if (result1 === null) {
+              if (input.charCodeAt(pos) === 37) {
+                result1 = "%";
+                pos++;
+              } else {
+                result1 = null;
+
+                if (reportFailures === 0) {
+                  matchFailed("\"%\"");
+                }
+              }
+
+              if (result1 === null) {
+                if (input.charCodeAt(pos) === 42) {
+                  result1 = "*";
+                  pos++;
+                } else {
+                  result1 = null;
+
+                  if (reportFailures === 0) {
+                    matchFailed("\"*\"");
+                  }
+                }
+
+                if (result1 === null) {
+                  if (input.charCodeAt(pos) === 95) {
+                    result1 = "_";
+                    pos++;
+                  } else {
+                    result1 = null;
+
+                    if (reportFailures === 0) {
+                      matchFailed("\"_\"");
+                    }
+                  }
+
+                  if (result1 === null) {
+                    if (input.charCodeAt(pos) === 43) {
+                      result1 = "+";
+                      pos++;
+                    } else {
+                      result1 = null;
+
+                      if (reportFailures === 0) {
+                        matchFailed("\"+\"");
+                      }
+                    }
+
+                    if (result1 === null) {
+                      if (input.charCodeAt(pos) === 96) {
+                        result1 = "`";
+                        pos++;
+                      } else {
+                        result1 = null;
+
+                        if (reportFailures === 0) {
+                          matchFailed("\"`\"");
+                        }
+                      }
+
+                      if (result1 === null) {
+                        if (input.charCodeAt(pos) === 39) {
+                          result1 = "'";
+                          pos++;
+                        } else {
+                          result1 = null;
+
+                          if (reportFailures === 0) {
+                            matchFailed("\"'\"");
+                          }
+                        }
+
+                        if (result1 === null) {
+                          if (input.charCodeAt(pos) === 126) {
+                            result1 = "~";
+                            pos++;
+                          } else {
+                            result1 = null;
+
+                            if (reportFailures === 0) {
+                              matchFailed("\"~\"");
+                            }
+                          }
+                        }
+                      }
+                    }
+                  }
+                }
+              }
+            }
+          }
+        }
+
+        if (result1 !== null) {
+          result0 = [];
+
+          while (result1 !== null) {
+            result0.push(result1);
+            result1 = parse_alphanum();
+
+            if (result1 === null) {
+              if (input.charCodeAt(pos) === 45) {
+                result1 = "-";
+                pos++;
+              } else {
+                result1 = null;
+
+                if (reportFailures === 0) {
+                  matchFailed("\"-\"");
+                }
+              }
+
+              if (result1 === null) {
+                if (input.charCodeAt(pos) === 33) {
+                  result1 = "!";
+                  pos++;
+                } else {
+                  result1 = null;
+
+                  if (reportFailures === 0) {
+                    matchFailed("\"!\"");
+                  }
+                }
+
+                if (result1 === null) {
+                  if (input.charCodeAt(pos) === 37) {
+                    result1 = "%";
+                    pos++;
+                  } else {
+                    result1 = null;
+
+                    if (reportFailures === 0) {
+                      matchFailed("\"%\"");
+                    }
+                  }
+
+                  if (result1 === null) {
+                    if (input.charCodeAt(pos) === 42) {
+                      result1 = "*";
+                      pos++;
+                    } else {
+                      result1 = null;
+
+                      if (reportFailures === 0) {
+                        matchFailed("\"*\"");
+                      }
+                    }
+
+                    if (result1 === null) {
+                      if (input.charCodeAt(pos) === 95) {
+                        result1 = "_";
+                        pos++;
+                      } else {
+                        result1 = null;
+
+                        if (reportFailures === 0) {
+                          matchFailed("\"_\"");
+                        }
+                      }
+
+                      if (result1 === null) {
+                        if (input.charCodeAt(pos) === 43) {
+                          result1 = "+";
+                          pos++;
+                        } else {
+                          result1 = null;
+
+                          if (reportFailures === 0) {
+                            matchFailed("\"+\"");
+                          }
+                        }
+
+                        if (result1 === null) {
+                          if (input.charCodeAt(pos) === 96) {
+                            result1 = "`";
+                            pos++;
+                          } else {
+                            result1 = null;
+
+                            if (reportFailures === 0) {
+                              matchFailed("\"`\"");
+                            }
+                          }
+
+                          if (result1 === null) {
+                            if (input.charCodeAt(pos) === 39) {
+                              result1 = "'";
+                              pos++;
+                            } else {
+                              result1 = null;
+
+                              if (reportFailures === 0) {
+                                matchFailed("\"'\"");
+                              }
+                            }
+
+                            if (result1 === null) {
+                              if (input.charCodeAt(pos) === 126) {
+                                result1 = "~";
+                                pos++;
+                              } else {
+                                result1 = null;
+
+                                if (reportFailures === 0) {
+                                  matchFailed("\"~\"");
+                                }
+                              }
+                            }
+                          }
+                        }
+                      }
+                    }
+                  }
+                }
+              }
+            }
+          }
+        } else {
+          result0 = null;
+        }
+
+        if (result0 !== null) {
+          result0 = function (offset) {
+            return input.substring(pos, offset);
+          }(pos0);
+        }
+
+        if (result0 === null) {
+          pos = pos0;
+        }
+
+        return result0;
+      }
+
+      function parse_separators() {
+        var result0;
+
+        if (input.charCodeAt(pos) === 40) {
+          result0 = "(";
+          pos++;
+        } else {
+          result0 = null;
+
+          if (reportFailures === 0) {
+            matchFailed("\"(\"");
+          }
+        }
+
+        if (result0 === null) {
+          if (input.charCodeAt(pos) === 41) {
+            result0 = ")";
+            pos++;
+          } else {
+            result0 = null;
+
+            if (reportFailures === 0) {
+              matchFailed("\")\"");
+            }
+          }
+
+          if (result0 === null) {
+            if (input.charCodeAt(pos) === 60) {
+              result0 = "<";
+              pos++;
+            } else {
+              result0 = null;
+
+              if (reportFailures === 0) {
+                matchFailed("\"<\"");
+              }
+            }
+
+            if (result0 === null) {
+              if (input.charCodeAt(pos) === 62) {
+                result0 = ">";
+                pos++;
+              } else {
+                result0 = null;
+
+                if (reportFailures === 0) {
+                  matchFailed("\">\"");
+                }
+              }
+
+              if (result0 === null) {
+                if (input.charCodeAt(pos) === 64) {
+                  result0 = "@";
+                  pos++;
+                } else {
+                  result0 = null;
+
+                  if (reportFailures === 0) {
+                    matchFailed("\"@\"");
+                  }
+                }
+
+                if (result0 === null) {
+                  if (input.charCodeAt(pos) === 44) {
+                    result0 = ",";
+                    pos++;
+                  } else {
+                    result0 = null;
+
+                    if (reportFailures === 0) {
+                      matchFailed("\",\"");
+                    }
+                  }
+
+                  if (result0 === null) {
+                    if (input.charCodeAt(pos) === 59) {
+                      result0 = ";";
+                      pos++;
+                    } else {
+                      result0 = null;
+
+                      if (reportFailures === 0) {
+                        matchFailed("\";\"");
+                      }
+                    }
+
+                    if (result0 === null) {
+                      if (input.charCodeAt(pos) === 58) {
+                        result0 = ":";
+                        pos++;
+                      } else {
+                        result0 = null;
+
+                        if (reportFailures === 0) {
+                          matchFailed("\":\"");
+                        }
+                      }
+
+                      if (result0 === null) {
+                        if (input.charCodeAt(pos) === 92) {
+                          result0 = "\\";
+                          pos++;
+                        } else {
+                          result0 = null;
+
+                          if (reportFailures === 0) {
+                            matchFailed("\"\\\\\"");
+                          }
+                        }
+
+                        if (result0 === null) {
+                          result0 = parse_DQUOTE();
+
+                          if (result0 === null) {
+                            if (input.charCodeAt(pos) === 47) {
+                              result0 = "/";
+                              pos++;
+                            } else {
+                              result0 = null;
+
+                              if (reportFailures === 0) {
+                                matchFailed("\"/\"");
+                              }
+                            }
+
+                            if (result0 === null) {
+                              if (input.charCodeAt(pos) === 91) {
+                                result0 = "[";
+                                pos++;
+                              } else {
+                                result0 = null;
+
+                                if (reportFailures === 0) {
+                                  matchFailed("\"[\"");
+                                }
+                              }
+
+                              if (result0 === null) {
+                                if (input.charCodeAt(pos) === 93) {
+                                  result0 = "]";
+                                  pos++;
+                                } else {
+                                  result0 = null;
+
+                                  if (reportFailures === 0) {
+                                    matchFailed("\"]\"");
+                                  }
+                                }
+
+                                if (result0 === null) {
+                                  if (input.charCodeAt(pos) === 63) {
+                                    result0 = "?";
+                                    pos++;
+                                  } else {
+                                    result0 = null;
+
+                                    if (reportFailures === 0) {
+                                      matchFailed("\"?\"");
+                                    }
+                                  }
+
+                                  if (result0 === null) {
+                                    if (input.charCodeAt(pos) === 61) {
+                                      result0 = "=";
+                                      pos++;
+                                    } else {
+                                      result0 = null;
+
+                                      if (reportFailures === 0) {
+                                        matchFailed("\"=\"");
+                                      }
+                                    }
+
+                                    if (result0 === null) {
+                                      if (input.charCodeAt(pos) === 123) {
+                                        result0 = "{";
+                                        pos++;
+                                      } else {
+                                        result0 = null;
+
+                                        if (reportFailures === 0) {
+                                          matchFailed("\"{\"");
+                                        }
+                                      }
+
+                                      if (result0 === null) {
+                                        if (input.charCodeAt(pos) === 125) {
+                                          result0 = "}";
+                                          pos++;
+                                        } else {
+                                          result0 = null;
+
+                                          if (reportFailures === 0) {
+                                            matchFailed("\"}\"");
+                                          }
+                                        }
+
+                                        if (result0 === null) {
+                                          result0 = parse_SP();
+
+                                          if (result0 === null) {
+                                            result0 = parse_HTAB();
+                                          }
+                                        }
+                                      }
+                                    }
+                                  }
+                                }
+                              }
+                            }
+                          }
+                        }
+                      }
+                    }
+                  }
+                }
+              }
+            }
+          }
+        }
+
+        return result0;
+      }
+
+      function parse_word() {
+        var result0, result1;
+        var pos0;
+        pos0 = pos;
+        result1 = parse_alphanum();
+
+        if (result1 === null) {
+          if (input.charCodeAt(pos) === 45) {
+            result1 = "-";
+            pos++;
+          } else {
+            result1 = null;
+
+            if (reportFailures === 0) {
+              matchFailed("\"-\"");
+            }
+          }
+
+          if (result1 === null) {
+            if (input.charCodeAt(pos) === 46) {
+              result1 = ".";
+              pos++;
+            } else {
+              result1 = null;
+
+              if (reportFailures === 0) {
+                matchFailed("\".\"");
+              }
+            }
+
+            if (result1 === null) {
+              if (input.charCodeAt(pos) === 33) {
+                result1 = "!";
+                pos++;
+              } else {
+                result1 = null;
+
+                if (reportFailures === 0) {
+                  matchFailed("\"!\"");
+                }
+              }
+
+              if (result1 === null) {
+                if (input.charCodeAt(pos) === 37) {
+                  result1 = "%";
+                  pos++;
+                } else {
+                  result1 = null;
+
+                  if (reportFailures === 0) {
+                    matchFailed("\"%\"");
+                  }
+                }
+
+                if (result1 === null) {
+                  if (input.charCodeAt(pos) === 42) {
+                    result1 = "*";
+                    pos++;
+                  } else {
+                    result1 = null;
+
+                    if (reportFailures === 0) {
+                      matchFailed("\"*\"");
+                    }
+                  }
+
+                  if (result1 === null) {
+                    if (input.charCodeAt(pos) === 95) {
+                      result1 = "_";
+                      pos++;
+                    } else {
+                      result1 = null;
+
+                      if (reportFailures === 0) {
+                        matchFailed("\"_\"");
+                      }
+                    }
+
+                    if (result1 === null) {
+                      if (input.charCodeAt(pos) === 43) {
+                        result1 = "+";
+                        pos++;
+                      } else {
+                        result1 = null;
+
+                        if (reportFailures === 0) {
+                          matchFailed("\"+\"");
+                        }
+                      }
+
+                      if (result1 === null) {
+                        if (input.charCodeAt(pos) === 96) {
+                          result1 = "`";
+                          pos++;
+                        } else {
+                          result1 = null;
+
+                          if (reportFailures === 0) {
+                            matchFailed("\"`\"");
+                          }
+                        }
+
+                        if (result1 === null) {
+                          if (input.charCodeAt(pos) === 39) {
+                            result1 = "'";
+                            pos++;
+                          } else {
+                            result1 = null;
+
+                            if (reportFailures === 0) {
+                              matchFailed("\"'\"");
+                            }
+                          }
+
+                          if (result1 === null) {
+                            if (input.charCodeAt(pos) === 126) {
+                              result1 = "~";
+                              pos++;
+                            } else {
+                              result1 = null;
+
+                              if (reportFailures === 0) {
+                                matchFailed("\"~\"");
+                              }
+                            }
+
+                            if (result1 === null) {
+                              if (input.charCodeAt(pos) === 40) {
+                                result1 = "(";
+                                pos++;
+                              } else {
+                                result1 = null;
+
+                                if (reportFailures === 0) {
+                                  matchFailed("\"(\"");
+                                }
+                              }
+
+                              if (result1 === null) {
+                                if (input.charCodeAt(pos) === 41) {
+                                  result1 = ")";
+                                  pos++;
+                                } else {
+                                  result1 = null;
+
+                                  if (reportFailures === 0) {
+                                    matchFailed("\")\"");
+                                  }
+                                }
+
+                                if (result1 === null) {
+                                  if (input.charCodeAt(pos) === 60) {
+                                    result1 = "<";
+                                    pos++;
+                                  } else {
+                                    result1 = null;
+
+                                    if (reportFailures === 0) {
+                                      matchFailed("\"<\"");
+                                    }
+                                  }
+
+                                  if (result1 === null) {
+                                    if (input.charCodeAt(pos) === 62) {
+                                      result1 = ">";
+                                      pos++;
+                                    } else {
+                                      result1 = null;
+
+                                      if (reportFailures === 0) {
+                                        matchFailed("\">\"");
+                                      }
+                                    }
+
+                                    if (result1 === null) {
+                                      if (input.charCodeAt(pos) === 58) {
+                                        result1 = ":";
+                                        pos++;
+                                      } else {
+                                        result1 = null;
+
+                                        if (reportFailures === 0) {
+                                          matchFailed("\":\"");
+                                        }
+                                      }
+
+                                      if (result1 === null) {
+                                        if (input.charCodeAt(pos) === 92) {
+                                          result1 = "\\";
+                                          pos++;
+                                        } else {
+                                          result1 = null;
+
+                                          if (reportFailures === 0) {
+                                            matchFailed("\"\\\\\"");
+                                          }
+                                        }
+
+                                        if (result1 === null) {
+                                          result1 = parse_DQUOTE();
+
+                                          if (result1 === null) {
+                                            if (input.charCodeAt(pos) === 47) {
+                                              result1 = "/";
+                                              pos++;
+                                            } else {
+                                              result1 = null;
+
+                                              if (reportFailures === 0) {
+                                                matchFailed("\"/\"");
+                                              }
+                                            }
+
+                                            if (result1 === null) {
+                                              if (input.charCodeAt(pos) === 91) {
+                                                result1 = "[";
+                                                pos++;
+                                              } else {
+                                                result1 = null;
+
+                                                if (reportFailures === 0) {
+                                                  matchFailed("\"[\"");
+                                                }
+                                              }
+
+                                              if (result1 === null) {
+                                                if (input.charCodeAt(pos) === 93) {
+                                                  result1 = "]";
+                                                  pos++;
+                                                } else {
+                                                  result1 = null;
+
+                                                  if (reportFailures === 0) {
+                                                    matchFailed("\"]\"");
+                                                  }
+                                                }
+
+                                                if (result1 === null) {
+                                                  if (input.charCodeAt(pos) === 63) {
+                                                    result1 = "?";
+                                                    pos++;
+                                                  } else {
+                                                    result1 = null;
+
+                                                    if (reportFailures === 0) {
+                                                      matchFailed("\"?\"");
+                                                    }
+                                                  }
+
+                                                  if (result1 === null) {
+                                                    if (input.charCodeAt(pos) === 123) {
+                                                      result1 = "{";
+                                                      pos++;
+                                                    } else {
+                                                      result1 = null;
+
+                                                      if (reportFailures === 0) {
+                                                        matchFailed("\"{\"");
+                                                      }
+                                                    }
+
+                                                    if (result1 === null) {
+                                                      if (input.charCodeAt(pos) === 125) {
+                                                        result1 = "}";
+                                                        pos++;
+                                                      } else {
+                                                        result1 = null;
+
+                                                        if (reportFailures === 0) {
+                                                          matchFailed("\"}\"");
+                                                        }
+                                                      }
+                                                    }
+                                                  }
+                                                }
+                                              }
+                                            }
+                                          }
+                                        }
+                                      }
+                                    }
+                                  }
+                                }
+                              }
+                            }
+                          }
+                        }
+                      }
+                    }
+                  }
+                }
+              }
+            }
+          }
+        }
+
+        if (result1 !== null) {
+          result0 = [];
+
+          while (result1 !== null) {
+            result0.push(result1);
+            result1 = parse_alphanum();
+
+            if (result1 === null) {
+              if (input.charCodeAt(pos) === 45) {
+                result1 = "-";
+                pos++;
+              } else {
+                result1 = null;
+
+                if (reportFailures === 0) {
+                  matchFailed("\"-\"");
+                }
+              }
+
+              if (result1 === null) {
+                if (input.charCodeAt(pos) === 46) {
+                  result1 = ".";
+                  pos++;
+                } else {
+                  result1 = null;
+
+                  if (reportFailures === 0) {
+                    matchFailed("\".\"");
+                  }
+                }
+
+                if (result1 === null) {
+                  if (input.charCodeAt(pos) === 33) {
+                    result1 = "!";
+                    pos++;
+                  } else {
+                    result1 = null;
+
+                    if (reportFailures === 0) {
+                      matchFailed("\"!\"");
+                    }
+                  }
+
+                  if (result1 === null) {
+                    if (input.charCodeAt(pos) === 37) {
+                      result1 = "%";
+                      pos++;
+                    } else {
+                      result1 = null;
+
+                      if (reportFailures === 0) {
+                        matchFailed("\"%\"");
+                      }
+                    }
+
+                    if (result1 === null) {
+                      if (input.charCodeAt(pos) === 42) {
+                        result1 = "*";
+                        pos++;
+                      } else {
+                        result1 = null;
+
+                        if (reportFailures === 0) {
+                          matchFailed("\"*\"");
+                        }
+                      }
+
+                      if (result1 === null) {
+                        if (input.charCodeAt(pos) === 95) {
+                          result1 = "_";
+                          pos++;
+                        } else {
+                          result1 = null;
+
+                          if (reportFailures === 0) {
+                            matchFailed("\"_\"");
+                          }
+                        }
+
+                        if (result1 === null) {
+                          if (input.charCodeAt(pos) === 43) {
+                            result1 = "+";
+                            pos++;
+                          } else {
+                            result1 = null;
+
+                            if (reportFailures === 0) {
+                              matchFailed("\"+\"");
+                            }
+                          }
+
+                          if (result1 === null) {
+                            if (input.charCodeAt(pos) === 96) {
+                              result1 = "`";
+                              pos++;
+                            } else {
+                              result1 = null;
+
+                              if (reportFailures === 0) {
+                                matchFailed("\"`\"");
+                              }
+                            }
+
+                            if (result1 === null) {
+                              if (input.charCodeAt(pos) === 39) {
+                                result1 = "'";
+                                pos++;
+                              } else {
+                                result1 = null;
+
+                                if (reportFailures === 0) {
+                                  matchFailed("\"'\"");
+                                }
+                              }
+
+                              if (result1 === null) {
+                                if (input.charCodeAt(pos) === 126) {
+                                  result1 = "~";
+                                  pos++;
+                                } else {
+                                  result1 = null;
+
+                                  if (reportFailures === 0) {
+                                    matchFailed("\"~\"");
+                                  }
+                                }
+
+                                if (result1 === null) {
+                                  if (input.charCodeAt(pos) === 40) {
+                                    result1 = "(";
+                                    pos++;
+                                  } else {
+                                    result1 = null;
+
+                                    if (reportFailures === 0) {
+                                      matchFailed("\"(\"");
+                                    }
+                                  }
+
+                                  if (result1 === null) {
+                                    if (input.charCodeAt(pos) === 41) {
+                                      result1 = ")";
+                                      pos++;
+                                    } else {
+                                      result1 = null;
+
+                                      if (reportFailures === 0) {
+                                        matchFailed("\")\"");
+                                      }
+                                    }
+
+                                    if (result1 === null) {
+                                      if (input.charCodeAt(pos) === 60) {
+                                        result1 = "<";
+                                        pos++;
+                                      } else {
+                                        result1 = null;
+
+                                        if (reportFailures === 0) {
+                                          matchFailed("\"<\"");
+                                        }
+                                      }
+
+                                      if (result1 === null) {
+                                        if (input.charCodeAt(pos) === 62) {
+                                          result1 = ">";
+                                          pos++;
+                                        } else {
+                                          result1 = null;
+
+                                          if (reportFailures === 0) {
+                                            matchFailed("\">\"");
+                                          }
+                                        }
+
+                                        if (result1 === null) {
+                                          if (input.charCodeAt(pos) === 58) {
+                                            result1 = ":";
+                                            pos++;
+                                          } else {
+                                            result1 = null;
+
+                                            if (reportFailures === 0) {
+                                              matchFailed("\":\"");
+                                            }
+                                          }
+
+                                          if (result1 === null) {
+                                            if (input.charCodeAt(pos) === 92) {
+                                              result1 = "\\";
+                                              pos++;
+                                            } else {
+                                              result1 = null;
+
+                                              if (reportFailures === 0) {
+                                                matchFailed("\"\\\\\"");
+                                              }
+                                            }
+
+                                            if (result1 === null) {
+                                              result1 = parse_DQUOTE();
+
+                                              if (result1 === null) {
+                                                if (input.charCodeAt(pos) === 47) {
+                                                  result1 = "/";
+                                                  pos++;
+                                                } else {
+                                                  result1 = null;
+
+                                                  if (reportFailures === 0) {
+                                                    matchFailed("\"/\"");
+                                                  }
+                                                }
+
+                                                if (result1 === null) {
+                                                  if (input.charCodeAt(pos) === 91) {
+                                                    result1 = "[";
+                                                    pos++;
+                                                  } else {
+                                                    result1 = null;
+
+                                                    if (reportFailures === 0) {
+                                                      matchFailed("\"[\"");
+                                                    }
+                                                  }
+
+                                                  if (result1 === null) {
+                                                    if (input.charCodeAt(pos) === 93) {
+                                                      result1 = "]";
+                                                      pos++;
+                                                    } else {
+                                                      result1 = null;
+
+                                                      if (reportFailures === 0) {
+                                                        matchFailed("\"]\"");
+                                                      }
+                                                    }
+
+                                                    if (result1 === null) {
+                                                      if (input.charCodeAt(pos) === 63) {
+                                                        result1 = "?";
+                                                        pos++;
+                                                      } else {
+                                                        result1 = null;
+
+                                                        if (reportFailures === 0) {
+                                                          matchFailed("\"?\"");
+                                                        }
+                                                      }
+
+                                                      if (result1 === null) {
+                                                        if (input.charCodeAt(pos) === 123) {
+                                                          result1 = "{";
+                                                          pos++;
+                                                        } else {
+                                                          result1 = null;
+
+                                                          if (reportFailures === 0) {
+                                                            matchFailed("\"{\"");
+                                                          }
+                                                        }
+
+                                                        if (result1 === null) {
+                                                          if (input.charCodeAt(pos) === 125) {
+                                                            result1 = "}";
+                                                            pos++;
+                                                          } else {
+                                                            result1 = null;
+
+                                                            if (reportFailures === 0) {
+                                                              matchFailed("\"}\"");
+                                                            }
+                                                          }
+                                                        }
+                                                      }
+                                                    }
+                                                  }
+                                                }
+                                              }
+                                            }
+                                          }
+                                        }
+                                      }
+                                    }
+                                  }
+                                }
+                              }
+                            }
+                          }
+                        }
+                      }
+                    }
+                  }
+                }
+              }
+            }
+          }
+        } else {
+          result0 = null;
+        }
+
+        if (result0 !== null) {
+          result0 = function (offset) {
+            return input.substring(pos, offset);
+          }(pos0);
+        }
+
+        if (result0 === null) {
+          pos = pos0;
+        }
+
+        return result0;
+      }
+
+      function parse_STAR() {
+        var result0, result1, result2;
+        var pos0, pos1;
+        pos0 = pos;
+        pos1 = pos;
+        result0 = parse_SWS();
+
+        if (result0 !== null) {
+          if (input.charCodeAt(pos) === 42) {
+            result1 = "*";
+            pos++;
+          } else {
+            result1 = null;
+
+            if (reportFailures === 0) {
+              matchFailed("\"*\"");
+            }
+          }
+
+          if (result1 !== null) {
+            result2 = parse_SWS();
+
+            if (result2 !== null) {
+              result0 = [result0, result1, result2];
+            } else {
+              result0 = null;
+              pos = pos1;
+            }
+          } else {
+            result0 = null;
+            pos = pos1;
+          }
+        } else {
+          result0 = null;
+          pos = pos1;
+        }
+
+        if (result0 !== null) {
+          result0 = function (offset) {
+            return "*";
+          }(pos0);
+        }
+
+        if (result0 === null) {
+          pos = pos0;
+        }
+
+        return result0;
+      }
+
+      function parse_SLASH() {
+        var result0, result1, result2;
+        var pos0, pos1;
+        pos0 = pos;
+        pos1 = pos;
+        result0 = parse_SWS();
+
+        if (result0 !== null) {
+          if (input.charCodeAt(pos) === 47) {
+            result1 = "/";
+            pos++;
+          } else {
+            result1 = null;
+
+            if (reportFailures === 0) {
+              matchFailed("\"/\"");
+            }
+          }
+
+          if (result1 !== null) {
+            result2 = parse_SWS();
+
+            if (result2 !== null) {
+              result0 = [result0, result1, result2];
+            } else {
+              result0 = null;
+              pos = pos1;
+            }
+          } else {
+            result0 = null;
+            pos = pos1;
+          }
+        } else {
+          result0 = null;
+          pos = pos1;
+        }
+
+        if (result0 !== null) {
+          result0 = function (offset) {
+            return "/";
+          }(pos0);
+        }
+
+        if (result0 === null) {
+          pos = pos0;
+        }
+
+        return result0;
+      }
+
+      function parse_EQUAL() {
+        var result0, result1, result2;
+        var pos0, pos1;
+        pos0 = pos;
+        pos1 = pos;
+        result0 = parse_SWS();
+
+        if (result0 !== null) {
+          if (input.charCodeAt(pos) === 61) {
+            result1 = "=";
+            pos++;
+          } else {
+            result1 = null;
+
+            if (reportFailures === 0) {
+              matchFailed("\"=\"");
+            }
+          }
+
+          if (result1 !== null) {
+            result2 = parse_SWS();
+
+            if (result2 !== null) {
+              result0 = [result0, result1, result2];
+            } else {
+              result0 = null;
+              pos = pos1;
+            }
+          } else {
+            result0 = null;
+            pos = pos1;
+          }
+        } else {
+          result0 = null;
+          pos = pos1;
+        }
+
+        if (result0 !== null) {
+          result0 = function (offset) {
+            return "=";
+          }(pos0);
+        }
+
+        if (result0 === null) {
+          pos = pos0;
+        }
+
+        return result0;
+      }
+
+      function parse_LPAREN() {
+        var result0, result1, result2;
+        var pos0, pos1;
+        pos0 = pos;
+        pos1 = pos;
+        result0 = parse_SWS();
+
+        if (result0 !== null) {
+          if (input.charCodeAt(pos) === 40) {
+            result1 = "(";
+            pos++;
+          } else {
+            result1 = null;
+
+            if (reportFailures === 0) {
+              matchFailed("\"(\"");
+            }
+          }
+
+          if (result1 !== null) {
+            result2 = parse_SWS();
+
+            if (result2 !== null) {
+              result0 = [result0, result1, result2];
+            } else {
+              result0 = null;
+              pos = pos1;
+            }
+          } else {
+            result0 = null;
+            pos = pos1;
+          }
+        } else {
+          result0 = null;
+          pos = pos1;
+        }
+
+        if (result0 !== null) {
+          result0 = function (offset) {
+            return "(";
+          }(pos0);
+        }
+
+        if (result0 === null) {
+          pos = pos0;
+        }
+
+        return result0;
+      }
+
+      function parse_RPAREN() {
+        var result0, result1, result2;
+        var pos0, pos1;
+        pos0 = pos;
+        pos1 = pos;
+        result0 = parse_SWS();
+
+        if (result0 !== null) {
+          if (input.charCodeAt(pos) === 41) {
+            result1 = ")";
+            pos++;
+          } else {
+            result1 = null;
+
+            if (reportFailures === 0) {
+              matchFailed("\")\"");
+            }
+          }
+
+          if (result1 !== null) {
+            result2 = parse_SWS();
+
+            if (result2 !== null) {
+              result0 = [result0, result1, result2];
+            } else {
+              result0 = null;
+              pos = pos1;
+            }
+          } else {
+            result0 = null;
+            pos = pos1;
+          }
+        } else {
+          result0 = null;
+          pos = pos1;
+        }
+
+        if (result0 !== null) {
+          result0 = function (offset) {
+            return ")";
+          }(pos0);
+        }
+
+        if (result0 === null) {
+          pos = pos0;
+        }
+
+        return result0;
+      }
+
+      function parse_RAQUOT() {
+        var result0, result1;
+        var pos0, pos1;
+        pos0 = pos;
+        pos1 = pos;
+
+        if (input.charCodeAt(pos) === 62) {
+          result0 = ">";
+          pos++;
+        } else {
+          result0 = null;
+
+          if (reportFailures === 0) {
+            matchFailed("\">\"");
+          }
+        }
+
+        if (result0 !== null) {
+          result1 = parse_SWS();
+
+          if (result1 !== null) {
+            result0 = [result0, result1];
+          } else {
+            result0 = null;
+            pos = pos1;
+          }
+        } else {
+          result0 = null;
+          pos = pos1;
+        }
+
+        if (result0 !== null) {
+          result0 = function (offset) {
+            return ">";
+          }(pos0);
+        }
+
+        if (result0 === null) {
+          pos = pos0;
+        }
+
+        return result0;
+      }
+
+      function parse_LAQUOT() {
+        var result0, result1;
+        var pos0, pos1;
+        pos0 = pos;
+        pos1 = pos;
+        result0 = parse_SWS();
+
+        if (result0 !== null) {
+          if (input.charCodeAt(pos) === 60) {
+            result1 = "<";
+            pos++;
+          } else {
+            result1 = null;
+
+            if (reportFailures === 0) {
+              matchFailed("\"<\"");
+            }
+          }
+
+          if (result1 !== null) {
+            result0 = [result0, result1];
+          } else {
+            result0 = null;
+            pos = pos1;
+          }
+        } else {
+          result0 = null;
+          pos = pos1;
+        }
+
+        if (result0 !== null) {
+          result0 = function (offset) {
+            return "<";
+          }(pos0);
+        }
+
+        if (result0 === null) {
+          pos = pos0;
+        }
+
+        return result0;
+      }
+
+      function parse_COMMA() {
+        var result0, result1, result2;
+        var pos0, pos1;
+        pos0 = pos;
+        pos1 = pos;
+        result0 = parse_SWS();
+
+        if (result0 !== null) {
+          if (input.charCodeAt(pos) === 44) {
+            result1 = ",";
+            pos++;
+          } else {
+            result1 = null;
+
+            if (reportFailures === 0) {
+              matchFailed("\",\"");
+            }
+          }
+
+          if (result1 !== null) {
+            result2 = parse_SWS();
+
+            if (result2 !== null) {
+              result0 = [result0, result1, result2];
+            } else {
+              result0 = null;
+              pos = pos1;
+            }
+          } else {
+            result0 = null;
+            pos = pos1;
+          }
+        } else {
+          result0 = null;
+          pos = pos1;
+        }
+
+        if (result0 !== null) {
+          result0 = function (offset) {
+            return ",";
+          }(pos0);
+        }
+
+        if (result0 === null) {
+          pos = pos0;
+        }
+
+        return result0;
+      }
+
+      function parse_SEMI() {
+        var result0, result1, result2;
+        var pos0, pos1;
+        pos0 = pos;
+        pos1 = pos;
+        result0 = parse_SWS();
+
+        if (result0 !== null) {
+          if (input.charCodeAt(pos) === 59) {
+            result1 = ";";
+            pos++;
+          } else {
+            result1 = null;
+
+            if (reportFailures === 0) {
+              matchFailed("\";\"");
+            }
+          }
+
+          if (result1 !== null) {
+            result2 = parse_SWS();
+
+            if (result2 !== null) {
+              result0 = [result0, result1, result2];
+            } else {
+              result0 = null;
+              pos = pos1;
+            }
+          } else {
+            result0 = null;
+            pos = pos1;
+          }
+        } else {
+          result0 = null;
+          pos = pos1;
+        }
+
+        if (result0 !== null) {
+          result0 = function (offset) {
+            return ";";
+          }(pos0);
+        }
+
+        if (result0 === null) {
+          pos = pos0;
+        }
+
+        return result0;
+      }
+
+      function parse_COLON() {
+        var result0, result1, result2;
+        var pos0, pos1;
+        pos0 = pos;
+        pos1 = pos;
+        result0 = parse_SWS();
+
+        if (result0 !== null) {
+          if (input.charCodeAt(pos) === 58) {
+            result1 = ":";
+            pos++;
+          } else {
+            result1 = null;
+
+            if (reportFailures === 0) {
+              matchFailed("\":\"");
+            }
+          }
+
+          if (result1 !== null) {
+            result2 = parse_SWS();
+
+            if (result2 !== null) {
+              result0 = [result0, result1, result2];
+            } else {
+              result0 = null;
+              pos = pos1;
+            }
+          } else {
+            result0 = null;
+            pos = pos1;
+          }
+        } else {
+          result0 = null;
+          pos = pos1;
+        }
+
+        if (result0 !== null) {
+          result0 = function (offset) {
+            return ":";
+          }(pos0);
+        }
+
+        if (result0 === null) {
+          pos = pos0;
+        }
+
+        return result0;
+      }
+
+      function parse_LDQUOT() {
+        var result0, result1;
+        var pos0, pos1;
+        pos0 = pos;
+        pos1 = pos;
+        result0 = parse_SWS();
+
+        if (result0 !== null) {
+          result1 = parse_DQUOTE();
+
+          if (result1 !== null) {
+            result0 = [result0, result1];
+          } else {
+            result0 = null;
+            pos = pos1;
+          }
+        } else {
+          result0 = null;
+          pos = pos1;
+        }
+
+        if (result0 !== null) {
+          result0 = function (offset) {
+            return "\"";
+          }(pos0);
+        }
+
+        if (result0 === null) {
+          pos = pos0;
+        }
+
+        return result0;
+      }
+
+      function parse_RDQUOT() {
+        var result0, result1;
+        var pos0, pos1;
+        pos0 = pos;
+        pos1 = pos;
+        result0 = parse_DQUOTE();
+
+        if (result0 !== null) {
+          result1 = parse_SWS();
+
+          if (result1 !== null) {
+            result0 = [result0, result1];
+          } else {
+            result0 = null;
+            pos = pos1;
+          }
+        } else {
+          result0 = null;
+          pos = pos1;
+        }
+
+        if (result0 !== null) {
+          result0 = function (offset) {
+            return "\"";
+          }(pos0);
+        }
+
+        if (result0 === null) {
+          pos = pos0;
+        }
+
+        return result0;
+      }
+
+      function parse_comment() {
+        var result0, result1, result2;
+        var pos0;
+        pos0 = pos;
+        result0 = parse_LPAREN();
+
+        if (result0 !== null) {
+          result1 = [];
+          result2 = parse_ctext();
+
+          if (result2 === null) {
+            result2 = parse_quoted_pair();
+
+            if (result2 === null) {
+              result2 = parse_comment();
+            }
+          }
+
+          while (result2 !== null) {
+            result1.push(result2);
+            result2 = parse_ctext();
+
+            if (result2 === null) {
+              result2 = parse_quoted_pair();
+
+              if (result2 === null) {
+                result2 = parse_comment();
+              }
+            }
+          }
+
+          if (result1 !== null) {
+            result2 = parse_RPAREN();
+
+            if (result2 !== null) {
+              result0 = [result0, result1, result2];
+            } else {
+              result0 = null;
+              pos = pos0;
+            }
+          } else {
+            result0 = null;
+            pos = pos0;
+          }
+        } else {
+          result0 = null;
+          pos = pos0;
+        }
+
+        return result0;
+      }
+
+      function parse_ctext() {
+        var result0;
+
+        if (/^[!-']/.test(input.charAt(pos))) {
+          result0 = input.charAt(pos);
+          pos++;
+        } else {
+          result0 = null;
+
+          if (reportFailures === 0) {
+            matchFailed("[!-']");
+          }
+        }
+
+        if (result0 === null) {
+          if (/^[*-[]/.test(input.charAt(pos))) {
+            result0 = input.charAt(pos);
+            pos++;
+          } else {
+            result0 = null;
+
+            if (reportFailures === 0) {
+              matchFailed("[*-[]");
+            }
+          }
+
+          if (result0 === null) {
+            if (/^[\]-~]/.test(input.charAt(pos))) {
+              result0 = input.charAt(pos);
+              pos++;
+            } else {
+              result0 = null;
+
+              if (reportFailures === 0) {
+                matchFailed("[\\]-~]");
+              }
+            }
+
+            if (result0 === null) {
+              result0 = parse_UTF8_NONASCII();
+
+              if (result0 === null) {
+                result0 = parse_LWS();
+              }
+            }
+          }
+        }
+
+        return result0;
+      }
+
+      function parse_quoted_string() {
+        var result0, result1, result2, result3;
+        var pos0, pos1;
+        pos0 = pos;
+        pos1 = pos;
+        result0 = parse_SWS();
+
+        if (result0 !== null) {
+          result1 = parse_DQUOTE();
+
+          if (result1 !== null) {
+            result2 = [];
+            result3 = parse_qdtext();
+
+            if (result3 === null) {
+              result3 = parse_quoted_pair();
+            }
+
+            while (result3 !== null) {
+              result2.push(result3);
+              result3 = parse_qdtext();
+
+              if (result3 === null) {
+                result3 = parse_quoted_pair();
+              }
+            }
+
+            if (result2 !== null) {
+              result3 = parse_DQUOTE();
+
+              if (result3 !== null) {
+                result0 = [result0, result1, result2, result3];
+              } else {
+                result0 = null;
+                pos = pos1;
+              }
+            } else {
+              result0 = null;
+              pos = pos1;
+            }
+          } else {
+            result0 = null;
+            pos = pos1;
+          }
+        } else {
+          result0 = null;
+          pos = pos1;
+        }
+
+        if (result0 !== null) {
+          result0 = function (offset) {
+            return input.substring(pos, offset);
+          }(pos0);
+        }
+
+        if (result0 === null) {
+          pos = pos0;
+        }
+
+        return result0;
+      }
+
+      function parse_quoted_string_clean() {
+        var result0, result1, result2, result3;
+        var pos0, pos1;
+        pos0 = pos;
+        pos1 = pos;
+        result0 = parse_SWS();
+
+        if (result0 !== null) {
+          result1 = parse_DQUOTE();
+
+          if (result1 !== null) {
+            result2 = [];
+            result3 = parse_qdtext();
+
+            if (result3 === null) {
+              result3 = parse_quoted_pair();
+            }
+
+            while (result3 !== null) {
+              result2.push(result3);
+              result3 = parse_qdtext();
+
+              if (result3 === null) {
+                result3 = parse_quoted_pair();
+              }
+            }
+
+            if (result2 !== null) {
+              result3 = parse_DQUOTE();
+
+              if (result3 !== null) {
+                result0 = [result0, result1, result2, result3];
+              } else {
+                result0 = null;
+                pos = pos1;
+              }
+            } else {
+              result0 = null;
+              pos = pos1;
+            }
+          } else {
+            result0 = null;
+            pos = pos1;
+          }
+        } else {
+          result0 = null;
+          pos = pos1;
+        }
+
+        if (result0 !== null) {
+          result0 = function (offset) {
+            var trimmed = input.substring(pos, offset).trim();
+            return trimmed.substring(1, trimmed.length - 1) // remove outer quotes
+            .replace(/\\([\x00-\x09\x0b-\x0c\x0e-\x7f])/g, '$1');
+          }(pos0);
+        }
+
+        if (result0 === null) {
+          pos = pos0;
+        }
+
+        return result0;
+      }
+
+      function parse_qdtext() {
+        var result0;
+        result0 = parse_LWS();
+
+        if (result0 === null) {
+          if (input.charCodeAt(pos) === 33) {
+            result0 = "!";
+            pos++;
+          } else {
+            result0 = null;
+
+            if (reportFailures === 0) {
+              matchFailed("\"!\"");
+            }
+          }
+
+          if (result0 === null) {
+            if (/^[#-[]/.test(input.charAt(pos))) {
+              result0 = input.charAt(pos);
+              pos++;
+            } else {
+              result0 = null;
+
+              if (reportFailures === 0) {
+                matchFailed("[#-[]");
+              }
+            }
+
+            if (result0 === null) {
+              if (/^[\]-~]/.test(input.charAt(pos))) {
+                result0 = input.charAt(pos);
+                pos++;
+              } else {
+                result0 = null;
+
+                if (reportFailures === 0) {
+                  matchFailed("[\\]-~]");
+                }
+              }
+
+              if (result0 === null) {
+                result0 = parse_UTF8_NONASCII();
+              }
+            }
+          }
+        }
+
+        return result0;
+      }
+
+      function parse_quoted_pair() {
+        var result0, result1;
+        var pos0;
+        pos0 = pos;
+
+        if (input.charCodeAt(pos) === 92) {
+          result0 = "\\";
+          pos++;
+        } else {
+          result0 = null;
+
+          if (reportFailures === 0) {
+            matchFailed("\"\\\\\"");
+          }
+        }
+
+        if (result0 !== null) {
+          if (/^[\0-\t]/.test(input.charAt(pos))) {
+            result1 = input.charAt(pos);
+            pos++;
+          } else {
+            result1 = null;
+
+            if (reportFailures === 0) {
+              matchFailed("[\\0-\\t]");
+            }
+          }
+
+          if (result1 === null) {
+            if (/^[\x0B-\f]/.test(input.charAt(pos))) {
+              result1 = input.charAt(pos);
+              pos++;
+            } else {
+              result1 = null;
+
+              if (reportFailures === 0) {
+                matchFailed("[\\x0B-\\f]");
+              }
+            }
+
+            if (result1 === null) {
+              if (/^[\x0E-]/.test(input.charAt(pos))) {
+                result1 = input.charAt(pos);
+                pos++;
+              } else {
+                result1 = null;
+
+                if (reportFailures === 0) {
+                  matchFailed("[\\x0E-]");
+                }
+              }
+            }
+          }
+
+          if (result1 !== null) {
+            result0 = [result0, result1];
+          } else {
+            result0 = null;
+            pos = pos0;
+          }
+        } else {
+          result0 = null;
+          pos = pos0;
+        }
+
+        return result0;
+      }
+
+      function parse_SIP_URI_noparams() {
+        var result0, result1, result2, result3;
+        var pos0, pos1;
+        pos0 = pos;
+        pos1 = pos;
+        result0 = parse_uri_scheme();
+
+        if (result0 !== null) {
+          if (input.charCodeAt(pos) === 58) {
+            result1 = ":";
+            pos++;
+          } else {
+            result1 = null;
+
+            if (reportFailures === 0) {
+              matchFailed("\":\"");
+            }
+          }
+
+          if (result1 !== null) {
+            result2 = parse_userinfo();
+            result2 = result2 !== null ? result2 : "";
+
+            if (result2 !== null) {
+              result3 = parse_hostport();
+
+              if (result3 !== null) {
+                result0 = [result0, result1, result2, result3];
+              } else {
+                result0 = null;
+                pos = pos1;
+              }
+            } else {
+              result0 = null;
+              pos = pos1;
+            }
+          } else {
+            result0 = null;
+            pos = pos1;
+          }
+        } else {
+          result0 = null;
+          pos = pos1;
+        }
+
+        if (result0 !== null) {
+          result0 = function (offset) {
+            try {
+              data.uri = new URI(data.scheme, data.user, data.host, data.port);
+              delete data.scheme;
+              delete data.user;
+              delete data.host;
+              delete data.host_type;
+              delete data.port;
+            } catch (e) {
+              data = -1;
+            }
+          }(pos0);
+        }
+
+        if (result0 === null) {
+          pos = pos0;
+        }
+
+        return result0;
+      }
+
+      function parse_SIP_URI() {
+        var result0, result1, result2, result3, result4, result5;
+        var pos0, pos1;
+        pos0 = pos;
+        pos1 = pos;
+        result0 = parse_uri_scheme();
+
+        if (result0 !== null) {
+          if (input.charCodeAt(pos) === 58) {
+            result1 = ":";
+            pos++;
+          } else {
+            result1 = null;
+
+            if (reportFailures === 0) {
+              matchFailed("\":\"");
+            }
+          }
+
+          if (result1 !== null) {
+            result2 = parse_userinfo();
+            result2 = result2 !== null ? result2 : "";
+
+            if (result2 !== null) {
+              result3 = parse_hostport();
+
+              if (result3 !== null) {
+                result4 = parse_uri_parameters();
+
+                if (result4 !== null) {
+                  result5 = parse_headers();
+                  result5 = result5 !== null ? result5 : "";
+
+                  if (result5 !== null) {
+                    result0 = [result0, result1, result2, result3, result4, result5];
+                  } else {
+                    result0 = null;
+                    pos = pos1;
+                  }
+                } else {
+                  result0 = null;
+                  pos = pos1;
+                }
+              } else {
+                result0 = null;
+                pos = pos1;
+              }
+            } else {
+              result0 = null;
+              pos = pos1;
+            }
+          } else {
+            result0 = null;
+            pos = pos1;
+          }
+        } else {
+          result0 = null;
+          pos = pos1;
+        }
+
+        if (result0 !== null) {
+          result0 = function (offset) {
+            var header;
+
+            try {
+              data.uri = new URI(data.scheme, data.user, data.host, data.port, data.uri_params, data.uri_headers);
+              delete data.scheme;
+              delete data.user;
+              delete data.host;
+              delete data.host_type;
+              delete data.port;
+              delete data.uri_params;
+
+              if (startRule === 'SIP_URI') {
+                data = data.uri;
+              }
+            } catch (e) {
+              data = -1;
+            }
+          }(pos0);
+        }
+
+        if (result0 === null) {
+          pos = pos0;
+        }
+
+        return result0;
+      }
+
+      function parse_uri_scheme() {
+        var result0;
+        result0 = parse_uri_scheme_sips();
+
+        if (result0 === null) {
+          result0 = parse_uri_scheme_sip();
+        }
+
+        return result0;
+      }
+
+      function parse_uri_scheme_sips() {
+        var result0;
+        var pos0;
+        pos0 = pos;
+
+        if (input.substr(pos, 4).toLowerCase() === "sips") {
+          result0 = input.substr(pos, 4);
+          pos += 4;
+        } else {
+          result0 = null;
+
+          if (reportFailures === 0) {
+            matchFailed("\"sips\"");
+          }
+        }
+
+        if (result0 !== null) {
+          result0 = function (offset, scheme) {
+            data.scheme = scheme.toLowerCase();
+          }(pos0, result0);
+        }
+
+        if (result0 === null) {
+          pos = pos0;
+        }
+
+        return result0;
+      }
+
+      function parse_uri_scheme_sip() {
+        var result0;
+        var pos0;
+        pos0 = pos;
+
+        if (input.substr(pos, 3).toLowerCase() === "sip") {
+          result0 = input.substr(pos, 3);
+          pos += 3;
+        } else {
+          result0 = null;
+
+          if (reportFailures === 0) {
+            matchFailed("\"sip\"");
+          }
+        }
+
+        if (result0 !== null) {
+          result0 = function (offset, scheme) {
+            data.scheme = scheme.toLowerCase();
+          }(pos0, result0);
+        }
+
+        if (result0 === null) {
+          pos = pos0;
+        }
+
+        return result0;
+      }
+
+      function parse_userinfo() {
+        var result0, result1, result2;
+        var pos0, pos1, pos2;
+        pos0 = pos;
+        pos1 = pos;
+        result0 = parse_user();
+
+        if (result0 !== null) {
+          pos2 = pos;
+
+          if (input.charCodeAt(pos) === 58) {
+            result1 = ":";
+            pos++;
+          } else {
+            result1 = null;
+
+            if (reportFailures === 0) {
+              matchFailed("\":\"");
+            }
+          }
+
+          if (result1 !== null) {
+            result2 = parse_password();
+
+            if (result2 !== null) {
+              result1 = [result1, result2];
+            } else {
+              result1 = null;
+              pos = pos2;
+            }
+          } else {
+            result1 = null;
+            pos = pos2;
+          }
+
+          result1 = result1 !== null ? result1 : "";
+
+          if (result1 !== null) {
+            if (input.charCodeAt(pos) === 64) {
+              result2 = "@";
+              pos++;
+            } else {
+              result2 = null;
+
+              if (reportFailures === 0) {
+                matchFailed("\"@\"");
+              }
+            }
+
+            if (result2 !== null) {
+              result0 = [result0, result1, result2];
+            } else {
+              result0 = null;
+              pos = pos1;
+            }
+          } else {
+            result0 = null;
+            pos = pos1;
+          }
+        } else {
+          result0 = null;
+          pos = pos1;
+        }
+
+        if (result0 !== null) {
+          result0 = function (offset) {
+            data.user = decodeURIComponent(input.substring(pos - 1, offset));
+          }(pos0);
+        }
+
+        if (result0 === null) {
+          pos = pos0;
+        }
+
+        return result0;
+      }
+
+      function parse_user() {
+        var result0, result1;
+        result1 = parse_unreserved();
+
+        if (result1 === null) {
+          result1 = parse_escaped();
+
+          if (result1 === null) {
+            result1 = parse_user_unreserved();
+          }
+        }
+
+        if (result1 !== null) {
+          result0 = [];
+
+          while (result1 !== null) {
+            result0.push(result1);
+            result1 = parse_unreserved();
+
+            if (result1 === null) {
+              result1 = parse_escaped();
+
+              if (result1 === null) {
+                result1 = parse_user_unreserved();
+              }
+            }
+          }
+        } else {
+          result0 = null;
+        }
+
+        return result0;
+      }
+
+      function parse_user_unreserved() {
+        var result0;
+
+        if (input.charCodeAt(pos) === 38) {
+          result0 = "&";
+          pos++;
+        } else {
+          result0 = null;
+
+          if (reportFailures === 0) {
+            matchFailed("\"&\"");
+          }
+        }
+
+        if (result0 === null) {
+          if (input.charCodeAt(pos) === 61) {
+            result0 = "=";
+            pos++;
+          } else {
+            result0 = null;
+
+            if (reportFailures === 0) {
+              matchFailed("\"=\"");
+            }
+          }
+
+          if (result0 === null) {
+            if (input.charCodeAt(pos) === 43) {
+              result0 = "+";
+              pos++;
+            } else {
+              result0 = null;
+
+              if (reportFailures === 0) {
+                matchFailed("\"+\"");
+              }
+            }
+
+            if (result0 === null) {
+              if (input.charCodeAt(pos) === 36) {
+                result0 = "$";
+                pos++;
+              } else {
+                result0 = null;
+
+                if (reportFailures === 0) {
+                  matchFailed("\"$\"");
+                }
+              }
+
+              if (result0 === null) {
+                if (input.charCodeAt(pos) === 44) {
+                  result0 = ",";
+                  pos++;
+                } else {
+                  result0 = null;
+
+                  if (reportFailures === 0) {
+                    matchFailed("\",\"");
+                  }
+                }
+
+                if (result0 === null) {
+                  if (input.charCodeAt(pos) === 59) {
+                    result0 = ";";
+                    pos++;
+                  } else {
+                    result0 = null;
+
+                    if (reportFailures === 0) {
+                      matchFailed("\";\"");
+                    }
+                  }
+
+                  if (result0 === null) {
+                    if (input.charCodeAt(pos) === 63) {
+                      result0 = "?";
+                      pos++;
+                    } else {
+                      result0 = null;
+
+                      if (reportFailures === 0) {
+                        matchFailed("\"?\"");
+                      }
+                    }
+
+                    if (result0 === null) {
+                      if (input.charCodeAt(pos) === 47) {
+                        result0 = "/";
+                        pos++;
+                      } else {
+                        result0 = null;
+
+                        if (reportFailures === 0) {
+                          matchFailed("\"/\"");
+                        }
+                      }
+                    }
+                  }
+                }
+              }
+            }
+          }
+        }
+
+        return result0;
+      }
+
+      function parse_password() {
+        var result0, result1;
+        var pos0;
+        pos0 = pos;
+        result0 = [];
+        result1 = parse_unreserved();
+
+        if (result1 === null) {
+          result1 = parse_escaped();
+
+          if (result1 === null) {
+            if (input.charCodeAt(pos) === 38) {
+              result1 = "&";
+              pos++;
+            } else {
+              result1 = null;
+
+              if (reportFailures === 0) {
+                matchFailed("\"&\"");
+              }
+            }
+
+            if (result1 === null) {
+              if (input.charCodeAt(pos) === 61) {
+                result1 = "=";
+                pos++;
+              } else {
+                result1 = null;
+
+                if (reportFailures === 0) {
+                  matchFailed("\"=\"");
+                }
+              }
+
+              if (result1 === null) {
+                if (input.charCodeAt(pos) === 43) {
+                  result1 = "+";
+                  pos++;
+                } else {
+                  result1 = null;
+
+                  if (reportFailures === 0) {
+                    matchFailed("\"+\"");
+                  }
+                }
+
+                if (result1 === null) {
+                  if (input.charCodeAt(pos) === 36) {
+                    result1 = "$";
+                    pos++;
+                  } else {
+                    result1 = null;
+
+                    if (reportFailures === 0) {
+                      matchFailed("\"$\"");
+                    }
+                  }
+
+                  if (result1 === null) {
+                    if (input.charCodeAt(pos) === 44) {
+                      result1 = ",";
+                      pos++;
+                    } else {
+                      result1 = null;
+
+                      if (reportFailures === 0) {
+                        matchFailed("\",\"");
+                      }
+                    }
+                  }
+                }
+              }
+            }
+          }
+        }
+
+        while (result1 !== null) {
+          result0.push(result1);
+          result1 = parse_unreserved();
+
+          if (result1 === null) {
+            result1 = parse_escaped();
+
+            if (result1 === null) {
+              if (input.charCodeAt(pos) === 38) {
+                result1 = "&";
+                pos++;
+              } else {
+                result1 = null;
+
+                if (reportFailures === 0) {
+                  matchFailed("\"&\"");
+                }
+              }
+
+              if (result1 === null) {
+                if (input.charCodeAt(pos) === 61) {
+                  result1 = "=";
+                  pos++;
+                } else {
+                  result1 = null;
+
+                  if (reportFailures === 0) {
+                    matchFailed("\"=\"");
+                  }
+                }
+
+                if (result1 === null) {
+                  if (input.charCodeAt(pos) === 43) {
+                    result1 = "+";
+                    pos++;
+                  } else {
+                    result1 = null;
+
+                    if (reportFailures === 0) {
+                      matchFailed("\"+\"");
+                    }
+                  }
+
+                  if (result1 === null) {
+                    if (input.charCodeAt(pos) === 36) {
+                      result1 = "$";
+                      pos++;
+                    } else {
+                      result1 = null;
+
+                      if (reportFailures === 0) {
+                        matchFailed("\"$\"");
+                      }
+                    }
+
+                    if (result1 === null) {
+                      if (input.charCodeAt(pos) === 44) {
+                        result1 = ",";
+                        pos++;
+                      } else {
+                        result1 = null;
+
+                        if (reportFailures === 0) {
+                          matchFailed("\",\"");
+                        }
+                      }
+                    }
+                  }
+                }
+              }
+            }
+          }
+        }
+
+        if (result0 !== null) {
+          result0 = function (offset) {
+            data.password = input.substring(pos, offset);
+          }(pos0);
+        }
+
+        if (result0 === null) {
+          pos = pos0;
+        }
+
+        return result0;
+      }
+
+      function parse_hostport() {
+        var result0, result1, result2;
+        var pos0, pos1;
+        pos0 = pos;
+        result0 = parse_host();
+
+        if (result0 !== null) {
+          pos1 = pos;
+
+          if (input.charCodeAt(pos) === 58) {
+            result1 = ":";
+            pos++;
+          } else {
+            result1 = null;
+
+            if (reportFailures === 0) {
+              matchFailed("\":\"");
+            }
+          }
+
+          if (result1 !== null) {
+            result2 = parse_port();
+
+            if (result2 !== null) {
+              result1 = [result1, result2];
+            } else {
+              result1 = null;
+              pos = pos1;
+            }
+          } else {
+            result1 = null;
+            pos = pos1;
+          }
+
+          result1 = result1 !== null ? result1 : "";
+
+          if (result1 !== null) {
+            result0 = [result0, result1];
+          } else {
+            result0 = null;
+            pos = pos0;
+          }
+        } else {
+          result0 = null;
+          pos = pos0;
+        }
+
+        return result0;
+      }
+
+      function parse_host() {
+        var result0;
+        var pos0;
+        pos0 = pos;
+        result0 = parse_hostname();
+
+        if (result0 === null) {
+          result0 = parse_IPv4address();
+
+          if (result0 === null) {
+            result0 = parse_IPv6reference();
+          }
+        }
+
+        if (result0 !== null) {
+          result0 = function (offset) {
+            data.host = input.substring(pos, offset).toLowerCase();
+            return data.host;
+          }(pos0);
+        }
+
+        if (result0 === null) {
+          pos = pos0;
+        }
+
+        return result0;
+      }
+
+      function parse_hostname() {
+        var result0, result1, result2;
+        var pos0, pos1, pos2;
+        pos0 = pos;
+        pos1 = pos;
+        result0 = [];
+        pos2 = pos;
+        result1 = parse_domainlabel();
+
+        if (result1 !== null) {
+          if (input.charCodeAt(pos) === 46) {
+            result2 = ".";
+            pos++;
+          } else {
+            result2 = null;
+
+            if (reportFailures === 0) {
+              matchFailed("\".\"");
+            }
+          }
+
+          if (result2 !== null) {
+            result1 = [result1, result2];
+          } else {
+            result1 = null;
+            pos = pos2;
+          }
+        } else {
+          result1 = null;
+          pos = pos2;
+        }
+
+        while (result1 !== null) {
+          result0.push(result1);
+          pos2 = pos;
+          result1 = parse_domainlabel();
+
+          if (result1 !== null) {
+            if (input.charCodeAt(pos) === 46) {
+              result2 = ".";
+              pos++;
+            } else {
+              result2 = null;
+
+              if (reportFailures === 0) {
+                matchFailed("\".\"");
+              }
+            }
+
+            if (result2 !== null) {
+              result1 = [result1, result2];
+            } else {
+              result1 = null;
+              pos = pos2;
+            }
+          } else {
+            result1 = null;
+            pos = pos2;
+          }
+        }
+
+        if (result0 !== null) {
+          result1 = parse_toplabel();
+
+          if (result1 !== null) {
+            if (input.charCodeAt(pos) === 46) {
+              result2 = ".";
+              pos++;
+            } else {
+              result2 = null;
+
+              if (reportFailures === 0) {
+                matchFailed("\".\"");
+              }
+            }
+
+            result2 = result2 !== null ? result2 : "";
+
+            if (result2 !== null) {
+              result0 = [result0, result1, result2];
+            } else {
+              result0 = null;
+              pos = pos1;
+            }
+          } else {
+            result0 = null;
+            pos = pos1;
+          }
+        } else {
+          result0 = null;
+          pos = pos1;
+        }
+
+        if (result0 !== null) {
+          result0 = function (offset) {
+            data.host_type = 'domain';
+            return input.substring(pos, offset);
+          }(pos0);
+        }
+
+        if (result0 === null) {
+          pos = pos0;
+        }
+
+        return result0;
+      }
+
+      function parse_domainlabel() {
+        var result0, result1, result2;
+        var pos0;
+        pos0 = pos;
+        result0 = parse_alphanum();
+
+        if (result0 !== null) {
+          result1 = [];
+          result2 = parse_alphanum();
+
+          if (result2 === null) {
+            if (input.charCodeAt(pos) === 45) {
+              result2 = "-";
+              pos++;
+            } else {
+              result2 = null;
+
+              if (reportFailures === 0) {
+                matchFailed("\"-\"");
+              }
+            }
+
+            if (result2 === null) {
+              if (input.charCodeAt(pos) === 95) {
+                result2 = "_";
+                pos++;
+              } else {
+                result2 = null;
+
+                if (reportFailures === 0) {
+                  matchFailed("\"_\"");
+                }
+              }
+            }
+          }
+
+          while (result2 !== null) {
+            result1.push(result2);
+            result2 = parse_alphanum();
+
+            if (result2 === null) {
+              if (input.charCodeAt(pos) === 45) {
+                result2 = "-";
+                pos++;
+              } else {
+                result2 = null;
+
+                if (reportFailures === 0) {
+                  matchFailed("\"-\"");
+                }
+              }
+
+              if (result2 === null) {
+                if (input.charCodeAt(pos) === 95) {
+                  result2 = "_";
+                  pos++;
+                } else {
+                  result2 = null;
+
+                  if (reportFailures === 0) {
+                    matchFailed("\"_\"");
+                  }
+                }
+              }
+            }
+          }
+
+          if (result1 !== null) {
+            result0 = [result0, result1];
+          } else {
+            result0 = null;
+            pos = pos0;
+          }
+        } else {
+          result0 = null;
+          pos = pos0;
+        }
+
+        return result0;
+      }
+
+      function parse_toplabel() {
+        var result0, result1, result2;
+        var pos0;
+        pos0 = pos;
+        result0 = parse_ALPHA();
+
+        if (result0 !== null) {
+          result1 = [];
+          result2 = parse_alphanum();
+
+          if (result2 === null) {
+            if (input.charCodeAt(pos) === 45) {
+              result2 = "-";
+              pos++;
+            } else {
+              result2 = null;
+
+              if (reportFailures === 0) {
+                matchFailed("\"-\"");
+              }
+            }
+
+            if (result2 === null) {
+              if (input.charCodeAt(pos) === 95) {
+                result2 = "_";
+                pos++;
+              } else {
+                result2 = null;
+
+                if (reportFailures === 0) {
+                  matchFailed("\"_\"");
+                }
+              }
+            }
+          }
+
+          while (result2 !== null) {
+            result1.push(result2);
+            result2 = parse_alphanum();
+
+            if (result2 === null) {
+              if (input.charCodeAt(pos) === 45) {
+                result2 = "-";
+                pos++;
+              } else {
+                result2 = null;
+
+                if (reportFailures === 0) {
+                  matchFailed("\"-\"");
+                }
+              }
+
+              if (result2 === null) {
+                if (input.charCodeAt(pos) === 95) {
+                  result2 = "_";
+                  pos++;
+                } else {
+                  result2 = null;
+
+                  if (reportFailures === 0) {
+                    matchFailed("\"_\"");
+                  }
+                }
+              }
+            }
+          }
+
+          if (result1 !== null) {
+            result0 = [result0, result1];
+          } else {
+            result0 = null;
+            pos = pos0;
+          }
+        } else {
+          result0 = null;
+          pos = pos0;
+        }
+
+        return result0;
+      }
+
+      function parse_IPv6reference() {
+        var result0, result1, result2;
+        var pos0, pos1;
+        pos0 = pos;
+        pos1 = pos;
+
+        if (input.charCodeAt(pos) === 91) {
+          result0 = "[";
+          pos++;
+        } else {
+          result0 = null;
+
+          if (reportFailures === 0) {
+            matchFailed("\"[\"");
+          }
+        }
+
+        if (result0 !== null) {
+          result1 = parse_IPv6address();
+
+          if (result1 !== null) {
+            if (input.charCodeAt(pos) === 93) {
+              result2 = "]";
+              pos++;
+            } else {
+              result2 = null;
+
+              if (reportFailures === 0) {
+                matchFailed("\"]\"");
+              }
+            }
+
+            if (result2 !== null) {
+              result0 = [result0, result1, result2];
+            } else {
+              result0 = null;
+              pos = pos1;
+            }
+          } else {
+            result0 = null;
+            pos = pos1;
+          }
+        } else {
+          result0 = null;
+          pos = pos1;
+        }
+
+        if (result0 !== null) {
+          result0 = function (offset) {
+            data.host_type = 'IPv6';
+            return input.substring(pos, offset);
+          }(pos0);
+        }
+
+        if (result0 === null) {
+          pos = pos0;
+        }
+
+        return result0;
+      }
+
+      function parse_IPv6address() {
+        var result0, result1, result2, result3, result4, result5, result6, result7, result8, result9, result10, result11, result12;
+        var pos0, pos1, pos2;
+        pos0 = pos;
+        pos1 = pos;
+        result0 = parse_h16();
+
+        if (result0 !== null) {
+          if (input.charCodeAt(pos) === 58) {
+            result1 = ":";
+            pos++;
+          } else {
+            result1 = null;
+
+            if (reportFailures === 0) {
+              matchFailed("\":\"");
+            }
+          }
+
+          if (result1 !== null) {
+            result2 = parse_h16();
+
+            if (result2 !== null) {
+              if (input.charCodeAt(pos) === 58) {
+                result3 = ":";
+                pos++;
+              } else {
+                result3 = null;
+
+                if (reportFailures === 0) {
+                  matchFailed("\":\"");
+                }
+              }
+
+              if (result3 !== null) {
+                result4 = parse_h16();
+
+                if (result4 !== null) {
+                  if (input.charCodeAt(pos) === 58) {
+                    result5 = ":";
+                    pos++;
+                  } else {
+                    result5 = null;
+
+                    if (reportFailures === 0) {
+                      matchFailed("\":\"");
+                    }
+                  }
+
+                  if (result5 !== null) {
+                    result6 = parse_h16();
+
+                    if (result6 !== null) {
+                      if (input.charCodeAt(pos) === 58) {
+                        result7 = ":";
+                        pos++;
+                      } else {
+                        result7 = null;
+
+                        if (reportFailures === 0) {
+                          matchFailed("\":\"");
+                        }
+                      }
+
+                      if (result7 !== null) {
+                        result8 = parse_h16();
+
+                        if (result8 !== null) {
+                          if (input.charCodeAt(pos) === 58) {
+                            result9 = ":";
+                            pos++;
+                          } else {
+                            result9 = null;
+
+                            if (reportFailures === 0) {
+                              matchFailed("\":\"");
+                            }
+                          }
+
+                          if (result9 !== null) {
+                            result10 = parse_h16();
+
+                            if (result10 !== null) {
+                              if (input.charCodeAt(pos) === 58) {
+                                result11 = ":";
+                                pos++;
+                              } else {
+                                result11 = null;
+
+                                if (reportFailures === 0) {
+                                  matchFailed("\":\"");
+                                }
+                              }
+
+                              if (result11 !== null) {
+                                result12 = parse_ls32();
+
+                                if (result12 !== null) {
+                                  result0 = [result0, result1, result2, result3, result4, result5, result6, result7, result8, result9, result10, result11, result12];
+                                } else {
+                                  result0 = null;
+                                  pos = pos1;
+                                }
+                              } else {
+                                result0 = null;
+                                pos = pos1;
+                              }
+                            } else {
+                              result0 = null;
+                              pos = pos1;
+                            }
+                          } else {
+                            result0 = null;
+                            pos = pos1;
+                          }
+                        } else {
+                          result0 = null;
+                          pos = pos1;
+                        }
+                      } else {
+                        result0 = null;
+                        pos = pos1;
+                      }
+                    } else {
+                      result0 = null;
+                      pos = pos1;
+                    }
+                  } else {
+                    result0 = null;
+                    pos = pos1;
+                  }
+                } else {
+                  result0 = null;
+                  pos = pos1;
+                }
+              } else {
+                result0 = null;
+                pos = pos1;
+              }
+            } else {
+              result0 = null;
+              pos = pos1;
+            }
+          } else {
+            result0 = null;
+            pos = pos1;
+          }
+        } else {
+          result0 = null;
+          pos = pos1;
+        }
+
+        if (result0 === null) {
+          pos1 = pos;
+
+          if (input.substr(pos, 2) === "::") {
+            result0 = "::";
+            pos += 2;
+          } else {
+            result0 = null;
+
+            if (reportFailures === 0) {
+              matchFailed("\"::\"");
+            }
+          }
+
+          if (result0 !== null) {
+            result1 = parse_h16();
+
+            if (result1 !== null) {
+              if (input.charCodeAt(pos) === 58) {
+                result2 = ":";
+                pos++;
+              } else {
+                result2 = null;
+
+                if (reportFailures === 0) {
+                  matchFailed("\":\"");
+                }
+              }
+
+              if (result2 !== null) {
+                result3 = parse_h16();
+
+                if (result3 !== null) {
+                  if (input.charCodeAt(pos) === 58) {
+                    result4 = ":";
+                    pos++;
+                  } else {
+                    result4 = null;
+
+                    if (reportFailures === 0) {
+                      matchFailed("\":\"");
+                    }
+                  }
+
+                  if (result4 !== null) {
+                    result5 = parse_h16();
+
+                    if (result5 !== null) {
+                      if (input.charCodeAt(pos) === 58) {
+                        result6 = ":";
+                        pos++;
+                      } else {
+                        result6 = null;
+
+                        if (reportFailures === 0) {
+                          matchFailed("\":\"");
+                        }
+                      }
+
+                      if (result6 !== null) {
+                        result7 = parse_h16();
+
+                        if (result7 !== null) {
+                          if (input.charCodeAt(pos) === 58) {
+                            result8 = ":";
+                            pos++;
+                          } else {
+                            result8 = null;
+
+                            if (reportFailures === 0) {
+                              matchFailed("\":\"");
+                            }
+                          }
+
+                          if (result8 !== null) {
+                            result9 = parse_h16();
+
+                            if (result9 !== null) {
+                              if (input.charCodeAt(pos) === 58) {
+                                result10 = ":";
+                                pos++;
+                              } else {
+                                result10 = null;
+
+                                if (reportFailures === 0) {
+                                  matchFailed("\":\"");
+                                }
+                              }
+
+                              if (result10 !== null) {
+                                result11 = parse_ls32();
+
+                                if (result11 !== null) {
+                                  result0 = [result0, result1, result2, result3, result4, result5, result6, result7, result8, result9, result10, result11];
+                                } else {
+                                  result0 = null;
+                                  pos = pos1;
+                                }
+                              } else {
+                                result0 = null;
+                                pos = pos1;
+                              }
+                            } else {
+                              result0 = null;
+                              pos = pos1;
+                            }
+                          } else {
+                            result0 = null;
+                            pos = pos1;
+                          }
+                        } else {
+                          result0 = null;
+                          pos = pos1;
+                        }
+                      } else {
+                        result0 = null;
+                        pos = pos1;
+                      }
+                    } else {
+                      result0 = null;
+                      pos = pos1;
+                    }
+                  } else {
+                    result0 = null;
+                    pos = pos1;
+                  }
+                } else {
+                  result0 = null;
+                  pos = pos1;
+                }
+              } else {
+                result0 = null;
+                pos = pos1;
+              }
+            } else {
+              result0 = null;
+              pos = pos1;
+            }
+          } else {
+            result0 = null;
+            pos = pos1;
+          }
+
+          if (result0 === null) {
+            pos1 = pos;
+
+            if (input.substr(pos, 2) === "::") {
+              result0 = "::";
+              pos += 2;
+            } else {
+              result0 = null;
+
+              if (reportFailures === 0) {
+                matchFailed("\"::\"");
+              }
+            }
+
+            if (result0 !== null) {
+              result1 = parse_h16();
+
+              if (result1 !== null) {
+                if (input.charCodeAt(pos) === 58) {
+                  result2 = ":";
+                  pos++;
+                } else {
+                  result2 = null;
+
+                  if (reportFailures === 0) {
+                    matchFailed("\":\"");
+                  }
+                }
+
+                if (result2 !== null) {
+                  result3 = parse_h16();
+
+                  if (result3 !== null) {
+                    if (input.charCodeAt(pos) === 58) {
+                      result4 = ":";
+                      pos++;
+                    } else {
+                      result4 = null;
+
+                      if (reportFailures === 0) {
+                        matchFailed("\":\"");
+                      }
+                    }
+
+                    if (result4 !== null) {
+                      result5 = parse_h16();
+
+                      if (result5 !== null) {
+                        if (input.charCodeAt(pos) === 58) {
+                          result6 = ":";
+                          pos++;
+                        } else {
+                          result6 = null;
+
+                          if (reportFailures === 0) {
+                            matchFailed("\":\"");
+                          }
+                        }
+
+                        if (result6 !== null) {
+                          result7 = parse_h16();
+
+                          if (result7 !== null) {
+                            if (input.charCodeAt(pos) === 58) {
+                              result8 = ":";
+                              pos++;
+                            } else {
+                              result8 = null;
+
+                              if (reportFailures === 0) {
+                                matchFailed("\":\"");
+                              }
+                            }
+
+                            if (result8 !== null) {
+                              result9 = parse_ls32();
+
+                              if (result9 !== null) {
+                                result0 = [result0, result1, result2, result3, result4, result5, result6, result7, result8, result9];
+                              } else {
+                                result0 = null;
+                                pos = pos1;
+                              }
+                            } else {
+                              result0 = null;
+                              pos = pos1;
+                            }
+                          } else {
+                            result0 = null;
+                            pos = pos1;
+                          }
+                        } else {
+                          result0 = null;
+                          pos = pos1;
+                        }
+                      } else {
+                        result0 = null;
+                        pos = pos1;
+                      }
+                    } else {
+                      result0 = null;
+                      pos = pos1;
+                    }
+                  } else {
+                    result0 = null;
+                    pos = pos1;
+                  }
+                } else {
+                  result0 = null;
+                  pos = pos1;
+                }
+              } else {
+                result0 = null;
+                pos = pos1;
+              }
+            } else {
+              result0 = null;
+              pos = pos1;
+            }
+
+            if (result0 === null) {
+              pos1 = pos;
+
+              if (input.substr(pos, 2) === "::") {
+                result0 = "::";
+                pos += 2;
+              } else {
+                result0 = null;
+
+                if (reportFailures === 0) {
+                  matchFailed("\"::\"");
+                }
+              }
+
+              if (result0 !== null) {
+                result1 = parse_h16();
+
+                if (result1 !== null) {
+                  if (input.charCodeAt(pos) === 58) {
+                    result2 = ":";
+                    pos++;
+                  } else {
+                    result2 = null;
+
+                    if (reportFailures === 0) {
+                      matchFailed("\":\"");
+                    }
+                  }
+
+                  if (result2 !== null) {
+                    result3 = parse_h16();
+
+                    if (result3 !== null) {
+                      if (input.charCodeAt(pos) === 58) {
+                        result4 = ":";
+                        pos++;
+                      } else {
+                        result4 = null;
+
+                        if (reportFailures === 0) {
+                          matchFailed("\":\"");
+                        }
+                      }
+
+                      if (result4 !== null) {
+                        result5 = parse_h16();
+
+                        if (result5 !== null) {
+                          if (input.charCodeAt(pos) === 58) {
+                            result6 = ":";
+                            pos++;
+                          } else {
+                            result6 = null;
+
+                            if (reportFailures === 0) {
+                              matchFailed("\":\"");
+                            }
+                          }
+
+                          if (result6 !== null) {
+                            result7 = parse_ls32();
+
+                            if (result7 !== null) {
+                              result0 = [result0, result1, result2, result3, result4, result5, result6, result7];
+                            } else {
+                              result0 = null;
+                              pos = pos1;
+                            }
+                          } else {
+                            result0 = null;
+                            pos = pos1;
+                          }
+                        } else {
+                          result0 = null;
+                          pos = pos1;
+                        }
+                      } else {
+                        result0 = null;
+                        pos = pos1;
+                      }
+                    } else {
+                      result0 = null;
+                      pos = pos1;
+                    }
+                  } else {
+                    result0 = null;
+                    pos = pos1;
+                  }
+                } else {
+                  result0 = null;
+                  pos = pos1;
+                }
+              } else {
+                result0 = null;
+                pos = pos1;
+              }
+
+              if (result0 === null) {
+                pos1 = pos;
+
+                if (input.substr(pos, 2) === "::") {
+                  result0 = "::";
+                  pos += 2;
+                } else {
+                  result0 = null;
+
+                  if (reportFailures === 0) {
+                    matchFailed("\"::\"");
+                  }
+                }
+
+                if (result0 !== null) {
+                  result1 = parse_h16();
+
+                  if (result1 !== null) {
+                    if (input.charCodeAt(pos) === 58) {
+                      result2 = ":";
+                      pos++;
+                    } else {
+                      result2 = null;
+
+                      if (reportFailures === 0) {
+                        matchFailed("\":\"");
+                      }
+                    }
+
+                    if (result2 !== null) {
+                      result3 = parse_h16();
+
+                      if (result3 !== null) {
+                        if (input.charCodeAt(pos) === 58) {
+                          result4 = ":";
+                          pos++;
+                        } else {
+                          result4 = null;
+
+                          if (reportFailures === 0) {
+                            matchFailed("\":\"");
+                          }
+                        }
+
+                        if (result4 !== null) {
+                          result5 = parse_ls32();
+
+                          if (result5 !== null) {
+                            result0 = [result0, result1, result2, result3, result4, result5];
+                          } else {
+                            result0 = null;
+                            pos = pos1;
+                          }
+                        } else {
+                          result0 = null;
+                          pos = pos1;
+                        }
+                      } else {
+                        result0 = null;
+                        pos = pos1;
+                      }
+                    } else {
+                      result0 = null;
+                      pos = pos1;
+                    }
+                  } else {
+                    result0 = null;
+                    pos = pos1;
+                  }
+                } else {
+                  result0 = null;
+                  pos = pos1;
+                }
+
+                if (result0 === null) {
+                  pos1 = pos;
+
+                  if (input.substr(pos, 2) === "::") {
+                    result0 = "::";
+                    pos += 2;
+                  } else {
+                    result0 = null;
+
+                    if (reportFailures === 0) {
+                      matchFailed("\"::\"");
+                    }
+                  }
+
+                  if (result0 !== null) {
+                    result1 = parse_h16();
+
+                    if (result1 !== null) {
+                      if (input.charCodeAt(pos) === 58) {
+                        result2 = ":";
+                        pos++;
+                      } else {
+                        result2 = null;
+
+                        if (reportFailures === 0) {
+                          matchFailed("\":\"");
+                        }
+                      }
+
+                      if (result2 !== null) {
+                        result3 = parse_ls32();
+
+                        if (result3 !== null) {
+                          result0 = [result0, result1, result2, result3];
+                        } else {
+                          result0 = null;
+                          pos = pos1;
+                        }
+                      } else {
+                        result0 = null;
+                        pos = pos1;
+                      }
+                    } else {
+                      result0 = null;
+                      pos = pos1;
+                    }
+                  } else {
+                    result0 = null;
+                    pos = pos1;
+                  }
+
+                  if (result0 === null) {
+                    pos1 = pos;
+
+                    if (input.substr(pos, 2) === "::") {
+                      result0 = "::";
+                      pos += 2;
+                    } else {
+                      result0 = null;
+
+                      if (reportFailures === 0) {
+                        matchFailed("\"::\"");
+                      }
+                    }
+
+                    if (result0 !== null) {
+                      result1 = parse_ls32();
+
+                      if (result1 !== null) {
+                        result0 = [result0, result1];
+                      } else {
+                        result0 = null;
+                        pos = pos1;
+                      }
+                    } else {
+                      result0 = null;
+                      pos = pos1;
+                    }
+
+                    if (result0 === null) {
+                      pos1 = pos;
+
+                      if (input.substr(pos, 2) === "::") {
+                        result0 = "::";
+                        pos += 2;
+                      } else {
+                        result0 = null;
+
+                        if (reportFailures === 0) {
+                          matchFailed("\"::\"");
+                        }
+                      }
+
+                      if (result0 !== null) {
+                        result1 = parse_h16();
+
+                        if (result1 !== null) {
+                          result0 = [result0, result1];
+                        } else {
+                          result0 = null;
+                          pos = pos1;
+                        }
+                      } else {
+                        result0 = null;
+                        pos = pos1;
+                      }
+
+                      if (result0 === null) {
+                        pos1 = pos;
+                        result0 = parse_h16();
+
+                        if (result0 !== null) {
+                          if (input.substr(pos, 2) === "::") {
+                            result1 = "::";
+                            pos += 2;
+                          } else {
+                            result1 = null;
+
+                            if (reportFailures === 0) {
+                              matchFailed("\"::\"");
+                            }
+                          }
+
+                          if (result1 !== null) {
+                            result2 = parse_h16();
+
+                            if (result2 !== null) {
+                              if (input.charCodeAt(pos) === 58) {
+                                result3 = ":";
+                                pos++;
+                              } else {
+                                result3 = null;
+
+                                if (reportFailures === 0) {
+                                  matchFailed("\":\"");
+                                }
+                              }
+
+                              if (result3 !== null) {
+                                result4 = parse_h16();
+
+                                if (result4 !== null) {
+                                  if (input.charCodeAt(pos) === 58) {
+                                    result5 = ":";
+                                    pos++;
+                                  } else {
+                                    result5 = null;
+
+                                    if (reportFailures === 0) {
+                                      matchFailed("\":\"");
+                                    }
+                                  }
+
+                                  if (result5 !== null) {
+                                    result6 = parse_h16();
+
+                                    if (result6 !== null) {
+                                      if (input.charCodeAt(pos) === 58) {
+                                        result7 = ":";
+                                        pos++;
+                                      } else {
+                                        result7 = null;
+
+                                        if (reportFailures === 0) {
+                                          matchFailed("\":\"");
+                                        }
+                                      }
+
+                                      if (result7 !== null) {
+                                        result8 = parse_h16();
+
+                                        if (result8 !== null) {
+                                          if (input.charCodeAt(pos) === 58) {
+                                            result9 = ":";
+                                            pos++;
+                                          } else {
+                                            result9 = null;
+
+                                            if (reportFailures === 0) {
+                                              matchFailed("\":\"");
+                                            }
+                                          }
+
+                                          if (result9 !== null) {
+                                            result10 = parse_ls32();
+
+                                            if (result10 !== null) {
+                                              result0 = [result0, result1, result2, result3, result4, result5, result6, result7, result8, result9, result10];
+                                            } else {
+                                              result0 = null;
+                                              pos = pos1;
+                                            }
+                                          } else {
+                                            result0 = null;
+                                            pos = pos1;
+                                          }
+                                        } else {
+                                          result0 = null;
+                                          pos = pos1;
+                                        }
+                                      } else {
+                                        result0 = null;
+                                        pos = pos1;
+                                      }
+                                    } else {
+                                      result0 = null;
+                                      pos = pos1;
+                                    }
+                                  } else {
+                                    result0 = null;
+                                    pos = pos1;
+                                  }
+                                } else {
+                                  result0 = null;
+                                  pos = pos1;
+                                }
+                              } else {
+                                result0 = null;
+                                pos = pos1;
+                              }
+                            } else {
+                              result0 = null;
+                              pos = pos1;
+                            }
+                          } else {
+                            result0 = null;
+                            pos = pos1;
+                          }
+                        } else {
+                          result0 = null;
+                          pos = pos1;
+                        }
+
+                        if (result0 === null) {
+                          pos1 = pos;
+                          result0 = parse_h16();
+
+                          if (result0 !== null) {
+                            pos2 = pos;
+
+                            if (input.charCodeAt(pos) === 58) {
+                              result1 = ":";
+                              pos++;
+                            } else {
+                              result1 = null;
+
+                              if (reportFailures === 0) {
+                                matchFailed("\":\"");
+                              }
+                            }
+
+                            if (result1 !== null) {
+                              result2 = parse_h16();
+
+                              if (result2 !== null) {
+                                result1 = [result1, result2];
+                              } else {
+                                result1 = null;
+                                pos = pos2;
+                              }
+                            } else {
+                              result1 = null;
+                              pos = pos2;
+                            }
+
+                            result1 = result1 !== null ? result1 : "";
+
+                            if (result1 !== null) {
+                              if (input.substr(pos, 2) === "::") {
+                                result2 = "::";
+                                pos += 2;
+                              } else {
+                                result2 = null;
+
+                                if (reportFailures === 0) {
+                                  matchFailed("\"::\"");
+                                }
+                              }
+
+                              if (result2 !== null) {
+                                result3 = parse_h16();
+
+                                if (result3 !== null) {
+                                  if (input.charCodeAt(pos) === 58) {
+                                    result4 = ":";
+                                    pos++;
+                                  } else {
+                                    result4 = null;
+
+                                    if (reportFailures === 0) {
+                                      matchFailed("\":\"");
+                                    }
+                                  }
+
+                                  if (result4 !== null) {
+                                    result5 = parse_h16();
+
+                                    if (result5 !== null) {
+                                      if (input.charCodeAt(pos) === 58) {
+                                        result6 = ":";
+                                        pos++;
+                                      } else {
+                                        result6 = null;
+
+                                        if (reportFailures === 0) {
+                                          matchFailed("\":\"");
+                                        }
+                                      }
+
+                                      if (result6 !== null) {
+                                        result7 = parse_h16();
+
+                                        if (result7 !== null) {
+                                          if (input.charCodeAt(pos) === 58) {
+                                            result8 = ":";
+                                            pos++;
+                                          } else {
+                                            result8 = null;
+
+                                            if (reportFailures === 0) {
+                                              matchFailed("\":\"");
+                                            }
+                                          }
+
+                                          if (result8 !== null) {
+                                            result9 = parse_ls32();
+
+                                            if (result9 !== null) {
+                                              result0 = [result0, result1, result2, result3, result4, result5, result6, result7, result8, result9];
+                                            } else {
+                                              result0 = null;
+                                              pos = pos1;
+                                            }
+                                          } else {
+                                            result0 = null;
+                                            pos = pos1;
+                                          }
+                                        } else {
+                                          result0 = null;
+                                          pos = pos1;
+                                        }
+                                      } else {
+                                        result0 = null;
+                                        pos = pos1;
+                                      }
+                                    } else {
+                                      result0 = null;
+                                      pos = pos1;
+                                    }
+                                  } else {
+                                    result0 = null;
+                                    pos = pos1;
+                                  }
+                                } else {
+                                  result0 = null;
+                                  pos = pos1;
+                                }
+                              } else {
+                                result0 = null;
+                                pos = pos1;
+                              }
+                            } else {
+                              result0 = null;
+                              pos = pos1;
+                            }
+                          } else {
+                            result0 = null;
+                            pos = pos1;
+                          }
+
+                          if (result0 === null) {
+                            pos1 = pos;
+                            result0 = parse_h16();
+
+                            if (result0 !== null) {
+                              pos2 = pos;
+
+                              if (input.charCodeAt(pos) === 58) {
+                                result1 = ":";
+                                pos++;
+                              } else {
+                                result1 = null;
+
+                                if (reportFailures === 0) {
+                                  matchFailed("\":\"");
+                                }
+                              }
+
+                              if (result1 !== null) {
+                                result2 = parse_h16();
+
+                                if (result2 !== null) {
+                                  result1 = [result1, result2];
+                                } else {
+                                  result1 = null;
+                                  pos = pos2;
+                                }
+                              } else {
+                                result1 = null;
+                                pos = pos2;
+                              }
+
+                              result1 = result1 !== null ? result1 : "";
+
+                              if (result1 !== null) {
+                                pos2 = pos;
+
+                                if (input.charCodeAt(pos) === 58) {
+                                  result2 = ":";
+                                  pos++;
+                                } else {
+                                  result2 = null;
+
+                                  if (reportFailures === 0) {
+                                    matchFailed("\":\"");
+                                  }
+                                }
+
+                                if (result2 !== null) {
+                                  result3 = parse_h16();
+
+                                  if (result3 !== null) {
+                                    result2 = [result2, result3];
+                                  } else {
+                                    result2 = null;
+                                    pos = pos2;
+                                  }
+                                } else {
+                                  result2 = null;
+                                  pos = pos2;
+                                }
+
+                                result2 = result2 !== null ? result2 : "";
+
+                                if (result2 !== null) {
+                                  if (input.substr(pos, 2) === "::") {
+                                    result3 = "::";
+                                    pos += 2;
+                                  } else {
+                                    result3 = null;
+
+                                    if (reportFailures === 0) {
+                                      matchFailed("\"::\"");
+                                    }
+                                  }
+
+                                  if (result3 !== null) {
+                                    result4 = parse_h16();
+
+                                    if (result4 !== null) {
+                                      if (input.charCodeAt(pos) === 58) {
+                                        result5 = ":";
+                                        pos++;
+                                      } else {
+                                        result5 = null;
+
+                                        if (reportFailures === 0) {
+                                          matchFailed("\":\"");
+                                        }
+                                      }
+
+                                      if (result5 !== null) {
+                                        result6 = parse_h16();
+
+                                        if (result6 !== null) {
+                                          if (input.charCodeAt(pos) === 58) {
+                                            result7 = ":";
+                                            pos++;
+                                          } else {
+                                            result7 = null;
+
+                                            if (reportFailures === 0) {
+                                              matchFailed("\":\"");
+                                            }
+                                          }
+
+                                          if (result7 !== null) {
+                                            result8 = parse_ls32();
+
+                                            if (result8 !== null) {
+                                              result0 = [result0, result1, result2, result3, result4, result5, result6, result7, result8];
+                                            } else {
+                                              result0 = null;
+                                              pos = pos1;
+                                            }
+                                          } else {
+                                            result0 = null;
+                                            pos = pos1;
+                                          }
+                                        } else {
+                                          result0 = null;
+                                          pos = pos1;
+                                        }
+                                      } else {
+                                        result0 = null;
+                                        pos = pos1;
+                                      }
+                                    } else {
+                                      result0 = null;
+                                      pos = pos1;
+                                    }
+                                  } else {
+                                    result0 = null;
+                                    pos = pos1;
+                                  }
+                                } else {
+                                  result0 = null;
+                                  pos = pos1;
+                                }
+                              } else {
+                                result0 = null;
+                                pos = pos1;
+                              }
+                            } else {
+                              result0 = null;
+                              pos = pos1;
+                            }
+
+                            if (result0 === null) {
+                              pos1 = pos;
+                              result0 = parse_h16();
+
+                              if (result0 !== null) {
+                                pos2 = pos;
+
+                                if (input.charCodeAt(pos) === 58) {
+                                  result1 = ":";
+                                  pos++;
+                                } else {
+                                  result1 = null;
+
+                                  if (reportFailures === 0) {
+                                    matchFailed("\":\"");
+                                  }
+                                }
+
+                                if (result1 !== null) {
+                                  result2 = parse_h16();
+
+                                  if (result2 !== null) {
+                                    result1 = [result1, result2];
+                                  } else {
+                                    result1 = null;
+                                    pos = pos2;
+                                  }
+                                } else {
+                                  result1 = null;
+                                  pos = pos2;
+                                }
+
+                                result1 = result1 !== null ? result1 : "";
+
+                                if (result1 !== null) {
+                                  pos2 = pos;
+
+                                  if (input.charCodeAt(pos) === 58) {
+                                    result2 = ":";
+                                    pos++;
+                                  } else {
+                                    result2 = null;
+
+                                    if (reportFailures === 0) {
+                                      matchFailed("\":\"");
+                                    }
+                                  }
+
+                                  if (result2 !== null) {
+                                    result3 = parse_h16();
+
+                                    if (result3 !== null) {
+                                      result2 = [result2, result3];
+                                    } else {
+                                      result2 = null;
+                                      pos = pos2;
+                                    }
+                                  } else {
+                                    result2 = null;
+                                    pos = pos2;
+                                  }
+
+                                  result2 = result2 !== null ? result2 : "";
+
+                                  if (result2 !== null) {
+                                    pos2 = pos;
+
+                                    if (input.charCodeAt(pos) === 58) {
+                                      result3 = ":";
+                                      pos++;
+                                    } else {
+                                      result3 = null;
+
+                                      if (reportFailures === 0) {
+                                        matchFailed("\":\"");
+                                      }
+                                    }
+
+                                    if (result3 !== null) {
+                                      result4 = parse_h16();
+
+                                      if (result4 !== null) {
+                                        result3 = [result3, result4];
+                                      } else {
+                                        result3 = null;
+                                        pos = pos2;
+                                      }
+                                    } else {
+                                      result3 = null;
+                                      pos = pos2;
+                                    }
+
+                                    result3 = result3 !== null ? result3 : "";
+
+                                    if (result3 !== null) {
+                                      if (input.substr(pos, 2) === "::") {
+                                        result4 = "::";
+                                        pos += 2;
+                                      } else {
+                                        result4 = null;
+
+                                        if (reportFailures === 0) {
+                                          matchFailed("\"::\"");
+                                        }
+                                      }
+
+                                      if (result4 !== null) {
+                                        result5 = parse_h16();
+
+                                        if (result5 !== null) {
+                                          if (input.charCodeAt(pos) === 58) {
+                                            result6 = ":";
+                                            pos++;
+                                          } else {
+                                            result6 = null;
+
+                                            if (reportFailures === 0) {
+                                              matchFailed("\":\"");
+                                            }
+                                          }
+
+                                          if (result6 !== null) {
+                                            result7 = parse_ls32();
+
+                                            if (result7 !== null) {
+                                              result0 = [result0, result1, result2, result3, result4, result5, result6, result7];
+                                            } else {
+                                              result0 = null;
+                                              pos = pos1;
+                                            }
+                                          } else {
+                                            result0 = null;
+                                            pos = pos1;
+                                          }
+                                        } else {
+                                          result0 = null;
+                                          pos = pos1;
+                                        }
+                                      } else {
+                                        result0 = null;
+                                        pos = pos1;
+                                      }
+                                    } else {
+                                      result0 = null;
+                                      pos = pos1;
+                                    }
+                                  } else {
+                                    result0 = null;
+                                    pos = pos1;
+                                  }
+                                } else {
+                                  result0 = null;
+                                  pos = pos1;
+                                }
+                              } else {
+                                result0 = null;
+                                pos = pos1;
+                              }
+
+                              if (result0 === null) {
+                                pos1 = pos;
+                                result0 = parse_h16();
+
+                                if (result0 !== null) {
+                                  pos2 = pos;
+
+                                  if (input.charCodeAt(pos) === 58) {
+                                    result1 = ":";
+                                    pos++;
+                                  } else {
+                                    result1 = null;
+
+                                    if (reportFailures === 0) {
+                                      matchFailed("\":\"");
+                                    }
+                                  }
+
+                                  if (result1 !== null) {
+                                    result2 = parse_h16();
+
+                                    if (result2 !== null) {
+                                      result1 = [result1, result2];
+                                    } else {
+                                      result1 = null;
+                                      pos = pos2;
+                                    }
+                                  } else {
+                                    result1 = null;
+                                    pos = pos2;
+                                  }
+
+                                  result1 = result1 !== null ? result1 : "";
+
+                                  if (result1 !== null) {
+                                    pos2 = pos;
+
+                                    if (input.charCodeAt(pos) === 58) {
+                                      result2 = ":";
+                                      pos++;
+                                    } else {
+                                      result2 = null;
+
+                                      if (reportFailures === 0) {
+                                        matchFailed("\":\"");
+                                      }
+                                    }
+
+                                    if (result2 !== null) {
+                                      result3 = parse_h16();
+
+                                      if (result3 !== null) {
+                                        result2 = [result2, result3];
+                                      } else {
+                                        result2 = null;
+                                        pos = pos2;
+                                      }
+                                    } else {
+                                      result2 = null;
+                                      pos = pos2;
+                                    }
+
+                                    result2 = result2 !== null ? result2 : "";
+
+                                    if (result2 !== null) {
+                                      pos2 = pos;
+
+                                      if (input.charCodeAt(pos) === 58) {
+                                        result3 = ":";
+                                        pos++;
+                                      } else {
+                                        result3 = null;
+
+                                        if (reportFailures === 0) {
+                                          matchFailed("\":\"");
+                                        }
+                                      }
+
+                                      if (result3 !== null) {
+                                        result4 = parse_h16();
+
+                                        if (result4 !== null) {
+                                          result3 = [result3, result4];
+                                        } else {
+                                          result3 = null;
+                                          pos = pos2;
+                                        }
+                                      } else {
+                                        result3 = null;
+                                        pos = pos2;
+                                      }
+
+                                      result3 = result3 !== null ? result3 : "";
+
+                                      if (result3 !== null) {
+                                        pos2 = pos;
+
+                                        if (input.charCodeAt(pos) === 58) {
+                                          result4 = ":";
+                                          pos++;
+                                        } else {
+                                          result4 = null;
+
+                                          if (reportFailures === 0) {
+                                            matchFailed("\":\"");
+                                          }
+                                        }
+
+                                        if (result4 !== null) {
+                                          result5 = parse_h16();
+
+                                          if (result5 !== null) {
+                                            result4 = [result4, result5];
+                                          } else {
+                                            result4 = null;
+                                            pos = pos2;
+                                          }
+                                        } else {
+                                          result4 = null;
+                                          pos = pos2;
+                                        }
+
+                                        result4 = result4 !== null ? result4 : "";
+
+                                        if (result4 !== null) {
+                                          if (input.substr(pos, 2) === "::") {
+                                            result5 = "::";
+                                            pos += 2;
+                                          } else {
+                                            result5 = null;
+
+                                            if (reportFailures === 0) {
+                                              matchFailed("\"::\"");
+                                            }
+                                          }
+
+                                          if (result5 !== null) {
+                                            result6 = parse_ls32();
+
+                                            if (result6 !== null) {
+                                              result0 = [result0, result1, result2, result3, result4, result5, result6];
+                                            } else {
+                                              result0 = null;
+                                              pos = pos1;
+                                            }
+                                          } else {
+                                            result0 = null;
+                                            pos = pos1;
+                                          }
+                                        } else {
+                                          result0 = null;
+                                          pos = pos1;
+                                        }
+                                      } else {
+                                        result0 = null;
+                                        pos = pos1;
+                                      }
+                                    } else {
+                                      result0 = null;
+                                      pos = pos1;
+                                    }
+                                  } else {
+                                    result0 = null;
+                                    pos = pos1;
+                                  }
+                                } else {
+                                  result0 = null;
+                                  pos = pos1;
+                                }
+
+                                if (result0 === null) {
+                                  pos1 = pos;
+                                  result0 = parse_h16();
+
+                                  if (result0 !== null) {
+                                    pos2 = pos;
+
+                                    if (input.charCodeAt(pos) === 58) {
+                                      result1 = ":";
+                                      pos++;
+                                    } else {
+                                      result1 = null;
+
+                                      if (reportFailures === 0) {
+                                        matchFailed("\":\"");
+                                      }
+                                    }
+
+                                    if (result1 !== null) {
+                                      result2 = parse_h16();
+
+                                      if (result2 !== null) {
+                                        result1 = [result1, result2];
+                                      } else {
+                                        result1 = null;
+                                        pos = pos2;
+                                      }
+                                    } else {
+                                      result1 = null;
+                                      pos = pos2;
+                                    }
+
+                                    result1 = result1 !== null ? result1 : "";
+
+                                    if (result1 !== null) {
+                                      pos2 = pos;
+
+                                      if (input.charCodeAt(pos) === 58) {
+                                        result2 = ":";
+                                        pos++;
+                                      } else {
+                                        result2 = null;
+
+                                        if (reportFailures === 0) {
+                                          matchFailed("\":\"");
+                                        }
+                                      }
+
+                                      if (result2 !== null) {
+                                        result3 = parse_h16();
+
+                                        if (result3 !== null) {
+                                          result2 = [result2, result3];
+                                        } else {
+                                          result2 = null;
+                                          pos = pos2;
+                                        }
+                                      } else {
+                                        result2 = null;
+                                        pos = pos2;
+                                      }
+
+                                      result2 = result2 !== null ? result2 : "";
+
+                                      if (result2 !== null) {
+                                        pos2 = pos;
+
+                                        if (input.charCodeAt(pos) === 58) {
+                                          result3 = ":";
+                                          pos++;
+                                        } else {
+                                          result3 = null;
+
+                                          if (reportFailures === 0) {
+                                            matchFailed("\":\"");
+                                          }
+                                        }
+
+                                        if (result3 !== null) {
+                                          result4 = parse_h16();
+
+                                          if (result4 !== null) {
+                                            result3 = [result3, result4];
+                                          } else {
+                                            result3 = null;
+                                            pos = pos2;
+                                          }
+                                        } else {
+                                          result3 = null;
+                                          pos = pos2;
+                                        }
+
+                                        result3 = result3 !== null ? result3 : "";
+
+                                        if (result3 !== null) {
+                                          pos2 = pos;
+
+                                          if (input.charCodeAt(pos) === 58) {
+                                            result4 = ":";
+                                            pos++;
+                                          } else {
+                                            result4 = null;
+
+                                            if (reportFailures === 0) {
+                                              matchFailed("\":\"");
+                                            }
+                                          }
+
+                                          if (result4 !== null) {
+                                            result5 = parse_h16();
+
+                                            if (result5 !== null) {
+                                              result4 = [result4, result5];
+                                            } else {
+                                              result4 = null;
+                                              pos = pos2;
+                                            }
+                                          } else {
+                                            result4 = null;
+                                            pos = pos2;
+                                          }
+
+                                          result4 = result4 !== null ? result4 : "";
+
+                                          if (result4 !== null) {
+                                            pos2 = pos;
+
+                                            if (input.charCodeAt(pos) === 58) {
+                                              result5 = ":";
+                                              pos++;
+                                            } else {
+                                              result5 = null;
+
+                                              if (reportFailures === 0) {
+                                                matchFailed("\":\"");
+                                              }
+                                            }
+
+                                            if (result5 !== null) {
+                                              result6 = parse_h16();
+
+                                              if (result6 !== null) {
+                                                result5 = [result5, result6];
+                                              } else {
+                                                result5 = null;
+                                                pos = pos2;
+                                              }
+                                            } else {
+                                              result5 = null;
+                                              pos = pos2;
+                                            }
+
+                                            result5 = result5 !== null ? result5 : "";
+
+                                            if (result5 !== null) {
+                                              if (input.substr(pos, 2) === "::") {
+                                                result6 = "::";
+                                                pos += 2;
+                                              } else {
+                                                result6 = null;
+
+                                                if (reportFailures === 0) {
+                                                  matchFailed("\"::\"");
+                                                }
+                                              }
+
+                                              if (result6 !== null) {
+                                                result7 = parse_h16();
+
+                                                if (result7 !== null) {
+                                                  result0 = [result0, result1, result2, result3, result4, result5, result6, result7];
+                                                } else {
+                                                  result0 = null;
+                                                  pos = pos1;
+                                                }
+                                              } else {
+                                                result0 = null;
+                                                pos = pos1;
+                                              }
+                                            } else {
+                                              result0 = null;
+                                              pos = pos1;
+                                            }
+                                          } else {
+                                            result0 = null;
+                                            pos = pos1;
+                                          }
+                                        } else {
+                                          result0 = null;
+                                          pos = pos1;
+                                        }
+                                      } else {
+                                        result0 = null;
+                                        pos = pos1;
+                                      }
+                                    } else {
+                                      result0 = null;
+                                      pos = pos1;
+                                    }
+                                  } else {
+                                    result0 = null;
+                                    pos = pos1;
+                                  }
+
+                                  if (result0 === null) {
+                                    pos1 = pos;
+                                    result0 = parse_h16();
+
+                                    if (result0 !== null) {
+                                      pos2 = pos;
+
+                                      if (input.charCodeAt(pos) === 58) {
+                                        result1 = ":";
+                                        pos++;
+                                      } else {
+                                        result1 = null;
+
+                                        if (reportFailures === 0) {
+                                          matchFailed("\":\"");
+                                        }
+                                      }
+
+                                      if (result1 !== null) {
+                                        result2 = parse_h16();
+
+                                        if (result2 !== null) {
+                                          result1 = [result1, result2];
+                                        } else {
+                                          result1 = null;
+                                          pos = pos2;
+                                        }
+                                      } else {
+                                        result1 = null;
+                                        pos = pos2;
+                                      }
+
+                                      result1 = result1 !== null ? result1 : "";
+
+                                      if (result1 !== null) {
+                                        pos2 = pos;
+
+                                        if (input.charCodeAt(pos) === 58) {
+                                          result2 = ":";
+                                          pos++;
+                                        } else {
+                                          result2 = null;
+
+                                          if (reportFailures === 0) {
+                                            matchFailed("\":\"");
+                                          }
+                                        }
+
+                                        if (result2 !== null) {
+                                          result3 = parse_h16();
+
+                                          if (result3 !== null) {
+                                            result2 = [result2, result3];
+                                          } else {
+                                            result2 = null;
+                                            pos = pos2;
+                                          }
+                                        } else {
+                                          result2 = null;
+                                          pos = pos2;
+                                        }
+
+                                        result2 = result2 !== null ? result2 : "";
+
+                                        if (result2 !== null) {
+                                          pos2 = pos;
+
+                                          if (input.charCodeAt(pos) === 58) {
+                                            result3 = ":";
+                                            pos++;
+                                          } else {
+                                            result3 = null;
+
+                                            if (reportFailures === 0) {
+                                              matchFailed("\":\"");
+                                            }
+                                          }
+
+                                          if (result3 !== null) {
+                                            result4 = parse_h16();
+
+                                            if (result4 !== null) {
+                                              result3 = [result3, result4];
+                                            } else {
+                                              result3 = null;
+                                              pos = pos2;
+                                            }
+                                          } else {
+                                            result3 = null;
+                                            pos = pos2;
+                                          }
+
+                                          result3 = result3 !== null ? result3 : "";
+
+                                          if (result3 !== null) {
+                                            pos2 = pos;
+
+                                            if (input.charCodeAt(pos) === 58) {
+                                              result4 = ":";
+                                              pos++;
+                                            } else {
+                                              result4 = null;
+
+                                              if (reportFailures === 0) {
+                                                matchFailed("\":\"");
+                                              }
+                                            }
+
+                                            if (result4 !== null) {
+                                              result5 = parse_h16();
+
+                                              if (result5 !== null) {
+                                                result4 = [result4, result5];
+                                              } else {
+                                                result4 = null;
+                                                pos = pos2;
+                                              }
+                                            } else {
+                                              result4 = null;
+                                              pos = pos2;
+                                            }
+
+                                            result4 = result4 !== null ? result4 : "";
+
+                                            if (result4 !== null) {
+                                              pos2 = pos;
+
+                                              if (input.charCodeAt(pos) === 58) {
+                                                result5 = ":";
+                                                pos++;
+                                              } else {
+                                                result5 = null;
+
+                                                if (reportFailures === 0) {
+                                                  matchFailed("\":\"");
+                                                }
+                                              }
+
+                                              if (result5 !== null) {
+                                                result6 = parse_h16();
+
+                                                if (result6 !== null) {
+                                                  result5 = [result5, result6];
+                                                } else {
+                                                  result5 = null;
+                                                  pos = pos2;
+                                                }
+                                              } else {
+                                                result5 = null;
+                                                pos = pos2;
+                                              }
+
+                                              result5 = result5 !== null ? result5 : "";
+
+                                              if (result5 !== null) {
+                                                pos2 = pos;
+
+                                                if (input.charCodeAt(pos) === 58) {
+                                                  result6 = ":";
+                                                  pos++;
+                                                } else {
+                                                  result6 = null;
+
+                                                  if (reportFailures === 0) {
+                                                    matchFailed("\":\"");
+                                                  }
+                                                }
+
+                                                if (result6 !== null) {
+                                                  result7 = parse_h16();
+
+                                                  if (result7 !== null) {
+                                                    result6 = [result6, result7];
+                                                  } else {
+                                                    result6 = null;
+                                                    pos = pos2;
+                                                  }
+                                                } else {
+                                                  result6 = null;
+                                                  pos = pos2;
+                                                }
+
+                                                result6 = result6 !== null ? result6 : "";
+
+                                                if (result6 !== null) {
+                                                  if (input.substr(pos, 2) === "::") {
+                                                    result7 = "::";
+                                                    pos += 2;
+                                                  } else {
+                                                    result7 = null;
+
+                                                    if (reportFailures === 0) {
+                                                      matchFailed("\"::\"");
+                                                    }
+                                                  }
+
+                                                  if (result7 !== null) {
+                                                    result0 = [result0, result1, result2, result3, result4, result5, result6, result7];
+                                                  } else {
+                                                    result0 = null;
+                                                    pos = pos1;
+                                                  }
+                                                } else {
+                                                  result0 = null;
+                                                  pos = pos1;
+                                                }
+                                              } else {
+                                                result0 = null;
+                                                pos = pos1;
+                                              }
+                                            } else {
+                                              result0 = null;
+                                              pos = pos1;
+                                            }
+                                          } else {
+                                            result0 = null;
+                                            pos = pos1;
+                                          }
+                                        } else {
+                                          result0 = null;
+                                          pos = pos1;
+                                        }
+                                      } else {
+                                        result0 = null;
+                                        pos = pos1;
+                                      }
+                                    } else {
+                                      result0 = null;
+                                      pos = pos1;
+                                    }
+                                  }
+                                }
+                              }
+                            }
+                          }
+                        }
+                      }
+                    }
+                  }
+                }
+              }
+            }
+          }
+        }
+
+        if (result0 !== null) {
+          result0 = function (offset) {
+            data.host_type = 'IPv6';
+            return input.substring(pos, offset);
+          }(pos0);
+        }
+
+        if (result0 === null) {
+          pos = pos0;
+        }
+
+        return result0;
+      }
+
+      function parse_h16() {
+        var result0, result1, result2, result3;
+        var pos0;
+        pos0 = pos;
+        result0 = parse_HEXDIG();
+
+        if (result0 !== null) {
+          result1 = parse_HEXDIG();
+          result1 = result1 !== null ? result1 : "";
+
+          if (result1 !== null) {
+            result2 = parse_HEXDIG();
+            result2 = result2 !== null ? result2 : "";
+
+            if (result2 !== null) {
+              result3 = parse_HEXDIG();
+              result3 = result3 !== null ? result3 : "";
+
+              if (result3 !== null) {
+                result0 = [result0, result1, result2, result3];
+              } else {
+                result0 = null;
+                pos = pos0;
+              }
+            } else {
+              result0 = null;
+              pos = pos0;
+            }
+          } else {
+            result0 = null;
+            pos = pos0;
+          }
+        } else {
+          result0 = null;
+          pos = pos0;
+        }
+
+        return result0;
+      }
+
+      function parse_ls32() {
+        var result0, result1, result2;
+        var pos0;
+        pos0 = pos;
+        result0 = parse_h16();
+
+        if (result0 !== null) {
+          if (input.charCodeAt(pos) === 58) {
+            result1 = ":";
+            pos++;
+          } else {
+            result1 = null;
+
+            if (reportFailures === 0) {
+              matchFailed("\":\"");
+            }
+          }
+
+          if (result1 !== null) {
+            result2 = parse_h16();
+
+            if (result2 !== null) {
+              result0 = [result0, result1, result2];
+            } else {
+              result0 = null;
+              pos = pos0;
+            }
+          } else {
+            result0 = null;
+            pos = pos0;
+          }
+        } else {
+          result0 = null;
+          pos = pos0;
+        }
+
+        if (result0 === null) {
+          result0 = parse_IPv4address();
+        }
+
+        return result0;
+      }
+
+      function parse_IPv4address() {
+        var result0, result1, result2, result3, result4, result5, result6;
+        var pos0, pos1;
+        pos0 = pos;
+        pos1 = pos;
+        result0 = parse_dec_octet();
+
+        if (result0 !== null) {
+          if (input.charCodeAt(pos) === 46) {
+            result1 = ".";
+            pos++;
+          } else {
+            result1 = null;
+
+            if (reportFailures === 0) {
+              matchFailed("\".\"");
+            }
+          }
+
+          if (result1 !== null) {
+            result2 = parse_dec_octet();
+
+            if (result2 !== null) {
+              if (input.charCodeAt(pos) === 46) {
+                result3 = ".";
+                pos++;
+              } else {
+                result3 = null;
+
+                if (reportFailures === 0) {
+                  matchFailed("\".\"");
+                }
+              }
+
+              if (result3 !== null) {
+                result4 = parse_dec_octet();
+
+                if (result4 !== null) {
+                  if (input.charCodeAt(pos) === 46) {
+                    result5 = ".";
+                    pos++;
+                  } else {
+                    result5 = null;
+
+                    if (reportFailures === 0) {
+                      matchFailed("\".\"");
+                    }
+                  }
+
+                  if (result5 !== null) {
+                    result6 = parse_dec_octet();
+
+                    if (result6 !== null) {
+                      result0 = [result0, result1, result2, result3, result4, result5, result6];
+                    } else {
+                      result0 = null;
+                      pos = pos1;
+                    }
+                  } else {
+                    result0 = null;
+                    pos = pos1;
+                  }
+                } else {
+                  result0 = null;
+                  pos = pos1;
+                }
+              } else {
+                result0 = null;
+                pos = pos1;
+              }
+            } else {
+              result0 = null;
+              pos = pos1;
+            }
+          } else {
+            result0 = null;
+            pos = pos1;
+          }
+        } else {
+          result0 = null;
+          pos = pos1;
+        }
+
+        if (result0 !== null) {
+          result0 = function (offset) {
+            data.host_type = 'IPv4';
+            return input.substring(pos, offset);
+          }(pos0);
+        }
+
+        if (result0 === null) {
+          pos = pos0;
+        }
+
+        return result0;
+      }
+
+      function parse_dec_octet() {
+        var result0, result1, result2;
+        var pos0;
+        pos0 = pos;
+
+        if (input.substr(pos, 2) === "25") {
+          result0 = "25";
+          pos += 2;
+        } else {
+          result0 = null;
+
+          if (reportFailures === 0) {
+            matchFailed("\"25\"");
+          }
+        }
+
+        if (result0 !== null) {
+          if (/^[0-5]/.test(input.charAt(pos))) {
+            result1 = input.charAt(pos);
+            pos++;
+          } else {
+            result1 = null;
+
+            if (reportFailures === 0) {
+              matchFailed("[0-5]");
+            }
+          }
+
+          if (result1 !== null) {
+            result0 = [result0, result1];
+          } else {
+            result0 = null;
+            pos = pos0;
+          }
+        } else {
+          result0 = null;
+          pos = pos0;
+        }
+
+        if (result0 === null) {
+          pos0 = pos;
+
+          if (input.charCodeAt(pos) === 50) {
+            result0 = "2";
+            pos++;
+          } else {
+            result0 = null;
+
+            if (reportFailures === 0) {
+              matchFailed("\"2\"");
+            }
+          }
+
+          if (result0 !== null) {
+            if (/^[0-4]/.test(input.charAt(pos))) {
+              result1 = input.charAt(pos);
+              pos++;
+            } else {
+              result1 = null;
+
+              if (reportFailures === 0) {
+                matchFailed("[0-4]");
+              }
+            }
+
+            if (result1 !== null) {
+              result2 = parse_DIGIT();
+
+              if (result2 !== null) {
+                result0 = [result0, result1, result2];
+              } else {
+                result0 = null;
+                pos = pos0;
+              }
+            } else {
+              result0 = null;
+              pos = pos0;
+            }
+          } else {
+            result0 = null;
+            pos = pos0;
+          }
+
+          if (result0 === null) {
+            pos0 = pos;
+
+            if (input.charCodeAt(pos) === 49) {
+              result0 = "1";
+              pos++;
+            } else {
+              result0 = null;
+
+              if (reportFailures === 0) {
+                matchFailed("\"1\"");
+              }
+            }
+
+            if (result0 !== null) {
+              result1 = parse_DIGIT();
+
+              if (result1 !== null) {
+                result2 = parse_DIGIT();
+
+                if (result2 !== null) {
+                  result0 = [result0, result1, result2];
+                } else {
+                  result0 = null;
+                  pos = pos0;
+                }
+              } else {
+                result0 = null;
+                pos = pos0;
+              }
+            } else {
+              result0 = null;
+              pos = pos0;
+            }
+
+            if (result0 === null) {
+              pos0 = pos;
+
+              if (/^[1-9]/.test(input.charAt(pos))) {
+                result0 = input.charAt(pos);
+                pos++;
+              } else {
+                result0 = null;
+
+                if (reportFailures === 0) {
+                  matchFailed("[1-9]");
+                }
+              }
+
+              if (result0 !== null) {
+                result1 = parse_DIGIT();
+
+                if (result1 !== null) {
+                  result0 = [result0, result1];
+                } else {
+                  result0 = null;
+                  pos = pos0;
+                }
+              } else {
+                result0 = null;
+                pos = pos0;
+              }
+
+              if (result0 === null) {
+                result0 = parse_DIGIT();
+              }
+            }
+          }
+        }
+
+        return result0;
+      }
+
+      function parse_port() {
+        var result0, result1, result2, result3, result4;
+        var pos0, pos1;
+        pos0 = pos;
+        pos1 = pos;
+        result0 = parse_DIGIT();
+        result0 = result0 !== null ? result0 : "";
+
+        if (result0 !== null) {
+          result1 = parse_DIGIT();
+          result1 = result1 !== null ? result1 : "";
+
+          if (result1 !== null) {
+            result2 = parse_DIGIT();
+            result2 = result2 !== null ? result2 : "";
+
+            if (result2 !== null) {
+              result3 = parse_DIGIT();
+              result3 = result3 !== null ? result3 : "";
+
+              if (result3 !== null) {
+                result4 = parse_DIGIT();
+                result4 = result4 !== null ? result4 : "";
+
+                if (result4 !== null) {
+                  result0 = [result0, result1, result2, result3, result4];
+                } else {
+                  result0 = null;
+                  pos = pos1;
+                }
+              } else {
+                result0 = null;
+                pos = pos1;
+              }
+            } else {
+              result0 = null;
+              pos = pos1;
+            }
+          } else {
+            result0 = null;
+            pos = pos1;
+          }
+        } else {
+          result0 = null;
+          pos = pos1;
+        }
+
+        if (result0 !== null) {
+          result0 = function (offset, port) {
+            port = parseInt(port.join(''));
+            data.port = port;
+            return port;
+          }(pos0, result0);
+        }
+
+        if (result0 === null) {
+          pos = pos0;
+        }
+
+        return result0;
+      }
+
+      function parse_uri_parameters() {
+        var result0, result1, result2;
+        var pos0;
+        result0 = [];
+        pos0 = pos;
+
+        if (input.charCodeAt(pos) === 59) {
+          result1 = ";";
+          pos++;
+        } else {
+          result1 = null;
+
+          if (reportFailures === 0) {
+            matchFailed("\";\"");
+          }
+        }
+
+        if (result1 !== null) {
+          result2 = parse_uri_parameter();
+
+          if (result2 !== null) {
+            result1 = [result1, result2];
+          } else {
+            result1 = null;
+            pos = pos0;
+          }
+        } else {
+          result1 = null;
+          pos = pos0;
+        }
+
+        while (result1 !== null) {
+          result0.push(result1);
+          pos0 = pos;
+
+          if (input.charCodeAt(pos) === 59) {
+            result1 = ";";
+            pos++;
+          } else {
+            result1 = null;
+
+            if (reportFailures === 0) {
+              matchFailed("\";\"");
+            }
+          }
+
+          if (result1 !== null) {
+            result2 = parse_uri_parameter();
+
+            if (result2 !== null) {
+              result1 = [result1, result2];
+            } else {
+              result1 = null;
+              pos = pos0;
+            }
+          } else {
+            result1 = null;
+            pos = pos0;
+          }
+        }
+
+        return result0;
+      }
+
+      function parse_uri_parameter() {
+        var result0;
+        result0 = parse_transport_param();
+
+        if (result0 === null) {
+          result0 = parse_user_param();
+
+          if (result0 === null) {
+            result0 = parse_method_param();
+
+            if (result0 === null) {
+              result0 = parse_ttl_param();
+
+              if (result0 === null) {
+                result0 = parse_maddr_param();
+
+                if (result0 === null) {
+                  result0 = parse_lr_param();
+
+                  if (result0 === null) {
+                    result0 = parse_other_param();
+                  }
+                }
+              }
+            }
+          }
+        }
+
+        return result0;
+      }
+
+      function parse_transport_param() {
+        var result0, result1;
+        var pos0, pos1;
+        pos0 = pos;
+        pos1 = pos;
+
+        if (input.substr(pos, 10).toLowerCase() === "transport=") {
+          result0 = input.substr(pos, 10);
+          pos += 10;
+        } else {
+          result0 = null;
+
+          if (reportFailures === 0) {
+            matchFailed("\"transport=\"");
+          }
+        }
+
+        if (result0 !== null) {
+          if (input.substr(pos, 3).toLowerCase() === "udp") {
+            result1 = input.substr(pos, 3);
+            pos += 3;
+          } else {
+            result1 = null;
+
+            if (reportFailures === 0) {
+              matchFailed("\"udp\"");
+            }
+          }
+
+          if (result1 === null) {
+            if (input.substr(pos, 3).toLowerCase() === "tcp") {
+              result1 = input.substr(pos, 3);
+              pos += 3;
+            } else {
+              result1 = null;
+
+              if (reportFailures === 0) {
+                matchFailed("\"tcp\"");
+              }
+            }
+
+            if (result1 === null) {
+              if (input.substr(pos, 4).toLowerCase() === "sctp") {
+                result1 = input.substr(pos, 4);
+                pos += 4;
+              } else {
+                result1 = null;
+
+                if (reportFailures === 0) {
+                  matchFailed("\"sctp\"");
+                }
+              }
+
+              if (result1 === null) {
+                if (input.substr(pos, 3).toLowerCase() === "tls") {
+                  result1 = input.substr(pos, 3);
+                  pos += 3;
+                } else {
+                  result1 = null;
+
+                  if (reportFailures === 0) {
+                    matchFailed("\"tls\"");
+                  }
+                }
+
+                if (result1 === null) {
+                  result1 = parse_token();
+                }
+              }
+            }
+          }
+
+          if (result1 !== null) {
+            result0 = [result0, result1];
+          } else {
+            result0 = null;
+            pos = pos1;
+          }
+        } else {
+          result0 = null;
+          pos = pos1;
+        }
+
+        if (result0 !== null) {
+          result0 = function (offset, transport) {
+            if (!data.uri_params) data.uri_params = {};
+            data.uri_params['transport'] = transport.toLowerCase();
+          }(pos0, result0[1]);
+        }
+
+        if (result0 === null) {
+          pos = pos0;
+        }
+
+        return result0;
+      }
+
+      function parse_user_param() {
+        var result0, result1;
+        var pos0, pos1;
+        pos0 = pos;
+        pos1 = pos;
+
+        if (input.substr(pos, 5).toLowerCase() === "user=") {
+          result0 = input.substr(pos, 5);
+          pos += 5;
+        } else {
+          result0 = null;
+
+          if (reportFailures === 0) {
+            matchFailed("\"user=\"");
+          }
+        }
+
+        if (result0 !== null) {
+          if (input.substr(pos, 5).toLowerCase() === "phone") {
+            result1 = input.substr(pos, 5);
+            pos += 5;
+          } else {
+            result1 = null;
+
+            if (reportFailures === 0) {
+              matchFailed("\"phone\"");
+            }
+          }
+
+          if (result1 === null) {
+            if (input.substr(pos, 2).toLowerCase() === "ip") {
+              result1 = input.substr(pos, 2);
+              pos += 2;
+            } else {
+              result1 = null;
+
+              if (reportFailures === 0) {
+                matchFailed("\"ip\"");
+              }
+            }
+
+            if (result1 === null) {
+              result1 = parse_token();
+            }
+          }
+
+          if (result1 !== null) {
+            result0 = [result0, result1];
+          } else {
+            result0 = null;
+            pos = pos1;
+          }
+        } else {
+          result0 = null;
+          pos = pos1;
+        }
+
+        if (result0 !== null) {
+          result0 = function (offset, user) {
+            if (!data.uri_params) data.uri_params = {};
+            data.uri_params['user'] = user.toLowerCase();
+          }(pos0, result0[1]);
+        }
+
+        if (result0 === null) {
+          pos = pos0;
+        }
+
+        return result0;
+      }
+
+      function parse_method_param() {
+        var result0, result1;
+        var pos0, pos1;
+        pos0 = pos;
+        pos1 = pos;
+
+        if (input.substr(pos, 7).toLowerCase() === "method=") {
+          result0 = input.substr(pos, 7);
+          pos += 7;
+        } else {
+          result0 = null;
+
+          if (reportFailures === 0) {
+            matchFailed("\"method=\"");
+          }
+        }
+
+        if (result0 !== null) {
+          result1 = parse_Method();
+
+          if (result1 !== null) {
+            result0 = [result0, result1];
+          } else {
+            result0 = null;
+            pos = pos1;
+          }
+        } else {
+          result0 = null;
+          pos = pos1;
+        }
+
+        if (result0 !== null) {
+          result0 = function (offset, method) {
+            if (!data.uri_params) data.uri_params = {};
+            data.uri_params['method'] = method;
+          }(pos0, result0[1]);
+        }
+
+        if (result0 === null) {
+          pos = pos0;
+        }
+
+        return result0;
+      }
+
+      function parse_ttl_param() {
+        var result0, result1;
+        var pos0, pos1;
+        pos0 = pos;
+        pos1 = pos;
+
+        if (input.substr(pos, 4).toLowerCase() === "ttl=") {
+          result0 = input.substr(pos, 4);
+          pos += 4;
+        } else {
+          result0 = null;
+
+          if (reportFailures === 0) {
+            matchFailed("\"ttl=\"");
+          }
+        }
+
+        if (result0 !== null) {
+          result1 = parse_ttl();
+
+          if (result1 !== null) {
+            result0 = [result0, result1];
+          } else {
+            result0 = null;
+            pos = pos1;
+          }
+        } else {
+          result0 = null;
+          pos = pos1;
+        }
+
+        if (result0 !== null) {
+          result0 = function (offset, ttl) {
+            if (!data.params) data.params = {};
+            data.params['ttl'] = ttl;
+          }(pos0, result0[1]);
+        }
+
+        if (result0 === null) {
+          pos = pos0;
+        }
+
+        return result0;
+      }
+
+      function parse_maddr_param() {
+        var result0, result1;
+        var pos0, pos1;
+        pos0 = pos;
+        pos1 = pos;
+
+        if (input.substr(pos, 6).toLowerCase() === "maddr=") {
+          result0 = input.substr(pos, 6);
+          pos += 6;
+        } else {
+          result0 = null;
+
+          if (reportFailures === 0) {
+            matchFailed("\"maddr=\"");
+          }
+        }
+
+        if (result0 !== null) {
+          result1 = parse_host();
+
+          if (result1 !== null) {
+            result0 = [result0, result1];
+          } else {
+            result0 = null;
+            pos = pos1;
+          }
+        } else {
+          result0 = null;
+          pos = pos1;
+        }
+
+        if (result0 !== null) {
+          result0 = function (offset, maddr) {
+            if (!data.uri_params) data.uri_params = {};
+            data.uri_params['maddr'] = maddr;
+          }(pos0, result0[1]);
+        }
+
+        if (result0 === null) {
+          pos = pos0;
+        }
+
+        return result0;
+      }
+
+      function parse_lr_param() {
+        var result0, result1, result2;
+        var pos0, pos1, pos2;
+        pos0 = pos;
+        pos1 = pos;
+
+        if (input.substr(pos, 2).toLowerCase() === "lr") {
+          result0 = input.substr(pos, 2);
+          pos += 2;
+        } else {
+          result0 = null;
+
+          if (reportFailures === 0) {
+            matchFailed("\"lr\"");
+          }
+        }
+
+        if (result0 !== null) {
+          pos2 = pos;
+
+          if (input.charCodeAt(pos) === 61) {
+            result1 = "=";
+            pos++;
+          } else {
+            result1 = null;
+
+            if (reportFailures === 0) {
+              matchFailed("\"=\"");
+            }
+          }
+
+          if (result1 !== null) {
+            result2 = parse_token();
+
+            if (result2 !== null) {
+              result1 = [result1, result2];
+            } else {
+              result1 = null;
+              pos = pos2;
+            }
+          } else {
+            result1 = null;
+            pos = pos2;
+          }
+
+          result1 = result1 !== null ? result1 : "";
+
+          if (result1 !== null) {
+            result0 = [result0, result1];
+          } else {
+            result0 = null;
+            pos = pos1;
+          }
+        } else {
+          result0 = null;
+          pos = pos1;
+        }
+
+        if (result0 !== null) {
+          result0 = function (offset) {
+            if (!data.uri_params) data.uri_params = {};
+            data.uri_params['lr'] = undefined;
+          }(pos0);
+        }
+
+        if (result0 === null) {
+          pos = pos0;
+        }
+
+        return result0;
+      }
+
+      function parse_other_param() {
+        var result0, result1, result2;
+        var pos0, pos1, pos2;
+        pos0 = pos;
+        pos1 = pos;
+        result0 = parse_pname();
+
+        if (result0 !== null) {
+          pos2 = pos;
+
+          if (input.charCodeAt(pos) === 61) {
+            result1 = "=";
+            pos++;
+          } else {
+            result1 = null;
+
+            if (reportFailures === 0) {
+              matchFailed("\"=\"");
+            }
+          }
+
+          if (result1 !== null) {
+            result2 = parse_pvalue();
+
+            if (result2 !== null) {
+              result1 = [result1, result2];
+            } else {
+              result1 = null;
+              pos = pos2;
+            }
+          } else {
+            result1 = null;
+            pos = pos2;
+          }
+
+          result1 = result1 !== null ? result1 : "";
+
+          if (result1 !== null) {
+            result0 = [result0, result1];
+          } else {
+            result0 = null;
+            pos = pos1;
+          }
+        } else {
+          result0 = null;
+          pos = pos1;
+        }
+
+        if (result0 !== null) {
+          result0 = function (offset, param, value) {
+            if (!data.uri_params) data.uri_params = {};
+
+            if (typeof value === 'undefined') {
+              value = undefined;
+            } else {
+              value = value[1];
+            }
+
+            data.uri_params[param.toLowerCase()] = value;
+          }(pos0, result0[0], result0[1]);
+        }
+
+        if (result0 === null) {
+          pos = pos0;
+        }
+
+        return result0;
+      }
+
+      function parse_pname() {
+        var result0, result1;
+        var pos0;
+        pos0 = pos;
+        result1 = parse_paramchar();
+
+        if (result1 !== null) {
+          result0 = [];
+
+          while (result1 !== null) {
+            result0.push(result1);
+            result1 = parse_paramchar();
+          }
+        } else {
+          result0 = null;
+        }
+
+        if (result0 !== null) {
+          result0 = function (offset, pname) {
+            return pname.join('');
+          }(pos0, result0);
+        }
+
+        if (result0 === null) {
+          pos = pos0;
+        }
+
+        return result0;
+      }
+
+      function parse_pvalue() {
+        var result0, result1;
+        var pos0;
+        pos0 = pos;
+        result1 = parse_paramchar();
+
+        if (result1 !== null) {
+          result0 = [];
+
+          while (result1 !== null) {
+            result0.push(result1);
+            result1 = parse_paramchar();
+          }
+        } else {
+          result0 = null;
+        }
+
+        if (result0 !== null) {
+          result0 = function (offset, pvalue) {
+            return pvalue.join('');
+          }(pos0, result0);
+        }
+
+        if (result0 === null) {
+          pos = pos0;
+        }
+
+        return result0;
+      }
+
+      function parse_paramchar() {
+        var result0;
+        result0 = parse_param_unreserved();
+
+        if (result0 === null) {
+          result0 = parse_unreserved();
+
+          if (result0 === null) {
+            result0 = parse_escaped();
+          }
+        }
+
+        return result0;
+      }
+
+      function parse_param_unreserved() {
+        var result0;
+
+        if (input.charCodeAt(pos) === 91) {
+          result0 = "[";
+          pos++;
+        } else {
+          result0 = null;
+
+          if (reportFailures === 0) {
+            matchFailed("\"[\"");
+          }
+        }
+
+        if (result0 === null) {
+          if (input.charCodeAt(pos) === 93) {
+            result0 = "]";
+            pos++;
+          } else {
+            result0 = null;
+
+            if (reportFailures === 0) {
+              matchFailed("\"]\"");
+            }
+          }
+
+          if (result0 === null) {
+            if (input.charCodeAt(pos) === 47) {
+              result0 = "/";
+              pos++;
+            } else {
+              result0 = null;
+
+              if (reportFailures === 0) {
+                matchFailed("\"/\"");
+              }
+            }
+
+            if (result0 === null) {
+              if (input.charCodeAt(pos) === 58) {
+                result0 = ":";
+                pos++;
+              } else {
+                result0 = null;
+
+                if (reportFailures === 0) {
+                  matchFailed("\":\"");
+                }
+              }
+
+              if (result0 === null) {
+                if (input.charCodeAt(pos) === 38) {
+                  result0 = "&";
+                  pos++;
+                } else {
+                  result0 = null;
+
+                  if (reportFailures === 0) {
+                    matchFailed("\"&\"");
+                  }
+                }
+
+                if (result0 === null) {
+                  if (input.charCodeAt(pos) === 43) {
+                    result0 = "+";
+                    pos++;
+                  } else {
+                    result0 = null;
+
+                    if (reportFailures === 0) {
+                      matchFailed("\"+\"");
+                    }
+                  }
+
+                  if (result0 === null) {
+                    if (input.charCodeAt(pos) === 36) {
+                      result0 = "$";
+                      pos++;
+                    } else {
+                      result0 = null;
+
+                      if (reportFailures === 0) {
+                        matchFailed("\"$\"");
+                      }
+                    }
+                  }
+                }
+              }
+            }
+          }
+        }
+
+        return result0;
+      }
+
+      function parse_headers() {
+        var result0, result1, result2, result3, result4;
+        var pos0, pos1;
+        pos0 = pos;
+
+        if (input.charCodeAt(pos) === 63) {
+          result0 = "?";
+          pos++;
+        } else {
+          result0 = null;
+
+          if (reportFailures === 0) {
+            matchFailed("\"?\"");
+          }
+        }
+
+        if (result0 !== null) {
+          result1 = parse_header();
+
+          if (result1 !== null) {
+            result2 = [];
+            pos1 = pos;
+
+            if (input.charCodeAt(pos) === 38) {
+              result3 = "&";
+              pos++;
+            } else {
+              result3 = null;
+
+              if (reportFailures === 0) {
+                matchFailed("\"&\"");
+              }
+            }
+
+            if (result3 !== null) {
+              result4 = parse_header();
+
+              if (result4 !== null) {
+                result3 = [result3, result4];
+              } else {
+                result3 = null;
+                pos = pos1;
+              }
+            } else {
+              result3 = null;
+              pos = pos1;
+            }
+
+            while (result3 !== null) {
+              result2.push(result3);
+              pos1 = pos;
+
+              if (input.charCodeAt(pos) === 38) {
+                result3 = "&";
+                pos++;
+              } else {
+                result3 = null;
+
+                if (reportFailures === 0) {
+                  matchFailed("\"&\"");
+                }
+              }
+
+              if (result3 !== null) {
+                result4 = parse_header();
+
+                if (result4 !== null) {
+                  result3 = [result3, result4];
+                } else {
+                  result3 = null;
+                  pos = pos1;
+                }
+              } else {
+                result3 = null;
+                pos = pos1;
+              }
+            }
+
+            if (result2 !== null) {
+              result0 = [result0, result1, result2];
+            } else {
+              result0 = null;
+              pos = pos0;
+            }
+          } else {
+            result0 = null;
+            pos = pos0;
+          }
+        } else {
+          result0 = null;
+          pos = pos0;
+        }
+
+        return result0;
+      }
+
+      function parse_header() {
+        var result0, result1, result2;
+        var pos0, pos1;
+        pos0 = pos;
+        pos1 = pos;
+        result0 = parse_hname();
+
+        if (result0 !== null) {
+          if (input.charCodeAt(pos) === 61) {
+            result1 = "=";
+            pos++;
+          } else {
+            result1 = null;
+
+            if (reportFailures === 0) {
+              matchFailed("\"=\"");
+            }
+          }
+
+          if (result1 !== null) {
+            result2 = parse_hvalue();
+
+            if (result2 !== null) {
+              result0 = [result0, result1, result2];
+            } else {
+              result0 = null;
+              pos = pos1;
+            }
+          } else {
+            result0 = null;
+            pos = pos1;
+          }
+        } else {
+          result0 = null;
+          pos = pos1;
+        }
+
+        if (result0 !== null) {
+          result0 = function (offset, hname, hvalue) {
+            hname = hname.join('').toLowerCase();
+            hvalue = hvalue.join('');
+            if (!data.uri_headers) data.uri_headers = {};
+
+            if (!data.uri_headers[hname]) {
+              data.uri_headers[hname] = [hvalue];
+            } else {
+              data.uri_headers[hname].push(hvalue);
+            }
+          }(pos0, result0[0], result0[2]);
+        }
+
+        if (result0 === null) {
+          pos = pos0;
+        }
+
+        return result0;
+      }
+
+      function parse_hname() {
+        var result0, result1;
+        result1 = parse_hnv_unreserved();
+
+        if (result1 === null) {
+          result1 = parse_unreserved();
+
+          if (result1 === null) {
+            result1 = parse_escaped();
+          }
+        }
+
+        if (result1 !== null) {
+          result0 = [];
+
+          while (result1 !== null) {
+            result0.push(result1);
+            result1 = parse_hnv_unreserved();
+
+            if (result1 === null) {
+              result1 = parse_unreserved();
+
+              if (result1 === null) {
+                result1 = parse_escaped();
+              }
+            }
+          }
+        } else {
+          result0 = null;
+        }
+
+        return result0;
+      }
+
+      function parse_hvalue() {
+        var result0, result1;
+        result0 = [];
+        result1 = parse_hnv_unreserved();
+
+        if (result1 === null) {
+          result1 = parse_unreserved();
+
+          if (result1 === null) {
+            result1 = parse_escaped();
+          }
+        }
+
+        while (result1 !== null) {
+          result0.push(result1);
+          result1 = parse_hnv_unreserved();
+
+          if (result1 === null) {
+            result1 = parse_unreserved();
+
+            if (result1 === null) {
+              result1 = parse_escaped();
+            }
+          }
+        }
+
+        return result0;
+      }
+
+      function parse_hnv_unreserved() {
+        var result0;
+
+        if (input.charCodeAt(pos) === 91) {
+          result0 = "[";
+          pos++;
+        } else {
+          result0 = null;
+
+          if (reportFailures === 0) {
+            matchFailed("\"[\"");
+          }
+        }
+
+        if (result0 === null) {
+          if (input.charCodeAt(pos) === 93) {
+            result0 = "]";
+            pos++;
+          } else {
+            result0 = null;
+
+            if (reportFailures === 0) {
+              matchFailed("\"]\"");
+            }
+          }
+
+          if (result0 === null) {
+            if (input.charCodeAt(pos) === 47) {
+              result0 = "/";
+              pos++;
+            } else {
+              result0 = null;
+
+              if (reportFailures === 0) {
+                matchFailed("\"/\"");
+              }
+            }
+
+            if (result0 === null) {
+              if (input.charCodeAt(pos) === 63) {
+                result0 = "?";
+                pos++;
+              } else {
+                result0 = null;
+
+                if (reportFailures === 0) {
+                  matchFailed("\"?\"");
+                }
+              }
+
+              if (result0 === null) {
+                if (input.charCodeAt(pos) === 58) {
+                  result0 = ":";
+                  pos++;
+                } else {
+                  result0 = null;
+
+                  if (reportFailures === 0) {
+                    matchFailed("\":\"");
+                  }
+                }
+
+                if (result0 === null) {
+                  if (input.charCodeAt(pos) === 43) {
+                    result0 = "+";
+                    pos++;
+                  } else {
+                    result0 = null;
+
+                    if (reportFailures === 0) {
+                      matchFailed("\"+\"");
+                    }
+                  }
+
+                  if (result0 === null) {
+                    if (input.charCodeAt(pos) === 36) {
+                      result0 = "$";
+                      pos++;
+                    } else {
+                      result0 = null;
+
+                      if (reportFailures === 0) {
+                        matchFailed("\"$\"");
+                      }
+                    }
+                  }
+                }
+              }
+            }
+          }
+        }
+
+        return result0;
+      }
+
+      function parse_Request_Response() {
+        var result0;
+        result0 = parse_Status_Line();
+
+        if (result0 === null) {
+          result0 = parse_Request_Line();
+        }
+
+        return result0;
+      }
+
+      function parse_Request_Line() {
+        var result0, result1, result2, result3, result4;
+        var pos0;
+        pos0 = pos;
+        result0 = parse_Method();
+
+        if (result0 !== null) {
+          result1 = parse_SP();
+
+          if (result1 !== null) {
+            result2 = parse_Request_URI();
+
+            if (result2 !== null) {
+              result3 = parse_SP();
+
+              if (result3 !== null) {
+                result4 = parse_SIP_Version();
+
+                if (result4 !== null) {
+                  result0 = [result0, result1, result2, result3, result4];
+                } else {
+                  result0 = null;
+                  pos = pos0;
+                }
+              } else {
+                result0 = null;
+                pos = pos0;
+              }
+            } else {
+              result0 = null;
+              pos = pos0;
+            }
+          } else {
+            result0 = null;
+            pos = pos0;
+          }
+        } else {
+          result0 = null;
+          pos = pos0;
+        }
+
+        return result0;
+      }
+
+      function parse_Request_URI() {
+        var result0;
+        result0 = parse_SIP_URI();
+
+        if (result0 === null) {
+          result0 = parse_absoluteURI();
+        }
+
+        return result0;
+      }
+
+      function parse_absoluteURI() {
+        var result0, result1, result2;
+        var pos0;
+        pos0 = pos;
+        result0 = parse_scheme();
+
+        if (result0 !== null) {
+          if (input.charCodeAt(pos) === 58) {
+            result1 = ":";
+            pos++;
+          } else {
+            result1 = null;
+
+            if (reportFailures === 0) {
+              matchFailed("\":\"");
+            }
+          }
+
+          if (result1 !== null) {
+            result2 = parse_hier_part();
+
+            if (result2 === null) {
+              result2 = parse_opaque_part();
+            }
+
+            if (result2 !== null) {
+              result0 = [result0, result1, result2];
+            } else {
+              result0 = null;
+              pos = pos0;
+            }
+          } else {
+            result0 = null;
+            pos = pos0;
+          }
+        } else {
+          result0 = null;
+          pos = pos0;
+        }
+
+        return result0;
+      }
+
+      function parse_hier_part() {
+        var result0, result1, result2;
+        var pos0, pos1;
+        pos0 = pos;
+        result0 = parse_net_path();
+
+        if (result0 === null) {
+          result0 = parse_abs_path();
+        }
+
+        if (result0 !== null) {
+          pos1 = pos;
+
+          if (input.charCodeAt(pos) === 63) {
+            result1 = "?";
+            pos++;
+          } else {
+            result1 = null;
+
+            if (reportFailures === 0) {
+              matchFailed("\"?\"");
+            }
+          }
+
+          if (result1 !== null) {
+            result2 = parse_query();
+
+            if (result2 !== null) {
+              result1 = [result1, result2];
+            } else {
+              result1 = null;
+              pos = pos1;
+            }
+          } else {
+            result1 = null;
+            pos = pos1;
+          }
+
+          result1 = result1 !== null ? result1 : "";
+
+          if (result1 !== null) {
+            result0 = [result0, result1];
+          } else {
+            result0 = null;
+            pos = pos0;
+          }
+        } else {
+          result0 = null;
+          pos = pos0;
+        }
+
+        return result0;
+      }
+
+      function parse_net_path() {
+        var result0, result1, result2;
+        var pos0;
+        pos0 = pos;
+
+        if (input.substr(pos, 2) === "//") {
+          result0 = "//";
+          pos += 2;
+        } else {
+          result0 = null;
+
+          if (reportFailures === 0) {
+            matchFailed("\"//\"");
+          }
+        }
+
+        if (result0 !== null) {
+          result1 = parse_authority();
+
+          if (result1 !== null) {
+            result2 = parse_abs_path();
+            result2 = result2 !== null ? result2 : "";
+
+            if (result2 !== null) {
+              result0 = [result0, result1, result2];
+            } else {
+              result0 = null;
+              pos = pos0;
+            }
+          } else {
+            result0 = null;
+            pos = pos0;
+          }
+        } else {
+          result0 = null;
+          pos = pos0;
+        }
+
+        return result0;
+      }
+
+      function parse_abs_path() {
+        var result0, result1;
+        var pos0;
+        pos0 = pos;
+
+        if (input.charCodeAt(pos) === 47) {
+          result0 = "/";
+          pos++;
+        } else {
+          result0 = null;
+
+          if (reportFailures === 0) {
+            matchFailed("\"/\"");
+          }
+        }
+
+        if (result0 !== null) {
+          result1 = parse_path_segments();
+
+          if (result1 !== null) {
+            result0 = [result0, result1];
+          } else {
+            result0 = null;
+            pos = pos0;
+          }
+        } else {
+          result0 = null;
+          pos = pos0;
+        }
+
+        return result0;
+      }
+
+      function parse_opaque_part() {
+        var result0, result1, result2;
+        var pos0;
+        pos0 = pos;
+        result0 = parse_uric_no_slash();
+
+        if (result0 !== null) {
+          result1 = [];
+          result2 = parse_uric();
+
+          while (result2 !== null) {
+            result1.push(result2);
+            result2 = parse_uric();
+          }
+
+          if (result1 !== null) {
+            result0 = [result0, result1];
+          } else {
+            result0 = null;
+            pos = pos0;
+          }
+        } else {
+          result0 = null;
+          pos = pos0;
+        }
+
+        return result0;
+      }
+
+      function parse_uric() {
+        var result0;
+        result0 = parse_reserved();
+
+        if (result0 === null) {
+          result0 = parse_unreserved();
+
+          if (result0 === null) {
+            result0 = parse_escaped();
+          }
+        }
+
+        return result0;
+      }
+
+      function parse_uric_no_slash() {
+        var result0;
+        result0 = parse_unreserved();
+
+        if (result0 === null) {
+          result0 = parse_escaped();
+
+          if (result0 === null) {
+            if (input.charCodeAt(pos) === 59) {
+              result0 = ";";
+              pos++;
+            } else {
+              result0 = null;
+
+              if (reportFailures === 0) {
+                matchFailed("\";\"");
+              }
+            }
+
+            if (result0 === null) {
+              if (input.charCodeAt(pos) === 63) {
+                result0 = "?";
+                pos++;
+              } else {
+                result0 = null;
+
+                if (reportFailures === 0) {
+                  matchFailed("\"?\"");
+                }
+              }
+
+              if (result0 === null) {
+                if (input.charCodeAt(pos) === 58) {
+                  result0 = ":";
+                  pos++;
+                } else {
+                  result0 = null;
+
+                  if (reportFailures === 0) {
+                    matchFailed("\":\"");
+                  }
+                }
+
+                if (result0 === null) {
+                  if (input.charCodeAt(pos) === 64) {
+                    result0 = "@";
+                    pos++;
+                  } else {
+                    result0 = null;
+
+                    if (reportFailures === 0) {
+                      matchFailed("\"@\"");
+                    }
+                  }
+
+                  if (result0 === null) {
+                    if (input.charCodeAt(pos) === 38) {
+                      result0 = "&";
+                      pos++;
+                    } else {
+                      result0 = null;
+
+                      if (reportFailures === 0) {
+                        matchFailed("\"&\"");
+                      }
+                    }
+
+                    if (result0 === null) {
+                      if (input.charCodeAt(pos) === 61) {
+                        result0 = "=";
+                        pos++;
+                      } else {
+                        result0 = null;
+
+                        if (reportFailures === 0) {
+                          matchFailed("\"=\"");
+                        }
+                      }
+
+                      if (result0 === null) {
+                        if (input.charCodeAt(pos) === 43) {
+                          result0 = "+";
+                          pos++;
+                        } else {
+                          result0 = null;
+
+                          if (reportFailures === 0) {
+                            matchFailed("\"+\"");
+                          }
+                        }
+
+                        if (result0 === null) {
+                          if (input.charCodeAt(pos) === 36) {
+                            result0 = "$";
+                            pos++;
+                          } else {
+                            result0 = null;
+
+                            if (reportFailures === 0) {
+                              matchFailed("\"$\"");
+                            }
+                          }
+
+                          if (result0 === null) {
+                            if (input.charCodeAt(pos) === 44) {
+                              result0 = ",";
+                              pos++;
+                            } else {
+                              result0 = null;
+
+                              if (reportFailures === 0) {
+                                matchFailed("\",\"");
+                              }
+                            }
+                          }
+                        }
+                      }
+                    }
+                  }
+                }
+              }
+            }
+          }
+        }
+
+        return result0;
+      }
+
+      function parse_path_segments() {
+        var result0, result1, result2, result3;
+        var pos0, pos1;
+        pos0 = pos;
+        result0 = parse_segment();
+
+        if (result0 !== null) {
+          result1 = [];
+          pos1 = pos;
+
+          if (input.charCodeAt(pos) === 47) {
+            result2 = "/";
+            pos++;
+          } else {
+            result2 = null;
+
+            if (reportFailures === 0) {
+              matchFailed("\"/\"");
+            }
+          }
+
+          if (result2 !== null) {
+            result3 = parse_segment();
+
+            if (result3 !== null) {
+              result2 = [result2, result3];
+            } else {
+              result2 = null;
+              pos = pos1;
+            }
+          } else {
+            result2 = null;
+            pos = pos1;
+          }
+
+          while (result2 !== null) {
+            result1.push(result2);
+            pos1 = pos;
+
+            if (input.charCodeAt(pos) === 47) {
+              result2 = "/";
+              pos++;
+            } else {
+              result2 = null;
+
+              if (reportFailures === 0) {
+                matchFailed("\"/\"");
+              }
+            }
+
+            if (result2 !== null) {
+              result3 = parse_segment();
+
+              if (result3 !== null) {
+                result2 = [result2, result3];
+              } else {
+                result2 = null;
+                pos = pos1;
+              }
+            } else {
+              result2 = null;
+              pos = pos1;
+            }
+          }
+
+          if (result1 !== null) {
+            result0 = [result0, result1];
+          } else {
+            result0 = null;
+            pos = pos0;
+          }
+        } else {
+          result0 = null;
+          pos = pos0;
+        }
+
+        return result0;
+      }
+
+      function parse_segment() {
+        var result0, result1, result2, result3;
+        var pos0, pos1;
+        pos0 = pos;
+        result0 = [];
+        result1 = parse_pchar();
+
+        while (result1 !== null) {
+          result0.push(result1);
+          result1 = parse_pchar();
+        }
+
+        if (result0 !== null) {
+          result1 = [];
+          pos1 = pos;
+
+          if (input.charCodeAt(pos) === 59) {
+            result2 = ";";
+            pos++;
+          } else {
+            result2 = null;
+
+            if (reportFailures === 0) {
+              matchFailed("\";\"");
+            }
+          }
+
+          if (result2 !== null) {
+            result3 = parse_param();
+
+            if (result3 !== null) {
+              result2 = [result2, result3];
+            } else {
+              result2 = null;
+              pos = pos1;
+            }
+          } else {
+            result2 = null;
+            pos = pos1;
+          }
+
+          while (result2 !== null) {
+            result1.push(result2);
+            pos1 = pos;
+
+            if (input.charCodeAt(pos) === 59) {
+              result2 = ";";
+              pos++;
+            } else {
+              result2 = null;
+
+              if (reportFailures === 0) {
+                matchFailed("\";\"");
+              }
+            }
+
+            if (result2 !== null) {
+              result3 = parse_param();
+
+              if (result3 !== null) {
+                result2 = [result2, result3];
+              } else {
+                result2 = null;
+                pos = pos1;
+              }
+            } else {
+              result2 = null;
+              pos = pos1;
+            }
+          }
+
+          if (result1 !== null) {
+            result0 = [result0, result1];
+          } else {
+            result0 = null;
+            pos = pos0;
+          }
+        } else {
+          result0 = null;
+          pos = pos0;
+        }
+
+        return result0;
+      }
+
+      function parse_param() {
+        var result0, result1;
+        result0 = [];
+        result1 = parse_pchar();
+
+        while (result1 !== null) {
+          result0.push(result1);
+          result1 = parse_pchar();
+        }
+
+        return result0;
+      }
+
+      function parse_pchar() {
+        var result0;
+        result0 = parse_unreserved();
+
+        if (result0 === null) {
+          result0 = parse_escaped();
+
+          if (result0 === null) {
+            if (input.charCodeAt(pos) === 58) {
+              result0 = ":";
+              pos++;
+            } else {
+              result0 = null;
+
+              if (reportFailures === 0) {
+                matchFailed("\":\"");
+              }
+            }
+
+            if (result0 === null) {
+              if (input.charCodeAt(pos) === 64) {
+                result0 = "@";
+                pos++;
+              } else {
+                result0 = null;
+
+                if (reportFailures === 0) {
+                  matchFailed("\"@\"");
+                }
+              }
+
+              if (result0 === null) {
+                if (input.charCodeAt(pos) === 38) {
+                  result0 = "&";
+                  pos++;
+                } else {
+                  result0 = null;
+
+                  if (reportFailures === 0) {
+                    matchFailed("\"&\"");
+                  }
+                }
+
+                if (result0 === null) {
+                  if (input.charCodeAt(pos) === 61) {
+                    result0 = "=";
+                    pos++;
+                  } else {
+                    result0 = null;
+
+                    if (reportFailures === 0) {
+                      matchFailed("\"=\"");
+                    }
+                  }
+
+                  if (result0 === null) {
+                    if (input.charCodeAt(pos) === 43) {
+                      result0 = "+";
+                      pos++;
+                    } else {
+                      result0 = null;
+
+                      if (reportFailures === 0) {
+                        matchFailed("\"+\"");
+                      }
+                    }
+
+                    if (result0 === null) {
+                      if (input.charCodeAt(pos) === 36) {
+                        result0 = "$";
+                        pos++;
+                      } else {
+                        result0 = null;
+
+                        if (reportFailures === 0) {
+                          matchFailed("\"$\"");
+                        }
+                      }
+
+                      if (result0 === null) {
+                        if (input.charCodeAt(pos) === 44) {
+                          result0 = ",";
+                          pos++;
+                        } else {
+                          result0 = null;
+
+                          if (reportFailures === 0) {
+                            matchFailed("\",\"");
+                          }
+                        }
+                      }
+                    }
+                  }
+                }
+              }
+            }
+          }
+        }
+
+        return result0;
+      }
+
+      function parse_scheme() {
+        var result0, result1, result2;
+        var pos0, pos1;
+        pos0 = pos;
+        pos1 = pos;
+        result0 = parse_ALPHA();
+
+        if (result0 !== null) {
+          result1 = [];
+          result2 = parse_ALPHA();
+
+          if (result2 === null) {
+            result2 = parse_DIGIT();
+
+            if (result2 === null) {
+              if (input.charCodeAt(pos) === 43) {
+                result2 = "+";
+                pos++;
+              } else {
+                result2 = null;
+
+                if (reportFailures === 0) {
+                  matchFailed("\"+\"");
+                }
+              }
+
+              if (result2 === null) {
+                if (input.charCodeAt(pos) === 45) {
+                  result2 = "-";
+                  pos++;
+                } else {
+                  result2 = null;
+
+                  if (reportFailures === 0) {
+                    matchFailed("\"-\"");
+                  }
+                }
+
+                if (result2 === null) {
+                  if (input.charCodeAt(pos) === 46) {
+                    result2 = ".";
+                    pos++;
+                  } else {
+                    result2 = null;
+
+                    if (reportFailures === 0) {
+                      matchFailed("\".\"");
+                    }
+                  }
+                }
+              }
+            }
+          }
+
+          while (result2 !== null) {
+            result1.push(result2);
+            result2 = parse_ALPHA();
+
+            if (result2 === null) {
+              result2 = parse_DIGIT();
+
+              if (result2 === null) {
+                if (input.charCodeAt(pos) === 43) {
+                  result2 = "+";
+                  pos++;
+                } else {
+                  result2 = null;
+
+                  if (reportFailures === 0) {
+                    matchFailed("\"+\"");
+                  }
+                }
+
+                if (result2 === null) {
+                  if (input.charCodeAt(pos) === 45) {
+                    result2 = "-";
+                    pos++;
+                  } else {
+                    result2 = null;
+
+                    if (reportFailures === 0) {
+                      matchFailed("\"-\"");
+                    }
+                  }
+
+                  if (result2 === null) {
+                    if (input.charCodeAt(pos) === 46) {
+                      result2 = ".";
+                      pos++;
+                    } else {
+                      result2 = null;
+
+                      if (reportFailures === 0) {
+                        matchFailed("\".\"");
+                      }
+                    }
+                  }
+                }
+              }
+            }
+          }
+
+          if (result1 !== null) {
+            result0 = [result0, result1];
+          } else {
+            result0 = null;
+            pos = pos1;
+          }
+        } else {
+          result0 = null;
+          pos = pos1;
+        }
+
+        if (result0 !== null) {
+          result0 = function (offset) {
+            data.scheme = input.substring(pos, offset);
+          }(pos0);
+        }
+
+        if (result0 === null) {
+          pos = pos0;
+        }
+
+        return result0;
+      }
+
+      function parse_authority() {
+        var result0;
+        result0 = parse_srvr();
+
+        if (result0 === null) {
+          result0 = parse_reg_name();
+        }
+
+        return result0;
+      }
+
+      function parse_srvr() {
+        var result0, result1;
+        var pos0, pos1;
+        pos0 = pos;
+        pos1 = pos;
+        result0 = parse_userinfo();
+
+        if (result0 !== null) {
+          if (input.charCodeAt(pos) === 64) {
+            result1 = "@";
+            pos++;
+          } else {
+            result1 = null;
+
+            if (reportFailures === 0) {
+              matchFailed("\"@\"");
+            }
+          }
+
+          if (result1 !== null) {
+            result0 = [result0, result1];
+          } else {
+            result0 = null;
+            pos = pos1;
+          }
+        } else {
+          result0 = null;
+          pos = pos1;
+        }
+
+        result0 = result0 !== null ? result0 : "";
+
+        if (result0 !== null) {
+          result1 = parse_hostport();
+
+          if (result1 !== null) {
+            result0 = [result0, result1];
+          } else {
+            result0 = null;
+            pos = pos0;
+          }
+        } else {
+          result0 = null;
+          pos = pos0;
+        }
+
+        result0 = result0 !== null ? result0 : "";
+        return result0;
+      }
+
+      function parse_reg_name() {
+        var result0, result1;
+        result1 = parse_unreserved();
+
+        if (result1 === null) {
+          result1 = parse_escaped();
+
+          if (result1 === null) {
+            if (input.charCodeAt(pos) === 36) {
+              result1 = "$";
+              pos++;
+            } else {
+              result1 = null;
+
+              if (reportFailures === 0) {
+                matchFailed("\"$\"");
+              }
+            }
+
+            if (result1 === null) {
+              if (input.charCodeAt(pos) === 44) {
+                result1 = ",";
+                pos++;
+              } else {
+                result1 = null;
+
+                if (reportFailures === 0) {
+                  matchFailed("\",\"");
+                }
+              }
+
+              if (result1 === null) {
+                if (input.charCodeAt(pos) === 59) {
+                  result1 = ";";
+                  pos++;
+                } else {
+                  result1 = null;
+
+                  if (reportFailures === 0) {
+                    matchFailed("\";\"");
+                  }
+                }
+
+                if (result1 === null) {
+                  if (input.charCodeAt(pos) === 58) {
+                    result1 = ":";
+                    pos++;
+                  } else {
+                    result1 = null;
+
+                    if (reportFailures === 0) {
+                      matchFailed("\":\"");
+                    }
+                  }
+
+                  if (result1 === null) {
+                    if (input.charCodeAt(pos) === 64) {
+                      result1 = "@";
+                      pos++;
+                    } else {
+                      result1 = null;
+
+                      if (reportFailures === 0) {
+                        matchFailed("\"@\"");
+                      }
+                    }
+
+                    if (result1 === null) {
+                      if (input.charCodeAt(pos) === 38) {
+                        result1 = "&";
+                        pos++;
+                      } else {
+                        result1 = null;
+
+                        if (reportFailures === 0) {
+                          matchFailed("\"&\"");
+                        }
+                      }
+
+                      if (result1 === null) {
+                        if (input.charCodeAt(pos) === 61) {
+                          result1 = "=";
+                          pos++;
+                        } else {
+                          result1 = null;
+
+                          if (reportFailures === 0) {
+                            matchFailed("\"=\"");
+                          }
+                        }
+
+                        if (result1 === null) {
+                          if (input.charCodeAt(pos) === 43) {
+                            result1 = "+";
+                            pos++;
+                          } else {
+                            result1 = null;
+
+                            if (reportFailures === 0) {
+                              matchFailed("\"+\"");
+                            }
+                          }
+                        }
+                      }
+                    }
+                  }
+                }
+              }
+            }
+          }
+        }
+
+        if (result1 !== null) {
+          result0 = [];
+
+          while (result1 !== null) {
+            result0.push(result1);
+            result1 = parse_unreserved();
+
+            if (result1 === null) {
+              result1 = parse_escaped();
+
+              if (result1 === null) {
+                if (input.charCodeAt(pos) === 36) {
+                  result1 = "$";
+                  pos++;
+                } else {
+                  result1 = null;
+
+                  if (reportFailures === 0) {
+                    matchFailed("\"$\"");
+                  }
+                }
+
+                if (result1 === null) {
+                  if (input.charCodeAt(pos) === 44) {
+                    result1 = ",";
+                    pos++;
+                  } else {
+                    result1 = null;
+
+                    if (reportFailures === 0) {
+                      matchFailed("\",\"");
+                    }
+                  }
+
+                  if (result1 === null) {
+                    if (input.charCodeAt(pos) === 59) {
+                      result1 = ";";
+                      pos++;
+                    } else {
+                      result1 = null;
+
+                      if (reportFailures === 0) {
+                        matchFailed("\";\"");
+                      }
+                    }
+
+                    if (result1 === null) {
+                      if (input.charCodeAt(pos) === 58) {
+                        result1 = ":";
+                        pos++;
+                      } else {
+                        result1 = null;
+
+                        if (reportFailures === 0) {
+                          matchFailed("\":\"");
+                        }
+                      }
+
+                      if (result1 === null) {
+                        if (input.charCodeAt(pos) === 64) {
+                          result1 = "@";
+                          pos++;
+                        } else {
+                          result1 = null;
+
+                          if (reportFailures === 0) {
+                            matchFailed("\"@\"");
+                          }
+                        }
+
+                        if (result1 === null) {
+                          if (input.charCodeAt(pos) === 38) {
+                            result1 = "&";
+                            pos++;
+                          } else {
+                            result1 = null;
+
+                            if (reportFailures === 0) {
+                              matchFailed("\"&\"");
+                            }
+                          }
+
+                          if (result1 === null) {
+                            if (input.charCodeAt(pos) === 61) {
+                              result1 = "=";
+                              pos++;
+                            } else {
+                              result1 = null;
+
+                              if (reportFailures === 0) {
+                                matchFailed("\"=\"");
+                              }
+                            }
+
+                            if (result1 === null) {
+                              if (input.charCodeAt(pos) === 43) {
+                                result1 = "+";
+                                pos++;
+                              } else {
+                                result1 = null;
+
+                                if (reportFailures === 0) {
+                                  matchFailed("\"+\"");
+                                }
+                              }
+                            }
+                          }
+                        }
+                      }
+                    }
+                  }
+                }
+              }
+            }
+          }
+        } else {
+          result0 = null;
+        }
+
+        return result0;
+      }
+
+      function parse_query() {
+        var result0, result1;
+        result0 = [];
+        result1 = parse_uric();
+
+        while (result1 !== null) {
+          result0.push(result1);
+          result1 = parse_uric();
+        }
+
+        return result0;
+      }
+
+      function parse_SIP_Version() {
+        var result0, result1, result2, result3, result4, result5;
+        var pos0, pos1;
+        pos0 = pos;
+        pos1 = pos;
+
+        if (input.substr(pos, 3).toLowerCase() === "sip") {
+          result0 = input.substr(pos, 3);
+          pos += 3;
+        } else {
+          result0 = null;
+
+          if (reportFailures === 0) {
+            matchFailed("\"SIP\"");
+          }
+        }
+
+        if (result0 !== null) {
+          if (input.charCodeAt(pos) === 47) {
+            result1 = "/";
+            pos++;
+          } else {
+            result1 = null;
+
+            if (reportFailures === 0) {
+              matchFailed("\"/\"");
+            }
+          }
+
+          if (result1 !== null) {
+            result3 = parse_DIGIT();
+
+            if (result3 !== null) {
+              result2 = [];
+
+              while (result3 !== null) {
+                result2.push(result3);
+                result3 = parse_DIGIT();
+              }
+            } else {
+              result2 = null;
+            }
+
+            if (result2 !== null) {
+              if (input.charCodeAt(pos) === 46) {
+                result3 = ".";
+                pos++;
+              } else {
+                result3 = null;
+
+                if (reportFailures === 0) {
+                  matchFailed("\".\"");
+                }
+              }
+
+              if (result3 !== null) {
+                result5 = parse_DIGIT();
+
+                if (result5 !== null) {
+                  result4 = [];
+
+                  while (result5 !== null) {
+                    result4.push(result5);
+                    result5 = parse_DIGIT();
+                  }
+                } else {
+                  result4 = null;
+                }
+
+                if (result4 !== null) {
+                  result0 = [result0, result1, result2, result3, result4];
+                } else {
+                  result0 = null;
+                  pos = pos1;
+                }
+              } else {
+                result0 = null;
+                pos = pos1;
+              }
+            } else {
+              result0 = null;
+              pos = pos1;
+            }
+          } else {
+            result0 = null;
+            pos = pos1;
+          }
+        } else {
+          result0 = null;
+          pos = pos1;
+        }
+
+        if (result0 !== null) {
+          result0 = function (offset) {
+            data.sip_version = input.substring(pos, offset);
+          }(pos0);
+        }
+
+        if (result0 === null) {
+          pos = pos0;
+        }
+
+        return result0;
+      }
+
+      function parse_INVITEm() {
+        var result0;
+
+        if (input.substr(pos, 6) === "INVITE") {
+          result0 = "INVITE";
+          pos += 6;
+        } else {
+          result0 = null;
+
+          if (reportFailures === 0) {
+            matchFailed("\"INVITE\"");
+          }
+        }
+
+        return result0;
+      }
+
+      function parse_ACKm() {
+        var result0;
+
+        if (input.substr(pos, 3) === "ACK") {
+          result0 = "ACK";
+          pos += 3;
+        } else {
+          result0 = null;
+
+          if (reportFailures === 0) {
+            matchFailed("\"ACK\"");
+          }
+        }
+
+        return result0;
+      }
+
+      function parse_OPTIONSm() {
+        var result0;
+
+        if (input.substr(pos, 7) === "OPTIONS") {
+          result0 = "OPTIONS";
+          pos += 7;
+        } else {
+          result0 = null;
+
+          if (reportFailures === 0) {
+            matchFailed("\"OPTIONS\"");
+          }
+        }
+
+        return result0;
+      }
+
+      function parse_BYEm() {
+        var result0;
+
+        if (input.substr(pos, 3) === "BYE") {
+          result0 = "BYE";
+          pos += 3;
+        } else {
+          result0 = null;
+
+          if (reportFailures === 0) {
+            matchFailed("\"BYE\"");
+          }
+        }
+
+        return result0;
+      }
+
+      function parse_CANCELm() {
+        var result0;
+
+        if (input.substr(pos, 6) === "CANCEL") {
+          result0 = "CANCEL";
+          pos += 6;
+        } else {
+          result0 = null;
+
+          if (reportFailures === 0) {
+            matchFailed("\"CANCEL\"");
+          }
+        }
+
+        return result0;
+      }
+
+      function parse_REGISTERm() {
+        var result0;
+
+        if (input.substr(pos, 8) === "REGISTER") {
+          result0 = "REGISTER";
+          pos += 8;
+        } else {
+          result0 = null;
+
+          if (reportFailures === 0) {
+            matchFailed("\"REGISTER\"");
+          }
+        }
+
+        return result0;
+      }
+
+      function parse_SUBSCRIBEm() {
+        var result0;
+
+        if (input.substr(pos, 9) === "SUBSCRIBE") {
+          result0 = "SUBSCRIBE";
+          pos += 9;
+        } else {
+          result0 = null;
+
+          if (reportFailures === 0) {
+            matchFailed("\"SUBSCRIBE\"");
+          }
+        }
+
+        return result0;
+      }
+
+      function parse_NOTIFYm() {
+        var result0;
+
+        if (input.substr(pos, 6) === "NOTIFY") {
+          result0 = "NOTIFY";
+          pos += 6;
+        } else {
+          result0 = null;
+
+          if (reportFailures === 0) {
+            matchFailed("\"NOTIFY\"");
+          }
+        }
+
+        return result0;
+      }
+
+      function parse_REFERm() {
+        var result0;
+
+        if (input.substr(pos, 5) === "REFER") {
+          result0 = "REFER";
+          pos += 5;
+        } else {
+          result0 = null;
+
+          if (reportFailures === 0) {
+            matchFailed("\"REFER\"");
+          }
+        }
+
+        return result0;
+      }
+
+      function parse_Method() {
+        var result0;
+        var pos0;
+        pos0 = pos;
+        result0 = parse_INVITEm();
+
+        if (result0 === null) {
+          result0 = parse_ACKm();
+
+          if (result0 === null) {
+            result0 = parse_OPTIONSm();
+
+            if (result0 === null) {
+              result0 = parse_BYEm();
+
+              if (result0 === null) {
+                result0 = parse_CANCELm();
+
+                if (result0 === null) {
+                  result0 = parse_REGISTERm();
+
+                  if (result0 === null) {
+                    result0 = parse_SUBSCRIBEm();
+
+                    if (result0 === null) {
+                      result0 = parse_NOTIFYm();
+
+                      if (result0 === null) {
+                        result0 = parse_REFERm();
+
+                        if (result0 === null) {
+                          result0 = parse_token();
+                        }
+                      }
+                    }
+                  }
+                }
+              }
+            }
+          }
+        }
+
+        if (result0 !== null) {
+          result0 = function (offset) {
+            data.method = input.substring(pos, offset);
+            return data.method;
+          }(pos0);
+        }
+
+        if (result0 === null) {
+          pos = pos0;
+        }
+
+        return result0;
+      }
+
+      function parse_Status_Line() {
+        var result0, result1, result2, result3, result4;
+        var pos0;
+        pos0 = pos;
+        result0 = parse_SIP_Version();
+
+        if (result0 !== null) {
+          result1 = parse_SP();
+
+          if (result1 !== null) {
+            result2 = parse_Status_Code();
+
+            if (result2 !== null) {
+              result3 = parse_SP();
+
+              if (result3 !== null) {
+                result4 = parse_Reason_Phrase();
+
+                if (result4 !== null) {
+                  result0 = [result0, result1, result2, result3, result4];
+                } else {
+                  result0 = null;
+                  pos = pos0;
+                }
+              } else {
+                result0 = null;
+                pos = pos0;
+              }
+            } else {
+              result0 = null;
+              pos = pos0;
+            }
+          } else {
+            result0 = null;
+            pos = pos0;
+          }
+        } else {
+          result0 = null;
+          pos = pos0;
+        }
+
+        return result0;
+      }
+
+      function parse_Status_Code() {
+        var result0;
+        var pos0;
+        pos0 = pos;
+        result0 = parse_extension_code();
+
+        if (result0 !== null) {
+          result0 = function (offset, status_code) {
+            data.status_code = parseInt(status_code.join(''));
+          }(pos0, result0);
+        }
+
+        if (result0 === null) {
+          pos = pos0;
+        }
+
+        return result0;
+      }
+
+      function parse_extension_code() {
+        var result0, result1, result2;
+        var pos0;
+        pos0 = pos;
+        result0 = parse_DIGIT();
+
+        if (result0 !== null) {
+          result1 = parse_DIGIT();
+
+          if (result1 !== null) {
+            result2 = parse_DIGIT();
+
+            if (result2 !== null) {
+              result0 = [result0, result1, result2];
+            } else {
+              result0 = null;
+              pos = pos0;
+            }
+          } else {
+            result0 = null;
+            pos = pos0;
+          }
+        } else {
+          result0 = null;
+          pos = pos0;
+        }
+
+        return result0;
+      }
+
+      function parse_Reason_Phrase() {
+        var result0, result1;
+        var pos0;
+        pos0 = pos;
+        result0 = [];
+        result1 = parse_reserved();
+
+        if (result1 === null) {
+          result1 = parse_unreserved();
+
+          if (result1 === null) {
+            result1 = parse_escaped();
+
+            if (result1 === null) {
+              result1 = parse_UTF8_NONASCII();
+
+              if (result1 === null) {
+                result1 = parse_UTF8_CONT();
+
+                if (result1 === null) {
+                  result1 = parse_SP();
+
+                  if (result1 === null) {
+                    result1 = parse_HTAB();
+                  }
+                }
+              }
+            }
+          }
+        }
+
+        while (result1 !== null) {
+          result0.push(result1);
+          result1 = parse_reserved();
+
+          if (result1 === null) {
+            result1 = parse_unreserved();
+
+            if (result1 === null) {
+              result1 = parse_escaped();
+
+              if (result1 === null) {
+                result1 = parse_UTF8_NONASCII();
+
+                if (result1 === null) {
+                  result1 = parse_UTF8_CONT();
+
+                  if (result1 === null) {
+                    result1 = parse_SP();
+
+                    if (result1 === null) {
+                      result1 = parse_HTAB();
+                    }
+                  }
+                }
+              }
+            }
+          }
+        }
+
+        if (result0 !== null) {
+          result0 = function (offset) {
+            data.reason_phrase = input.substring(pos, offset);
+          }(pos0);
+        }
+
+        if (result0 === null) {
+          pos = pos0;
+        }
+
+        return result0;
+      }
+
+      function parse_Allow_Events() {
+        var result0, result1, result2, result3;
+        var pos0, pos1;
+        pos0 = pos;
+        result0 = parse_event_type();
+
+        if (result0 !== null) {
+          result1 = [];
+          pos1 = pos;
+          result2 = parse_COMMA();
+
+          if (result2 !== null) {
+            result3 = parse_event_type();
+
+            if (result3 !== null) {
+              result2 = [result2, result3];
+            } else {
+              result2 = null;
+              pos = pos1;
+            }
+          } else {
+            result2 = null;
+            pos = pos1;
+          }
+
+          while (result2 !== null) {
+            result1.push(result2);
+            pos1 = pos;
+            result2 = parse_COMMA();
+
+            if (result2 !== null) {
+              result3 = parse_event_type();
+
+              if (result3 !== null) {
+                result2 = [result2, result3];
+              } else {
+                result2 = null;
+                pos = pos1;
+              }
+            } else {
+              result2 = null;
+              pos = pos1;
+            }
+          }
+
+          if (result1 !== null) {
+            result0 = [result0, result1];
+          } else {
+            result0 = null;
+            pos = pos0;
+          }
+        } else {
+          result0 = null;
+          pos = pos0;
+        }
+
+        return result0;
+      }
+
+      function parse_Call_ID() {
+        var result0, result1, result2;
+        var pos0, pos1, pos2;
+        pos0 = pos;
+        pos1 = pos;
+        result0 = parse_word();
+
+        if (result0 !== null) {
+          pos2 = pos;
+
+          if (input.charCodeAt(pos) === 64) {
+            result1 = "@";
+            pos++;
+          } else {
+            result1 = null;
+
+            if (reportFailures === 0) {
+              matchFailed("\"@\"");
+            }
+          }
+
+          if (result1 !== null) {
+            result2 = parse_word();
+
+            if (result2 !== null) {
+              result1 = [result1, result2];
+            } else {
+              result1 = null;
+              pos = pos2;
+            }
+          } else {
+            result1 = null;
+            pos = pos2;
+          }
+
+          result1 = result1 !== null ? result1 : "";
+
+          if (result1 !== null) {
+            result0 = [result0, result1];
+          } else {
+            result0 = null;
+            pos = pos1;
+          }
+        } else {
+          result0 = null;
+          pos = pos1;
+        }
+
+        if (result0 !== null) {
+          result0 = function (offset) {
+            data = input.substring(pos, offset);
+          }(pos0);
+        }
+
+        if (result0 === null) {
+          pos = pos0;
+        }
+
+        return result0;
+      }
+
+      function parse_Contact() {
+        var result0, result1, result2, result3;
+        var pos0, pos1, pos2;
+        pos0 = pos;
+        result0 = parse_STAR();
+
+        if (result0 === null) {
+          pos1 = pos;
+          result0 = parse_contact_param();
+
+          if (result0 !== null) {
+            result1 = [];
+            pos2 = pos;
+            result2 = parse_COMMA();
+
+            if (result2 !== null) {
+              result3 = parse_contact_param();
+
+              if (result3 !== null) {
+                result2 = [result2, result3];
+              } else {
+                result2 = null;
+                pos = pos2;
+              }
+            } else {
+              result2 = null;
+              pos = pos2;
+            }
+
+            while (result2 !== null) {
+              result1.push(result2);
+              pos2 = pos;
+              result2 = parse_COMMA();
+
+              if (result2 !== null) {
+                result3 = parse_contact_param();
+
+                if (result3 !== null) {
+                  result2 = [result2, result3];
+                } else {
+                  result2 = null;
+                  pos = pos2;
+                }
+              } else {
+                result2 = null;
+                pos = pos2;
+              }
+            }
+
+            if (result1 !== null) {
+              result0 = [result0, result1];
+            } else {
+              result0 = null;
+              pos = pos1;
+            }
+          } else {
+            result0 = null;
+            pos = pos1;
+          }
+        }
+
+        if (result0 !== null) {
+          result0 = function (offset) {
+            var idx, length;
+            length = data.multi_header.length;
+
+            for (idx = 0; idx < length; idx++) {
+              if (data.multi_header[idx].parsed === null) {
+                data = null;
+                break;
+              }
+            }
+
+            if (data !== null) {
+              data = data.multi_header;
+            } else {
+              data = -1;
+            }
+          }(pos0);
+        }
+
+        if (result0 === null) {
+          pos = pos0;
+        }
+
+        return result0;
+      }
+
+      function parse_contact_param() {
+        var result0, result1, result2, result3;
+        var pos0, pos1, pos2;
+        pos0 = pos;
+        pos1 = pos;
+        result0 = parse_SIP_URI_noparams();
+
+        if (result0 === null) {
+          result0 = parse_name_addr();
+        }
+
+        if (result0 !== null) {
+          result1 = [];
+          pos2 = pos;
+          result2 = parse_SEMI();
+
+          if (result2 !== null) {
+            result3 = parse_contact_params();
+
+            if (result3 !== null) {
+              result2 = [result2, result3];
+            } else {
+              result2 = null;
+              pos = pos2;
+            }
+          } else {
+            result2 = null;
+            pos = pos2;
+          }
+
+          while (result2 !== null) {
+            result1.push(result2);
+            pos2 = pos;
+            result2 = parse_SEMI();
+
+            if (result2 !== null) {
+              result3 = parse_contact_params();
+
+              if (result3 !== null) {
+                result2 = [result2, result3];
+              } else {
+                result2 = null;
+                pos = pos2;
+              }
+            } else {
+              result2 = null;
+              pos = pos2;
+            }
+          }
+
+          if (result1 !== null) {
+            result0 = [result0, result1];
+          } else {
+            result0 = null;
+            pos = pos1;
+          }
+        } else {
+          result0 = null;
+          pos = pos1;
+        }
+
+        if (result0 !== null) {
+          result0 = function (offset) {
+            var header;
+            if (!data.multi_header) data.multi_header = [];
+
+            try {
+              header = new NameAddrHeader(data.uri, data.display_name, data.params);
+              delete data.uri;
+              delete data.display_name;
+              delete data.params;
+            } catch (e) {
+              header = null;
+            }
+
+            data.multi_header.push({
+              'possition': pos,
+              'offset': offset,
+              'parsed': header
+            });
+          }(pos0);
+        }
+
+        if (result0 === null) {
+          pos = pos0;
+        }
+
+        return result0;
+      }
+
+      function parse_name_addr() {
+        var result0, result1, result2, result3;
+        var pos0;
+        pos0 = pos;
+        result0 = parse_display_name();
+        result0 = result0 !== null ? result0 : "";
+
+        if (result0 !== null) {
+          result1 = parse_LAQUOT();
+
+          if (result1 !== null) {
+            result2 = parse_SIP_URI();
+
+            if (result2 !== null) {
+              result3 = parse_RAQUOT();
+
+              if (result3 !== null) {
+                result0 = [result0, result1, result2, result3];
+              } else {
+                result0 = null;
+                pos = pos0;
+              }
+            } else {
+              result0 = null;
+              pos = pos0;
+            }
+          } else {
+            result0 = null;
+            pos = pos0;
+          }
+        } else {
+          result0 = null;
+          pos = pos0;
+        }
+
+        return result0;
+      }
+
+      function parse_display_name() {
+        var result0, result1, result2, result3;
+        var pos0, pos1, pos2;
+        pos0 = pos;
+        pos1 = pos;
+        result0 = parse_token();
+
+        if (result0 !== null) {
+          result1 = [];
+          pos2 = pos;
+          result2 = parse_LWS();
+
+          if (result2 !== null) {
+            result3 = parse_token();
+
+            if (result3 !== null) {
+              result2 = [result2, result3];
+            } else {
+              result2 = null;
+              pos = pos2;
+            }
+          } else {
+            result2 = null;
+            pos = pos2;
+          }
+
+          while (result2 !== null) {
+            result1.push(result2);
+            pos2 = pos;
+            result2 = parse_LWS();
+
+            if (result2 !== null) {
+              result3 = parse_token();
+
+              if (result3 !== null) {
+                result2 = [result2, result3];
+              } else {
+                result2 = null;
+                pos = pos2;
+              }
+            } else {
+              result2 = null;
+              pos = pos2;
+            }
+          }
+
+          if (result1 !== null) {
+            result0 = [result0, result1];
+          } else {
+            result0 = null;
+            pos = pos1;
+          }
+        } else {
+          result0 = null;
+          pos = pos1;
+        }
+
+        if (result0 === null) {
+          result0 = parse_quoted_string_clean();
+        }
+
+        if (result0 !== null) {
+          result0 = function (offset, display_name) {
+            if (typeof display_name === 'string') {
+              // quoted_string_clean
+              data.display_name = display_name;
+            } else {
+              // token ( LWS token )*
+              data.display_name = display_name[1].reduce(function (acc, cur) {
+                return acc + cur[0] + cur[1];
+              }, display_name[0]);
+            }
+          }(pos0, result0);
+        }
+
+        if (result0 === null) {
+          pos = pos0;
+        }
+
+        return result0;
+      }
+
+      function parse_contact_params() {
+        var result0;
+        result0 = parse_c_p_q();
+
+        if (result0 === null) {
+          result0 = parse_c_p_expires();
+
+          if (result0 === null) {
+            result0 = parse_generic_param();
+          }
+        }
+
+        return result0;
+      }
+
+      function parse_c_p_q() {
+        var result0, result1, result2;
+        var pos0, pos1;
+        pos0 = pos;
+        pos1 = pos;
+
+        if (input.substr(pos, 1).toLowerCase() === "q") {
+          result0 = input.substr(pos, 1);
+          pos++;
+        } else {
+          result0 = null;
+
+          if (reportFailures === 0) {
+            matchFailed("\"q\"");
+          }
+        }
+
+        if (result0 !== null) {
+          result1 = parse_EQUAL();
+
+          if (result1 !== null) {
+            result2 = parse_qvalue();
+
+            if (result2 !== null) {
+              result0 = [result0, result1, result2];
+            } else {
+              result0 = null;
+              pos = pos1;
+            }
+          } else {
+            result0 = null;
+            pos = pos1;
+          }
+        } else {
+          result0 = null;
+          pos = pos1;
+        }
+
+        if (result0 !== null) {
+          result0 = function (offset, q) {
+            if (!data.params) data.params = {};
+            data.params['q'] = q;
+          }(pos0, result0[2]);
+        }
+
+        if (result0 === null) {
+          pos = pos0;
+        }
+
+        return result0;
+      }
+
+      function parse_c_p_expires() {
+        var result0, result1, result2;
+        var pos0, pos1;
+        pos0 = pos;
+        pos1 = pos;
+
+        if (input.substr(pos, 7).toLowerCase() === "expires") {
+          result0 = input.substr(pos, 7);
+          pos += 7;
+        } else {
+          result0 = null;
+
+          if (reportFailures === 0) {
+            matchFailed("\"expires\"");
+          }
+        }
+
+        if (result0 !== null) {
+          result1 = parse_EQUAL();
+
+          if (result1 !== null) {
+            result2 = parse_delta_seconds();
+
+            if (result2 !== null) {
+              result0 = [result0, result1, result2];
+            } else {
+              result0 = null;
+              pos = pos1;
+            }
+          } else {
+            result0 = null;
+            pos = pos1;
+          }
+        } else {
+          result0 = null;
+          pos = pos1;
+        }
+
+        if (result0 !== null) {
+          result0 = function (offset, expires) {
+            if (!data.params) data.params = {};
+            data.params['expires'] = expires;
+          }(pos0, result0[2]);
+        }
+
+        if (result0 === null) {
+          pos = pos0;
+        }
+
+        return result0;
+      }
+
+      function parse_delta_seconds() {
+        var result0, result1;
+        var pos0;
+        pos0 = pos;
+        result1 = parse_DIGIT();
+
+        if (result1 !== null) {
+          result0 = [];
+
+          while (result1 !== null) {
+            result0.push(result1);
+            result1 = parse_DIGIT();
+          }
+        } else {
+          result0 = null;
+        }
+
+        if (result0 !== null) {
+          result0 = function (offset, delta_seconds) {
+            return parseInt(delta_seconds.join(''));
+          }(pos0, result0);
+        }
+
+        if (result0 === null) {
+          pos = pos0;
+        }
+
+        return result0;
+      }
+
+      function parse_qvalue() {
+        var result0, result1, result2, result3, result4;
+        var pos0, pos1, pos2;
+        pos0 = pos;
+        pos1 = pos;
+
+        if (input.charCodeAt(pos) === 48) {
+          result0 = "0";
+          pos++;
+        } else {
+          result0 = null;
+
+          if (reportFailures === 0) {
+            matchFailed("\"0\"");
+          }
+        }
+
+        if (result0 !== null) {
+          pos2 = pos;
+
+          if (input.charCodeAt(pos) === 46) {
+            result1 = ".";
+            pos++;
+          } else {
+            result1 = null;
+
+            if (reportFailures === 0) {
+              matchFailed("\".\"");
+            }
+          }
+
+          if (result1 !== null) {
+            result2 = parse_DIGIT();
+            result2 = result2 !== null ? result2 : "";
+
+            if (result2 !== null) {
+              result3 = parse_DIGIT();
+              result3 = result3 !== null ? result3 : "";
+
+              if (result3 !== null) {
+                result4 = parse_DIGIT();
+                result4 = result4 !== null ? result4 : "";
+
+                if (result4 !== null) {
+                  result1 = [result1, result2, result3, result4];
+                } else {
+                  result1 = null;
+                  pos = pos2;
+                }
+              } else {
+                result1 = null;
+                pos = pos2;
+              }
+            } else {
+              result1 = null;
+              pos = pos2;
+            }
+          } else {
+            result1 = null;
+            pos = pos2;
+          }
+
+          result1 = result1 !== null ? result1 : "";
+
+          if (result1 !== null) {
+            result0 = [result0, result1];
+          } else {
+            result0 = null;
+            pos = pos1;
+          }
+        } else {
+          result0 = null;
+          pos = pos1;
+        }
+
+        if (result0 !== null) {
+          result0 = function (offset) {
+            return parseFloat(input.substring(pos, offset));
+          }(pos0);
+        }
+
+        if (result0 === null) {
+          pos = pos0;
+        }
+
+        return result0;
+      }
+
+      function parse_generic_param() {
+        var result0, result1, result2;
+        var pos0, pos1, pos2;
+        pos0 = pos;
+        pos1 = pos;
+        result0 = parse_token();
+
+        if (result0 !== null) {
+          pos2 = pos;
+          result1 = parse_EQUAL();
+
+          if (result1 !== null) {
+            result2 = parse_gen_value();
+
+            if (result2 !== null) {
+              result1 = [result1, result2];
+            } else {
+              result1 = null;
+              pos = pos2;
+            }
+          } else {
+            result1 = null;
+            pos = pos2;
+          }
+
+          result1 = result1 !== null ? result1 : "";
+
+          if (result1 !== null) {
+            result0 = [result0, result1];
+          } else {
+            result0 = null;
+            pos = pos1;
+          }
+        } else {
+          result0 = null;
+          pos = pos1;
+        }
+
+        if (result0 !== null) {
+          result0 = function (offset, param, value) {
+            if (!data.params) data.params = {};
+
+            if (typeof value === 'undefined') {
+              value = undefined;
+            } else {
+              value = value[1];
+            }
+
+            data.params[param.toLowerCase()] = value;
+          }(pos0, result0[0], result0[1]);
+        }
+
+        if (result0 === null) {
+          pos = pos0;
+        }
+
+        return result0;
+      }
+
+      function parse_gen_value() {
+        var result0;
+        result0 = parse_token();
+
+        if (result0 === null) {
+          result0 = parse_host();
+
+          if (result0 === null) {
+            result0 = parse_quoted_string();
+          }
+        }
+
+        return result0;
+      }
+
+      function parse_Content_Disposition() {
+        var result0, result1, result2, result3;
+        var pos0, pos1;
+        pos0 = pos;
+        result0 = parse_disp_type();
+
+        if (result0 !== null) {
+          result1 = [];
+          pos1 = pos;
+          result2 = parse_SEMI();
+
+          if (result2 !== null) {
+            result3 = parse_disp_param();
+
+            if (result3 !== null) {
+              result2 = [result2, result3];
+            } else {
+              result2 = null;
+              pos = pos1;
+            }
+          } else {
+            result2 = null;
+            pos = pos1;
+          }
+
+          while (result2 !== null) {
+            result1.push(result2);
+            pos1 = pos;
+            result2 = parse_SEMI();
+
+            if (result2 !== null) {
+              result3 = parse_disp_param();
+
+              if (result3 !== null) {
+                result2 = [result2, result3];
+              } else {
+                result2 = null;
+                pos = pos1;
+              }
+            } else {
+              result2 = null;
+              pos = pos1;
+            }
+          }
+
+          if (result1 !== null) {
+            result0 = [result0, result1];
+          } else {
+            result0 = null;
+            pos = pos0;
+          }
+        } else {
+          result0 = null;
+          pos = pos0;
+        }
+
+        return result0;
+      }
+
+      function parse_disp_type() {
+        var result0;
+
+        if (input.substr(pos, 6).toLowerCase() === "render") {
+          result0 = input.substr(pos, 6);
+          pos += 6;
+        } else {
+          result0 = null;
+
+          if (reportFailures === 0) {
+            matchFailed("\"render\"");
+          }
+        }
+
+        if (result0 === null) {
+          if (input.substr(pos, 7).toLowerCase() === "session") {
+            result0 = input.substr(pos, 7);
+            pos += 7;
+          } else {
+            result0 = null;
+
+            if (reportFailures === 0) {
+              matchFailed("\"session\"");
+            }
+          }
+
+          if (result0 === null) {
+            if (input.substr(pos, 4).toLowerCase() === "icon") {
+              result0 = input.substr(pos, 4);
+              pos += 4;
+            } else {
+              result0 = null;
+
+              if (reportFailures === 0) {
+                matchFailed("\"icon\"");
+              }
+            }
+
+            if (result0 === null) {
+              if (input.substr(pos, 5).toLowerCase() === "alert") {
+                result0 = input.substr(pos, 5);
+                pos += 5;
+              } else {
+                result0 = null;
+
+                if (reportFailures === 0) {
+                  matchFailed("\"alert\"");
+                }
+              }
+
+              if (result0 === null) {
+                result0 = parse_token();
+              }
+            }
+          }
+        }
+
+        return result0;
+      }
+
+      function parse_disp_param() {
+        var result0;
+        result0 = parse_handling_param();
+
+        if (result0 === null) {
+          result0 = parse_generic_param();
+        }
+
+        return result0;
+      }
+
+      function parse_handling_param() {
+        var result0, result1, result2;
+        var pos0;
+        pos0 = pos;
+
+        if (input.substr(pos, 8).toLowerCase() === "handling") {
+          result0 = input.substr(pos, 8);
+          pos += 8;
+        } else {
+          result0 = null;
+
+          if (reportFailures === 0) {
+            matchFailed("\"handling\"");
+          }
+        }
+
+        if (result0 !== null) {
+          result1 = parse_EQUAL();
+
+          if (result1 !== null) {
+            if (input.substr(pos, 8).toLowerCase() === "optional") {
+              result2 = input.substr(pos, 8);
+              pos += 8;
+            } else {
+              result2 = null;
+
+              if (reportFailures === 0) {
+                matchFailed("\"optional\"");
+              }
+            }
+
+            if (result2 === null) {
+              if (input.substr(pos, 8).toLowerCase() === "required") {
+                result2 = input.substr(pos, 8);
+                pos += 8;
+              } else {
+                result2 = null;
+
+                if (reportFailures === 0) {
+                  matchFailed("\"required\"");
+                }
+              }
+
+              if (result2 === null) {
+                result2 = parse_token();
+              }
+            }
+
+            if (result2 !== null) {
+              result0 = [result0, result1, result2];
+            } else {
+              result0 = null;
+              pos = pos0;
+            }
+          } else {
+            result0 = null;
+            pos = pos0;
+          }
+        } else {
+          result0 = null;
+          pos = pos0;
+        }
+
+        return result0;
+      }
+
+      function parse_Content_Encoding() {
+        var result0, result1, result2, result3;
+        var pos0, pos1;
+        pos0 = pos;
+        result0 = parse_token();
+
+        if (result0 !== null) {
+          result1 = [];
+          pos1 = pos;
+          result2 = parse_COMMA();
+
+          if (result2 !== null) {
+            result3 = parse_token();
+
+            if (result3 !== null) {
+              result2 = [result2, result3];
+            } else {
+              result2 = null;
+              pos = pos1;
+            }
+          } else {
+            result2 = null;
+            pos = pos1;
+          }
+
+          while (result2 !== null) {
+            result1.push(result2);
+            pos1 = pos;
+            result2 = parse_COMMA();
+
+            if (result2 !== null) {
+              result3 = parse_token();
+
+              if (result3 !== null) {
+                result2 = [result2, result3];
+              } else {
+                result2 = null;
+                pos = pos1;
+              }
+            } else {
+              result2 = null;
+              pos = pos1;
+            }
+          }
+
+          if (result1 !== null) {
+            result0 = [result0, result1];
+          } else {
+            result0 = null;
+            pos = pos0;
+          }
+        } else {
+          result0 = null;
+          pos = pos0;
+        }
+
+        return result0;
+      }
+
+      function parse_Content_Length() {
+        var result0, result1;
+        var pos0;
+        pos0 = pos;
+        result1 = parse_DIGIT();
+
+        if (result1 !== null) {
+          result0 = [];
+
+          while (result1 !== null) {
+            result0.push(result1);
+            result1 = parse_DIGIT();
+          }
+        } else {
+          result0 = null;
+        }
+
+        if (result0 !== null) {
+          result0 = function (offset, length) {
+            data = parseInt(length.join(''));
+          }(pos0, result0);
+        }
+
+        if (result0 === null) {
+          pos = pos0;
+        }
+
+        return result0;
+      }
+
+      function parse_Content_Type() {
+        var result0;
+        var pos0;
+        pos0 = pos;
+        result0 = parse_media_type();
+
+        if (result0 !== null) {
+          result0 = function (offset) {
+            data = input.substring(pos, offset);
+          }(pos0);
+        }
+
+        if (result0 === null) {
+          pos = pos0;
+        }
+
+        return result0;
+      }
+
+      function parse_media_type() {
+        var result0, result1, result2, result3, result4, result5;
+        var pos0, pos1;
+        pos0 = pos;
+        result0 = parse_m_type();
+
+        if (result0 !== null) {
+          result1 = parse_SLASH();
+
+          if (result1 !== null) {
+            result2 = parse_m_subtype();
+
+            if (result2 !== null) {
+              result3 = [];
+              pos1 = pos;
+              result4 = parse_SEMI();
+
+              if (result4 !== null) {
+                result5 = parse_m_parameter();
+
+                if (result5 !== null) {
+                  result4 = [result4, result5];
+                } else {
+                  result4 = null;
+                  pos = pos1;
+                }
+              } else {
+                result4 = null;
+                pos = pos1;
+              }
+
+              while (result4 !== null) {
+                result3.push(result4);
+                pos1 = pos;
+                result4 = parse_SEMI();
+
+                if (result4 !== null) {
+                  result5 = parse_m_parameter();
+
+                  if (result5 !== null) {
+                    result4 = [result4, result5];
+                  } else {
+                    result4 = null;
+                    pos = pos1;
+                  }
+                } else {
+                  result4 = null;
+                  pos = pos1;
+                }
+              }
+
+              if (result3 !== null) {
+                result0 = [result0, result1, result2, result3];
+              } else {
+                result0 = null;
+                pos = pos0;
+              }
+            } else {
+              result0 = null;
+              pos = pos0;
+            }
+          } else {
+            result0 = null;
+            pos = pos0;
+          }
+        } else {
+          result0 = null;
+          pos = pos0;
+        }
+
+        return result0;
+      }
+
+      function parse_m_type() {
+        var result0;
+        result0 = parse_discrete_type();
+
+        if (result0 === null) {
+          result0 = parse_composite_type();
+        }
+
+        return result0;
+      }
+
+      function parse_discrete_type() {
+        var result0;
+
+        if (input.substr(pos, 4).toLowerCase() === "text") {
+          result0 = input.substr(pos, 4);
+          pos += 4;
+        } else {
+          result0 = null;
+
+          if (reportFailures === 0) {
+            matchFailed("\"text\"");
+          }
+        }
+
+        if (result0 === null) {
+          if (input.substr(pos, 5).toLowerCase() === "image") {
+            result0 = input.substr(pos, 5);
+            pos += 5;
+          } else {
+            result0 = null;
+
+            if (reportFailures === 0) {
+              matchFailed("\"image\"");
+            }
+          }
+
+          if (result0 === null) {
+            if (input.substr(pos, 5).toLowerCase() === "audio") {
+              result0 = input.substr(pos, 5);
+              pos += 5;
+            } else {
+              result0 = null;
+
+              if (reportFailures === 0) {
+                matchFailed("\"audio\"");
+              }
+            }
+
+            if (result0 === null) {
+              if (input.substr(pos, 5).toLowerCase() === "video") {
+                result0 = input.substr(pos, 5);
+                pos += 5;
+              } else {
+                result0 = null;
+
+                if (reportFailures === 0) {
+                  matchFailed("\"video\"");
+                }
+              }
+
+              if (result0 === null) {
+                if (input.substr(pos, 11).toLowerCase() === "application") {
+                  result0 = input.substr(pos, 11);
+                  pos += 11;
+                } else {
+                  result0 = null;
+
+                  if (reportFailures === 0) {
+                    matchFailed("\"application\"");
+                  }
+                }
+
+                if (result0 === null) {
+                  result0 = parse_extension_token();
+                }
+              }
+            }
+          }
+        }
+
+        return result0;
+      }
+
+      function parse_composite_type() {
+        var result0;
+
+        if (input.substr(pos, 7).toLowerCase() === "message") {
+          result0 = input.substr(pos, 7);
+          pos += 7;
+        } else {
+          result0 = null;
+
+          if (reportFailures === 0) {
+            matchFailed("\"message\"");
+          }
+        }
+
+        if (result0 === null) {
+          if (input.substr(pos, 9).toLowerCase() === "multipart") {
+            result0 = input.substr(pos, 9);
+            pos += 9;
+          } else {
+            result0 = null;
+
+            if (reportFailures === 0) {
+              matchFailed("\"multipart\"");
+            }
+          }
+
+          if (result0 === null) {
+            result0 = parse_extension_token();
+          }
+        }
+
+        return result0;
+      }
+
+      function parse_extension_token() {
+        var result0;
+        result0 = parse_token();
+
+        if (result0 === null) {
+          result0 = parse_x_token();
+        }
+
+        return result0;
+      }
+
+      function parse_x_token() {
+        var result0, result1;
+        var pos0;
+        pos0 = pos;
+
+        if (input.substr(pos, 2).toLowerCase() === "x-") {
+          result0 = input.substr(pos, 2);
+          pos += 2;
+        } else {
+          result0 = null;
+
+          if (reportFailures === 0) {
+            matchFailed("\"x-\"");
+          }
+        }
+
+        if (result0 !== null) {
+          result1 = parse_token();
+
+          if (result1 !== null) {
+            result0 = [result0, result1];
+          } else {
+            result0 = null;
+            pos = pos0;
+          }
+        } else {
+          result0 = null;
+          pos = pos0;
+        }
+
+        return result0;
+      }
+
+      function parse_m_subtype() {
+        var result0;
+        result0 = parse_extension_token();
+
+        if (result0 === null) {
+          result0 = parse_token();
+        }
+
+        return result0;
+      }
+
+      function parse_m_parameter() {
+        var result0, result1, result2;
+        var pos0;
+        pos0 = pos;
+        result0 = parse_token();
+
+        if (result0 !== null) {
+          result1 = parse_EQUAL();
+
+          if (result1 !== null) {
+            result2 = parse_m_value();
+
+            if (result2 !== null) {
+              result0 = [result0, result1, result2];
+            } else {
+              result0 = null;
+              pos = pos0;
+            }
+          } else {
+            result0 = null;
+            pos = pos0;
+          }
+        } else {
+          result0 = null;
+          pos = pos0;
+        }
+
+        return result0;
+      }
+
+      function parse_m_value() {
+        var result0;
+        result0 = parse_token();
+
+        if (result0 === null) {
+          result0 = parse_quoted_string();
+        }
+
+        return result0;
+      }
+
+      function parse_CSeq() {
+        var result0, result1, result2;
+        var pos0;
+        pos0 = pos;
+        result0 = parse_CSeq_value();
+
+        if (result0 !== null) {
+          result1 = parse_LWS();
+
+          if (result1 !== null) {
+            result2 = parse_Method();
+
+            if (result2 !== null) {
+              result0 = [result0, result1, result2];
+            } else {
+              result0 = null;
+              pos = pos0;
+            }
+          } else {
+            result0 = null;
+            pos = pos0;
+          }
+        } else {
+          result0 = null;
+          pos = pos0;
+        }
+
+        return result0;
+      }
+
+      function parse_CSeq_value() {
+        var result0, result1;
+        var pos0;
+        pos0 = pos;
+        result1 = parse_DIGIT();
+
+        if (result1 !== null) {
+          result0 = [];
+
+          while (result1 !== null) {
+            result0.push(result1);
+            result1 = parse_DIGIT();
+          }
+        } else {
+          result0 = null;
+        }
+
+        if (result0 !== null) {
+          result0 = function (offset, cseq_value) {
+            data.value = parseInt(cseq_value.join(''));
+          }(pos0, result0);
+        }
+
+        if (result0 === null) {
+          pos = pos0;
+        }
+
+        return result0;
+      }
+
+      function parse_Expires() {
+        var result0;
+        var pos0;
+        pos0 = pos;
+        result0 = parse_delta_seconds();
+
+        if (result0 !== null) {
+          result0 = function (offset, expires) {
+            data = expires;
+          }(pos0, result0);
+        }
+
+        if (result0 === null) {
+          pos = pos0;
+        }
+
+        return result0;
+      }
+
+      function parse_Event() {
+        var result0, result1, result2, result3;
+        var pos0, pos1, pos2;
+        pos0 = pos;
+        pos1 = pos;
+        result0 = parse_event_type();
+
+        if (result0 !== null) {
+          result1 = [];
+          pos2 = pos;
+          result2 = parse_SEMI();
+
+          if (result2 !== null) {
+            result3 = parse_generic_param();
+
+            if (result3 !== null) {
+              result2 = [result2, result3];
+            } else {
+              result2 = null;
+              pos = pos2;
+            }
+          } else {
+            result2 = null;
+            pos = pos2;
+          }
+
+          while (result2 !== null) {
+            result1.push(result2);
+            pos2 = pos;
+            result2 = parse_SEMI();
+
+            if (result2 !== null) {
+              result3 = parse_generic_param();
+
+              if (result3 !== null) {
+                result2 = [result2, result3];
+              } else {
+                result2 = null;
+                pos = pos2;
+              }
+            } else {
+              result2 = null;
+              pos = pos2;
+            }
+          }
+
+          if (result1 !== null) {
+            result0 = [result0, result1];
+          } else {
+            result0 = null;
+            pos = pos1;
+          }
+        } else {
+          result0 = null;
+          pos = pos1;
+        }
+
+        if (result0 !== null) {
+          result0 = function (offset, event_type) {
+            data.event = event_type.join('').toLowerCase();
+          }(pos0, result0[0]);
+        }
+
+        if (result0 === null) {
+          pos = pos0;
+        }
+
+        return result0;
+      }
+
+      function parse_event_type() {
+        var result0, result1, result2, result3;
+        var pos0, pos1;
+        pos0 = pos;
+        result0 = parse_token_nodot();
+
+        if (result0 !== null) {
+          result1 = [];
+          pos1 = pos;
+
+          if (input.charCodeAt(pos) === 46) {
+            result2 = ".";
+            pos++;
+          } else {
+            result2 = null;
+
+            if (reportFailures === 0) {
+              matchFailed("\".\"");
+            }
+          }
+
+          if (result2 !== null) {
+            result3 = parse_token_nodot();
+
+            if (result3 !== null) {
+              result2 = [result2, result3];
+            } else {
+              result2 = null;
+              pos = pos1;
+            }
+          } else {
+            result2 = null;
+            pos = pos1;
+          }
+
+          while (result2 !== null) {
+            result1.push(result2);
+            pos1 = pos;
+
+            if (input.charCodeAt(pos) === 46) {
+              result2 = ".";
+              pos++;
+            } else {
+              result2 = null;
+
+              if (reportFailures === 0) {
+                matchFailed("\".\"");
+              }
+            }
+
+            if (result2 !== null) {
+              result3 = parse_token_nodot();
+
+              if (result3 !== null) {
+                result2 = [result2, result3];
+              } else {
+                result2 = null;
+                pos = pos1;
+              }
+            } else {
+              result2 = null;
+              pos = pos1;
+            }
+          }
+
+          if (result1 !== null) {
+            result0 = [result0, result1];
+          } else {
+            result0 = null;
+            pos = pos0;
+          }
+        } else {
+          result0 = null;
+          pos = pos0;
+        }
+
+        return result0;
+      }
+
+      function parse_From() {
+        var result0, result1, result2, result3;
+        var pos0, pos1, pos2;
+        pos0 = pos;
+        pos1 = pos;
+        result0 = parse_SIP_URI_noparams();
+
+        if (result0 === null) {
+          result0 = parse_name_addr();
+        }
+
+        if (result0 !== null) {
+          result1 = [];
+          pos2 = pos;
+          result2 = parse_SEMI();
+
+          if (result2 !== null) {
+            result3 = parse_from_param();
+
+            if (result3 !== null) {
+              result2 = [result2, result3];
+            } else {
+              result2 = null;
+              pos = pos2;
+            }
+          } else {
+            result2 = null;
+            pos = pos2;
+          }
+
+          while (result2 !== null) {
+            result1.push(result2);
+            pos2 = pos;
+            result2 = parse_SEMI();
+
+            if (result2 !== null) {
+              result3 = parse_from_param();
+
+              if (result3 !== null) {
+                result2 = [result2, result3];
+              } else {
+                result2 = null;
+                pos = pos2;
+              }
+            } else {
+              result2 = null;
+              pos = pos2;
+            }
+          }
+
+          if (result1 !== null) {
+            result0 = [result0, result1];
+          } else {
+            result0 = null;
+            pos = pos1;
+          }
+        } else {
+          result0 = null;
+          pos = pos1;
+        }
+
+        if (result0 !== null) {
+          result0 = function (offset) {
+            var tag = data.tag;
+
+            try {
+              data = new NameAddrHeader(data.uri, data.display_name, data.params);
+
+              if (tag) {
+                data.setParam('tag', tag);
+              }
+            } catch (e) {
+              data = -1;
+            }
+          }(pos0);
+        }
+
+        if (result0 === null) {
+          pos = pos0;
+        }
+
+        return result0;
+      }
+
+      function parse_from_param() {
+        var result0;
+        result0 = parse_tag_param();
+
+        if (result0 === null) {
+          result0 = parse_generic_param();
+        }
+
+        return result0;
+      }
+
+      function parse_tag_param() {
+        var result0, result1, result2;
+        var pos0, pos1;
+        pos0 = pos;
+        pos1 = pos;
+
+        if (input.substr(pos, 3).toLowerCase() === "tag") {
+          result0 = input.substr(pos, 3);
+          pos += 3;
+        } else {
+          result0 = null;
+
+          if (reportFailures === 0) {
+            matchFailed("\"tag\"");
+          }
+        }
+
+        if (result0 !== null) {
+          result1 = parse_EQUAL();
+
+          if (result1 !== null) {
+            result2 = parse_token();
+
+            if (result2 !== null) {
+              result0 = [result0, result1, result2];
+            } else {
+              result0 = null;
+              pos = pos1;
+            }
+          } else {
+            result0 = null;
+            pos = pos1;
+          }
+        } else {
+          result0 = null;
+          pos = pos1;
+        }
+
+        if (result0 !== null) {
+          result0 = function (offset, tag) {
+            data.tag = tag;
+          }(pos0, result0[2]);
+        }
+
+        if (result0 === null) {
+          pos = pos0;
+        }
+
+        return result0;
+      }
+
+      function parse_Max_Forwards() {
+        var result0, result1;
+        var pos0;
+        pos0 = pos;
+        result1 = parse_DIGIT();
+
+        if (result1 !== null) {
+          result0 = [];
+
+          while (result1 !== null) {
+            result0.push(result1);
+            result1 = parse_DIGIT();
+          }
+        } else {
+          result0 = null;
+        }
+
+        if (result0 !== null) {
+          result0 = function (offset, forwards) {
+            data = parseInt(forwards.join(''));
+          }(pos0, result0);
+        }
+
+        if (result0 === null) {
+          pos = pos0;
+        }
+
+        return result0;
+      }
+
+      function parse_Min_Expires() {
+        var result0;
+        var pos0;
+        pos0 = pos;
+        result0 = parse_delta_seconds();
+
+        if (result0 !== null) {
+          result0 = function (offset, min_expires) {
+            data = min_expires;
+          }(pos0, result0);
+        }
+
+        if (result0 === null) {
+          pos = pos0;
+        }
+
+        return result0;
+      }
+
+      function parse_Name_Addr_Header() {
+        var result0, result1, result2, result3, result4, result5, result6;
+        var pos0, pos1, pos2;
+        pos0 = pos;
+        pos1 = pos;
+        result0 = [];
+        result1 = parse_display_name();
+
+        while (result1 !== null) {
+          result0.push(result1);
+          result1 = parse_display_name();
+        }
+
+        if (result0 !== null) {
+          result1 = parse_LAQUOT();
+
+          if (result1 !== null) {
+            result2 = parse_SIP_URI();
+
+            if (result2 !== null) {
+              result3 = parse_RAQUOT();
+
+              if (result3 !== null) {
+                result4 = [];
+                pos2 = pos;
+                result5 = parse_SEMI();
+
+                if (result5 !== null) {
+                  result6 = parse_generic_param();
+
+                  if (result6 !== null) {
+                    result5 = [result5, result6];
+                  } else {
+                    result5 = null;
+                    pos = pos2;
+                  }
+                } else {
+                  result5 = null;
+                  pos = pos2;
+                }
+
+                while (result5 !== null) {
+                  result4.push(result5);
+                  pos2 = pos;
+                  result5 = parse_SEMI();
+
+                  if (result5 !== null) {
+                    result6 = parse_generic_param();
+
+                    if (result6 !== null) {
+                      result5 = [result5, result6];
+                    } else {
+                      result5 = null;
+                      pos = pos2;
+                    }
+                  } else {
+                    result5 = null;
+                    pos = pos2;
+                  }
+                }
+
+                if (result4 !== null) {
+                  result0 = [result0, result1, result2, result3, result4];
+                } else {
+                  result0 = null;
+                  pos = pos1;
+                }
+              } else {
+                result0 = null;
+                pos = pos1;
+              }
+            } else {
+              result0 = null;
+              pos = pos1;
+            }
+          } else {
+            result0 = null;
+            pos = pos1;
+          }
+        } else {
+          result0 = null;
+          pos = pos1;
+        }
+
+        if (result0 !== null) {
+          result0 = function (offset) {
+            try {
+              data = new NameAddrHeader(data.uri, data.display_name, data.params);
+            } catch (e) {
+              data = -1;
+            }
+          }(pos0);
+        }
+
+        if (result0 === null) {
+          pos = pos0;
+        }
+
+        return result0;
+      }
+
+      function parse_Proxy_Authenticate() {
+        var result0;
+        result0 = parse_challenge();
+        return result0;
+      }
+
+      function parse_challenge() {
+        var result0, result1, result2, result3, result4, result5;
+        var pos0, pos1;
+        pos0 = pos;
+
+        if (input.substr(pos, 6).toLowerCase() === "digest") {
+          result0 = input.substr(pos, 6);
+          pos += 6;
+        } else {
+          result0 = null;
+
+          if (reportFailures === 0) {
+            matchFailed("\"Digest\"");
+          }
+        }
+
+        if (result0 !== null) {
+          result1 = parse_LWS();
+
+          if (result1 !== null) {
+            result2 = parse_digest_cln();
+
+            if (result2 !== null) {
+              result3 = [];
+              pos1 = pos;
+              result4 = parse_COMMA();
+
+              if (result4 !== null) {
+                result5 = parse_digest_cln();
+
+                if (result5 !== null) {
+                  result4 = [result4, result5];
+                } else {
+                  result4 = null;
+                  pos = pos1;
+                }
+              } else {
+                result4 = null;
+                pos = pos1;
+              }
+
+              while (result4 !== null) {
+                result3.push(result4);
+                pos1 = pos;
+                result4 = parse_COMMA();
+
+                if (result4 !== null) {
+                  result5 = parse_digest_cln();
+
+                  if (result5 !== null) {
+                    result4 = [result4, result5];
+                  } else {
+                    result4 = null;
+                    pos = pos1;
+                  }
+                } else {
+                  result4 = null;
+                  pos = pos1;
+                }
+              }
+
+              if (result3 !== null) {
+                result0 = [result0, result1, result2, result3];
+              } else {
+                result0 = null;
+                pos = pos0;
+              }
+            } else {
+              result0 = null;
+              pos = pos0;
+            }
+          } else {
+            result0 = null;
+            pos = pos0;
+          }
+        } else {
+          result0 = null;
+          pos = pos0;
+        }
+
+        if (result0 === null) {
+          result0 = parse_other_challenge();
+        }
+
+        return result0;
+      }
+
+      function parse_other_challenge() {
+        var result0, result1, result2, result3, result4, result5;
+        var pos0, pos1;
+        pos0 = pos;
+        result0 = parse_token();
+
+        if (result0 !== null) {
+          result1 = parse_LWS();
+
+          if (result1 !== null) {
+            result2 = parse_auth_param();
+
+            if (result2 !== null) {
+              result3 = [];
+              pos1 = pos;
+              result4 = parse_COMMA();
+
+              if (result4 !== null) {
+                result5 = parse_auth_param();
+
+                if (result5 !== null) {
+                  result4 = [result4, result5];
+                } else {
+                  result4 = null;
+                  pos = pos1;
+                }
+              } else {
+                result4 = null;
+                pos = pos1;
+              }
+
+              while (result4 !== null) {
+                result3.push(result4);
+                pos1 = pos;
+                result4 = parse_COMMA();
+
+                if (result4 !== null) {
+                  result5 = parse_auth_param();
+
+                  if (result5 !== null) {
+                    result4 = [result4, result5];
+                  } else {
+                    result4 = null;
+                    pos = pos1;
+                  }
+                } else {
+                  result4 = null;
+                  pos = pos1;
+                }
+              }
+
+              if (result3 !== null) {
+                result0 = [result0, result1, result2, result3];
+              } else {
+                result0 = null;
+                pos = pos0;
+              }
+            } else {
+              result0 = null;
+              pos = pos0;
+            }
+          } else {
+            result0 = null;
+            pos = pos0;
+          }
+        } else {
+          result0 = null;
+          pos = pos0;
+        }
+
+        return result0;
+      }
+
+      function parse_auth_param() {
+        var result0, result1, result2;
+        var pos0;
+        pos0 = pos;
+        result0 = parse_token();
+
+        if (result0 !== null) {
+          result1 = parse_EQUAL();
+
+          if (result1 !== null) {
+            result2 = parse_token();
+
+            if (result2 === null) {
+              result2 = parse_quoted_string();
+            }
+
+            if (result2 !== null) {
+              result0 = [result0, result1, result2];
+            } else {
+              result0 = null;
+              pos = pos0;
+            }
+          } else {
+            result0 = null;
+            pos = pos0;
+          }
+        } else {
+          result0 = null;
+          pos = pos0;
+        }
+
+        return result0;
+      }
+
+      function parse_digest_cln() {
+        var result0;
+        result0 = parse_realm();
+
+        if (result0 === null) {
+          result0 = parse_domain();
+
+          if (result0 === null) {
+            result0 = parse_nonce();
+
+            if (result0 === null) {
+              result0 = parse_opaque();
+
+              if (result0 === null) {
+                result0 = parse_stale();
+
+                if (result0 === null) {
+                  result0 = parse_algorithm();
+
+                  if (result0 === null) {
+                    result0 = parse_qop_options();
+
+                    if (result0 === null) {
+                      result0 = parse_auth_param();
+                    }
+                  }
+                }
+              }
+            }
+          }
+        }
+
+        return result0;
+      }
+
+      function parse_realm() {
+        var result0, result1, result2;
+        var pos0;
+        pos0 = pos;
+
+        if (input.substr(pos, 5).toLowerCase() === "realm") {
+          result0 = input.substr(pos, 5);
+          pos += 5;
+        } else {
+          result0 = null;
+
+          if (reportFailures === 0) {
+            matchFailed("\"realm\"");
+          }
+        }
+
+        if (result0 !== null) {
+          result1 = parse_EQUAL();
+
+          if (result1 !== null) {
+            result2 = parse_realm_value();
+
+            if (result2 !== null) {
+              result0 = [result0, result1, result2];
+            } else {
+              result0 = null;
+              pos = pos0;
+            }
+          } else {
+            result0 = null;
+            pos = pos0;
+          }
+        } else {
+          result0 = null;
+          pos = pos0;
+        }
+
+        return result0;
+      }
+
+      function parse_realm_value() {
+        var result0;
+        var pos0;
+        pos0 = pos;
+        result0 = parse_quoted_string_clean();
+
+        if (result0 !== null) {
+          result0 = function (offset, realm) {
+            data.realm = realm;
+          }(pos0, result0);
+        }
+
+        if (result0 === null) {
+          pos = pos0;
+        }
+
+        return result0;
+      }
+
+      function parse_domain() {
+        var result0, result1, result2, result3, result4, result5, result6;
+        var pos0, pos1;
+        pos0 = pos;
+
+        if (input.substr(pos, 6).toLowerCase() === "domain") {
+          result0 = input.substr(pos, 6);
+          pos += 6;
+        } else {
+          result0 = null;
+
+          if (reportFailures === 0) {
+            matchFailed("\"domain\"");
+          }
+        }
+
+        if (result0 !== null) {
+          result1 = parse_EQUAL();
+
+          if (result1 !== null) {
+            result2 = parse_LDQUOT();
+
+            if (result2 !== null) {
+              result3 = parse_URI();
+
+              if (result3 !== null) {
+                result4 = [];
+                pos1 = pos;
+                result6 = parse_SP();
+
+                if (result6 !== null) {
+                  result5 = [];
+
+                  while (result6 !== null) {
+                    result5.push(result6);
+                    result6 = parse_SP();
+                  }
+                } else {
+                  result5 = null;
+                }
+
+                if (result5 !== null) {
+                  result6 = parse_URI();
+
+                  if (result6 !== null) {
+                    result5 = [result5, result6];
+                  } else {
+                    result5 = null;
+                    pos = pos1;
+                  }
+                } else {
+                  result5 = null;
+                  pos = pos1;
+                }
+
+                while (result5 !== null) {
+                  result4.push(result5);
+                  pos1 = pos;
+                  result6 = parse_SP();
+
+                  if (result6 !== null) {
+                    result5 = [];
+
+                    while (result6 !== null) {
+                      result5.push(result6);
+                      result6 = parse_SP();
+                    }
+                  } else {
+                    result5 = null;
+                  }
+
+                  if (result5 !== null) {
+                    result6 = parse_URI();
+
+                    if (result6 !== null) {
+                      result5 = [result5, result6];
+                    } else {
+                      result5 = null;
+                      pos = pos1;
+                    }
+                  } else {
+                    result5 = null;
+                    pos = pos1;
+                  }
+                }
+
+                if (result4 !== null) {
+                  result5 = parse_RDQUOT();
+
+                  if (result5 !== null) {
+                    result0 = [result0, result1, result2, result3, result4, result5];
+                  } else {
+                    result0 = null;
+                    pos = pos0;
+                  }
+                } else {
+                  result0 = null;
+                  pos = pos0;
+                }
+              } else {
+                result0 = null;
+                pos = pos0;
+              }
+            } else {
+              result0 = null;
+              pos = pos0;
+            }
+          } else {
+            result0 = null;
+            pos = pos0;
+          }
+        } else {
+          result0 = null;
+          pos = pos0;
+        }
+
+        return result0;
+      }
+
+      function parse_URI() {
+        var result0;
+        result0 = parse_absoluteURI();
+
+        if (result0 === null) {
+          result0 = parse_abs_path();
+        }
+
+        return result0;
+      }
+
+      function parse_nonce() {
+        var result0, result1, result2;
+        var pos0;
+        pos0 = pos;
+
+        if (input.substr(pos, 5).toLowerCase() === "nonce") {
+          result0 = input.substr(pos, 5);
+          pos += 5;
+        } else {
+          result0 = null;
+
+          if (reportFailures === 0) {
+            matchFailed("\"nonce\"");
+          }
+        }
+
+        if (result0 !== null) {
+          result1 = parse_EQUAL();
+
+          if (result1 !== null) {
+            result2 = parse_nonce_value();
+
+            if (result2 !== null) {
+              result0 = [result0, result1, result2];
+            } else {
+              result0 = null;
+              pos = pos0;
+            }
+          } else {
+            result0 = null;
+            pos = pos0;
+          }
+        } else {
+          result0 = null;
+          pos = pos0;
+        }
+
+        return result0;
+      }
+
+      function parse_nonce_value() {
+        var result0;
+        var pos0;
+        pos0 = pos;
+        result0 = parse_quoted_string_clean();
+
+        if (result0 !== null) {
+          result0 = function (offset, nonce) {
+            data.nonce = nonce;
+          }(pos0, result0);
+        }
+
+        if (result0 === null) {
+          pos = pos0;
+        }
+
+        return result0;
+      }
+
+      function parse_opaque() {
+        var result0, result1, result2;
+        var pos0, pos1;
+        pos0 = pos;
+        pos1 = pos;
+
+        if (input.substr(pos, 6).toLowerCase() === "opaque") {
+          result0 = input.substr(pos, 6);
+          pos += 6;
+        } else {
+          result0 = null;
+
+          if (reportFailures === 0) {
+            matchFailed("\"opaque\"");
+          }
+        }
+
+        if (result0 !== null) {
+          result1 = parse_EQUAL();
+
+          if (result1 !== null) {
+            result2 = parse_quoted_string_clean();
+
+            if (result2 !== null) {
+              result0 = [result0, result1, result2];
+            } else {
+              result0 = null;
+              pos = pos1;
+            }
+          } else {
+            result0 = null;
+            pos = pos1;
+          }
+        } else {
+          result0 = null;
+          pos = pos1;
+        }
+
+        if (result0 !== null) {
+          result0 = function (offset, opaque) {
+            data.opaque = opaque;
+          }(pos0, result0[2]);
+        }
+
+        if (result0 === null) {
+          pos = pos0;
+        }
+
+        return result0;
+      }
+
+      function parse_stale() {
+        var result0, result1, result2;
+        var pos0, pos1;
+        pos0 = pos;
+
+        if (input.substr(pos, 5).toLowerCase() === "stale") {
+          result0 = input.substr(pos, 5);
+          pos += 5;
+        } else {
+          result0 = null;
+
+          if (reportFailures === 0) {
+            matchFailed("\"stale\"");
+          }
+        }
+
+        if (result0 !== null) {
+          result1 = parse_EQUAL();
+
+          if (result1 !== null) {
+            pos1 = pos;
+
+            if (input.substr(pos, 4).toLowerCase() === "true") {
+              result2 = input.substr(pos, 4);
+              pos += 4;
+            } else {
+              result2 = null;
+
+              if (reportFailures === 0) {
+                matchFailed("\"true\"");
+              }
+            }
+
+            if (result2 !== null) {
+              result2 = function (offset) {
+                data.stale = true;
+              }(pos1);
+            }
+
+            if (result2 === null) {
+              pos = pos1;
+            }
+
+            if (result2 === null) {
+              pos1 = pos;
+
+              if (input.substr(pos, 5).toLowerCase() === "false") {
+                result2 = input.substr(pos, 5);
+                pos += 5;
+              } else {
+                result2 = null;
+
+                if (reportFailures === 0) {
+                  matchFailed("\"false\"");
+                }
+              }
+
+              if (result2 !== null) {
+                result2 = function (offset) {
+                  data.stale = false;
+                }(pos1);
+              }
+
+              if (result2 === null) {
+                pos = pos1;
+              }
+            }
+
+            if (result2 !== null) {
+              result0 = [result0, result1, result2];
+            } else {
+              result0 = null;
+              pos = pos0;
+            }
+          } else {
+            result0 = null;
+            pos = pos0;
+          }
+        } else {
+          result0 = null;
+          pos = pos0;
+        }
+
+        return result0;
+      }
+
+      function parse_algorithm() {
+        var result0, result1, result2;
+        var pos0, pos1;
+        pos0 = pos;
+        pos1 = pos;
+
+        if (input.substr(pos, 9).toLowerCase() === "algorithm") {
+          result0 = input.substr(pos, 9);
+          pos += 9;
+        } else {
+          result0 = null;
+
+          if (reportFailures === 0) {
+            matchFailed("\"algorithm\"");
+          }
+        }
+
+        if (result0 !== null) {
+          result1 = parse_EQUAL();
+
+          if (result1 !== null) {
+            if (input.substr(pos, 3).toLowerCase() === "md5") {
+              result2 = input.substr(pos, 3);
+              pos += 3;
+            } else {
+              result2 = null;
+
+              if (reportFailures === 0) {
+                matchFailed("\"MD5\"");
+              }
+            }
+
+            if (result2 === null) {
+              if (input.substr(pos, 8).toLowerCase() === "md5-sess") {
+                result2 = input.substr(pos, 8);
+                pos += 8;
+              } else {
+                result2 = null;
+
+                if (reportFailures === 0) {
+                  matchFailed("\"MD5-sess\"");
+                }
+              }
+
+              if (result2 === null) {
+                result2 = parse_token();
+              }
+            }
+
+            if (result2 !== null) {
+              result0 = [result0, result1, result2];
+            } else {
+              result0 = null;
+              pos = pos1;
+            }
+          } else {
+            result0 = null;
+            pos = pos1;
+          }
+        } else {
+          result0 = null;
+          pos = pos1;
+        }
+
+        if (result0 !== null) {
+          result0 = function (offset, algorithm) {
+            data.algorithm = algorithm.toUpperCase();
+          }(pos0, result0[2]);
+        }
+
+        if (result0 === null) {
+          pos = pos0;
+        }
+
+        return result0;
+      }
+
+      function parse_qop_options() {
+        var result0, result1, result2, result3, result4, result5, result6;
+        var pos0, pos1, pos2;
+        pos0 = pos;
+
+        if (input.substr(pos, 3).toLowerCase() === "qop") {
+          result0 = input.substr(pos, 3);
+          pos += 3;
+        } else {
+          result0 = null;
+
+          if (reportFailures === 0) {
+            matchFailed("\"qop\"");
+          }
+        }
+
+        if (result0 !== null) {
+          result1 = parse_EQUAL();
+
+          if (result1 !== null) {
+            result2 = parse_LDQUOT();
+
+            if (result2 !== null) {
+              pos1 = pos;
+              result3 = parse_qop_value();
+
+              if (result3 !== null) {
+                result4 = [];
+                pos2 = pos;
+
+                if (input.charCodeAt(pos) === 44) {
+                  result5 = ",";
+                  pos++;
+                } else {
+                  result5 = null;
+
+                  if (reportFailures === 0) {
+                    matchFailed("\",\"");
+                  }
+                }
+
+                if (result5 !== null) {
+                  result6 = parse_qop_value();
+
+                  if (result6 !== null) {
+                    result5 = [result5, result6];
+                  } else {
+                    result5 = null;
+                    pos = pos2;
+                  }
+                } else {
+                  result5 = null;
+                  pos = pos2;
+                }
+
+                while (result5 !== null) {
+                  result4.push(result5);
+                  pos2 = pos;
+
+                  if (input.charCodeAt(pos) === 44) {
+                    result5 = ",";
+                    pos++;
+                  } else {
+                    result5 = null;
+
+                    if (reportFailures === 0) {
+                      matchFailed("\",\"");
+                    }
+                  }
+
+                  if (result5 !== null) {
+                    result6 = parse_qop_value();
+
+                    if (result6 !== null) {
+                      result5 = [result5, result6];
+                    } else {
+                      result5 = null;
+                      pos = pos2;
+                    }
+                  } else {
+                    result5 = null;
+                    pos = pos2;
+                  }
+                }
+
+                if (result4 !== null) {
+                  result3 = [result3, result4];
+                } else {
+                  result3 = null;
+                  pos = pos1;
+                }
+              } else {
+                result3 = null;
+                pos = pos1;
+              }
+
+              if (result3 !== null) {
+                result4 = parse_RDQUOT();
+
+                if (result4 !== null) {
+                  result0 = [result0, result1, result2, result3, result4];
+                } else {
+                  result0 = null;
+                  pos = pos0;
+                }
+              } else {
+                result0 = null;
+                pos = pos0;
+              }
+            } else {
+              result0 = null;
+              pos = pos0;
+            }
+          } else {
+            result0 = null;
+            pos = pos0;
+          }
+        } else {
+          result0 = null;
+          pos = pos0;
+        }
+
+        return result0;
+      }
+
+      function parse_qop_value() {
+        var result0;
+        var pos0;
+        pos0 = pos;
+
+        if (input.substr(pos, 8).toLowerCase() === "auth-int") {
+          result0 = input.substr(pos, 8);
+          pos += 8;
+        } else {
+          result0 = null;
+
+          if (reportFailures === 0) {
+            matchFailed("\"auth-int\"");
+          }
+        }
+
+        if (result0 === null) {
+          if (input.substr(pos, 4).toLowerCase() === "auth") {
+            result0 = input.substr(pos, 4);
+            pos += 4;
+          } else {
+            result0 = null;
+
+            if (reportFailures === 0) {
+              matchFailed("\"auth\"");
+            }
+          }
+
+          if (result0 === null) {
+            result0 = parse_token();
+          }
+        }
+
+        if (result0 !== null) {
+          result0 = function (offset, qop_value) {
+            data.qop || (data.qop = []);
+            data.qop.push(qop_value.toLowerCase());
+          }(pos0, result0);
+        }
+
+        if (result0 === null) {
+          pos = pos0;
+        }
+
+        return result0;
+      }
+
+      function parse_Proxy_Require() {
+        var result0, result1, result2, result3;
+        var pos0, pos1;
+        pos0 = pos;
+        result0 = parse_token();
+
+        if (result0 !== null) {
+          result1 = [];
+          pos1 = pos;
+          result2 = parse_COMMA();
+
+          if (result2 !== null) {
+            result3 = parse_token();
+
+            if (result3 !== null) {
+              result2 = [result2, result3];
+            } else {
+              result2 = null;
+              pos = pos1;
+            }
+          } else {
+            result2 = null;
+            pos = pos1;
+          }
+
+          while (result2 !== null) {
+            result1.push(result2);
+            pos1 = pos;
+            result2 = parse_COMMA();
+
+            if (result2 !== null) {
+              result3 = parse_token();
+
+              if (result3 !== null) {
+                result2 = [result2, result3];
+              } else {
+                result2 = null;
+                pos = pos1;
+              }
+            } else {
+              result2 = null;
+              pos = pos1;
+            }
+          }
+
+          if (result1 !== null) {
+            result0 = [result0, result1];
+          } else {
+            result0 = null;
+            pos = pos0;
+          }
+        } else {
+          result0 = null;
+          pos = pos0;
+        }
+
+        return result0;
+      }
+
+      function parse_Record_Route() {
+        var result0, result1, result2, result3;
+        var pos0, pos1, pos2;
+        pos0 = pos;
+        pos1 = pos;
+        result0 = parse_rec_route();
+
+        if (result0 !== null) {
+          result1 = [];
+          pos2 = pos;
+          result2 = parse_COMMA();
+
+          if (result2 !== null) {
+            result3 = parse_rec_route();
+
+            if (result3 !== null) {
+              result2 = [result2, result3];
+            } else {
+              result2 = null;
+              pos = pos2;
+            }
+          } else {
+            result2 = null;
+            pos = pos2;
+          }
+
+          while (result2 !== null) {
+            result1.push(result2);
+            pos2 = pos;
+            result2 = parse_COMMA();
+
+            if (result2 !== null) {
+              result3 = parse_rec_route();
+
+              if (result3 !== null) {
+                result2 = [result2, result3];
+              } else {
+                result2 = null;
+                pos = pos2;
+              }
+            } else {
+              result2 = null;
+              pos = pos2;
+            }
+          }
+
+          if (result1 !== null) {
+            result0 = [result0, result1];
+          } else {
+            result0 = null;
+            pos = pos1;
+          }
+        } else {
+          result0 = null;
+          pos = pos1;
+        }
+
+        if (result0 !== null) {
+          result0 = function (offset) {
+            var idx, length;
+            length = data.multi_header.length;
+
+            for (idx = 0; idx < length; idx++) {
+              if (data.multi_header[idx].parsed === null) {
+                data = null;
+                break;
+              }
+            }
+
+            if (data !== null) {
+              data = data.multi_header;
+            } else {
+              data = -1;
+            }
+          }(pos0);
+        }
+
+        if (result0 === null) {
+          pos = pos0;
+        }
+
+        return result0;
+      }
+
+      function parse_rec_route() {
+        var result0, result1, result2, result3;
+        var pos0, pos1, pos2;
+        pos0 = pos;
+        pos1 = pos;
+        result0 = parse_name_addr();
+
+        if (result0 !== null) {
+          result1 = [];
+          pos2 = pos;
+          result2 = parse_SEMI();
+
+          if (result2 !== null) {
+            result3 = parse_generic_param();
+
+            if (result3 !== null) {
+              result2 = [result2, result3];
+            } else {
+              result2 = null;
+              pos = pos2;
+            }
+          } else {
+            result2 = null;
+            pos = pos2;
+          }
+
+          while (result2 !== null) {
+            result1.push(result2);
+            pos2 = pos;
+            result2 = parse_SEMI();
+
+            if (result2 !== null) {
+              result3 = parse_generic_param();
+
+              if (result3 !== null) {
+                result2 = [result2, result3];
+              } else {
+                result2 = null;
+                pos = pos2;
+              }
+            } else {
+              result2 = null;
+              pos = pos2;
+            }
+          }
+
+          if (result1 !== null) {
+            result0 = [result0, result1];
+          } else {
+            result0 = null;
+            pos = pos1;
+          }
+        } else {
+          result0 = null;
+          pos = pos1;
+        }
+
+        if (result0 !== null) {
+          result0 = function (offset) {
+            var header;
+            if (!data.multi_header) data.multi_header = [];
+
+            try {
+              header = new NameAddrHeader(data.uri, data.display_name, data.params);
+              delete data.uri;
+              delete data.display_name;
+              delete data.params;
+            } catch (e) {
+              header = null;
+            }
+
+            data.multi_header.push({
+              'possition': pos,
+              'offset': offset,
+              'parsed': header
+            });
+          }(pos0);
+        }
+
+        if (result0 === null) {
+          pos = pos0;
+        }
+
+        return result0;
+      }
+
+      function parse_Reason() {
+        var result0, result1, result2, result3;
+        var pos0, pos1, pos2;
+        pos0 = pos;
+        pos1 = pos;
+
+        if (input.substr(pos, 3).toLowerCase() === "sip") {
+          result0 = input.substr(pos, 3);
+          pos += 3;
+        } else {
+          result0 = null;
+
+          if (reportFailures === 0) {
+            matchFailed("\"SIP\"");
+          }
+        }
+
+        if (result0 === null) {
+          result0 = parse_token();
+        }
+
+        if (result0 !== null) {
+          result1 = [];
+          pos2 = pos;
+          result2 = parse_SEMI();
+
+          if (result2 !== null) {
+            result3 = parse_reason_param();
+
+            if (result3 !== null) {
+              result2 = [result2, result3];
+            } else {
+              result2 = null;
+              pos = pos2;
+            }
+          } else {
+            result2 = null;
+            pos = pos2;
+          }
+
+          while (result2 !== null) {
+            result1.push(result2);
+            pos2 = pos;
+            result2 = parse_SEMI();
+
+            if (result2 !== null) {
+              result3 = parse_reason_param();
+
+              if (result3 !== null) {
+                result2 = [result2, result3];
+              } else {
+                result2 = null;
+                pos = pos2;
+              }
+            } else {
+              result2 = null;
+              pos = pos2;
+            }
+          }
+
+          if (result1 !== null) {
+            result0 = [result0, result1];
+          } else {
+            result0 = null;
+            pos = pos1;
+          }
+        } else {
+          result0 = null;
+          pos = pos1;
+        }
+
+        if (result0 !== null) {
+          result0 = function (offset, protocol) {
+            data.protocol = protocol.toLowerCase();
+            if (!data.params) data.params = {};
+
+            if (data.params.text && data.params.text[0] === '"') {
+              var text = data.params.text;
+              data.text = text.substring(1, text.length - 1);
+              delete data.params.text;
+            }
+          }(pos0, result0[0]);
+        }
+
+        if (result0 === null) {
+          pos = pos0;
+        }
+
+        return result0;
+      }
+
+      function parse_reason_param() {
+        var result0;
+        result0 = parse_reason_cause();
+
+        if (result0 === null) {
+          result0 = parse_generic_param();
+        }
+
+        return result0;
+      }
+
+      function parse_reason_cause() {
+        var result0, result1, result2, result3;
+        var pos0, pos1;
+        pos0 = pos;
+        pos1 = pos;
+
+        if (input.substr(pos, 5).toLowerCase() === "cause") {
+          result0 = input.substr(pos, 5);
+          pos += 5;
+        } else {
+          result0 = null;
+
+          if (reportFailures === 0) {
+            matchFailed("\"cause\"");
+          }
+        }
+
+        if (result0 !== null) {
+          result1 = parse_EQUAL();
+
+          if (result1 !== null) {
+            result3 = parse_DIGIT();
+
+            if (result3 !== null) {
+              result2 = [];
+
+              while (result3 !== null) {
+                result2.push(result3);
+                result3 = parse_DIGIT();
+              }
+            } else {
+              result2 = null;
+            }
+
+            if (result2 !== null) {
+              result0 = [result0, result1, result2];
+            } else {
+              result0 = null;
+              pos = pos1;
+            }
+          } else {
+            result0 = null;
+            pos = pos1;
+          }
+        } else {
+          result0 = null;
+          pos = pos1;
+        }
+
+        if (result0 !== null) {
+          result0 = function (offset, cause) {
+            data.cause = parseInt(cause.join(''));
+          }(pos0, result0[2]);
+        }
+
+        if (result0 === null) {
+          pos = pos0;
+        }
+
+        return result0;
+      }
+
+      function parse_Require() {
+        var result0, result1, result2, result3;
+        var pos0, pos1;
+        pos0 = pos;
+        result0 = parse_token();
+
+        if (result0 !== null) {
+          result1 = [];
+          pos1 = pos;
+          result2 = parse_COMMA();
+
+          if (result2 !== null) {
+            result3 = parse_token();
+
+            if (result3 !== null) {
+              result2 = [result2, result3];
+            } else {
+              result2 = null;
+              pos = pos1;
+            }
+          } else {
+            result2 = null;
+            pos = pos1;
+          }
+
+          while (result2 !== null) {
+            result1.push(result2);
+            pos1 = pos;
+            result2 = parse_COMMA();
+
+            if (result2 !== null) {
+              result3 = parse_token();
+
+              if (result3 !== null) {
+                result2 = [result2, result3];
+              } else {
+                result2 = null;
+                pos = pos1;
+              }
+            } else {
+              result2 = null;
+              pos = pos1;
+            }
+          }
+
+          if (result1 !== null) {
+            result0 = [result0, result1];
+          } else {
+            result0 = null;
+            pos = pos0;
+          }
+        } else {
+          result0 = null;
+          pos = pos0;
+        }
+
+        return result0;
+      }
+
+      function parse_Route() {
+        var result0, result1, result2, result3;
+        var pos0, pos1;
+        pos0 = pos;
+        result0 = parse_route_param();
+
+        if (result0 !== null) {
+          result1 = [];
+          pos1 = pos;
+          result2 = parse_COMMA();
+
+          if (result2 !== null) {
+            result3 = parse_route_param();
+
+            if (result3 !== null) {
+              result2 = [result2, result3];
+            } else {
+              result2 = null;
+              pos = pos1;
+            }
+          } else {
+            result2 = null;
+            pos = pos1;
+          }
+
+          while (result2 !== null) {
+            result1.push(result2);
+            pos1 = pos;
+            result2 = parse_COMMA();
+
+            if (result2 !== null) {
+              result3 = parse_route_param();
+
+              if (result3 !== null) {
+                result2 = [result2, result3];
+              } else {
+                result2 = null;
+                pos = pos1;
+              }
+            } else {
+              result2 = null;
+              pos = pos1;
+            }
+          }
+
+          if (result1 !== null) {
+            result0 = [result0, result1];
+          } else {
+            result0 = null;
+            pos = pos0;
+          }
+        } else {
+          result0 = null;
+          pos = pos0;
+        }
+
+        return result0;
+      }
+
+      function parse_route_param() {
+        var result0, result1, result2, result3;
+        var pos0, pos1;
+        pos0 = pos;
+        result0 = parse_name_addr();
+
+        if (result0 !== null) {
+          result1 = [];
+          pos1 = pos;
+          result2 = parse_SEMI();
+
+          if (result2 !== null) {
+            result3 = parse_generic_param();
+
+            if (result3 !== null) {
+              result2 = [result2, result3];
+            } else {
+              result2 = null;
+              pos = pos1;
+            }
+          } else {
+            result2 = null;
+            pos = pos1;
+          }
+
+          while (result2 !== null) {
+            result1.push(result2);
+            pos1 = pos;
+            result2 = parse_SEMI();
+
+            if (result2 !== null) {
+              result3 = parse_generic_param();
+
+              if (result3 !== null) {
+                result2 = [result2, result3];
+              } else {
+                result2 = null;
+                pos = pos1;
+              }
+            } else {
+              result2 = null;
+              pos = pos1;
+            }
+          }
+
+          if (result1 !== null) {
+            result0 = [result0, result1];
+          } else {
+            result0 = null;
+            pos = pos0;
+          }
+        } else {
+          result0 = null;
+          pos = pos0;
+        }
+
+        return result0;
+      }
+
+      function parse_Subscription_State() {
+        var result0, result1, result2, result3;
+        var pos0, pos1;
+        pos0 = pos;
+        result0 = parse_substate_value();
+
+        if (result0 !== null) {
+          result1 = [];
+          pos1 = pos;
+          result2 = parse_SEMI();
+
+          if (result2 !== null) {
+            result3 = parse_subexp_params();
+
+            if (result3 !== null) {
+              result2 = [result2, result3];
+            } else {
+              result2 = null;
+              pos = pos1;
+            }
+          } else {
+            result2 = null;
+            pos = pos1;
+          }
+
+          while (result2 !== null) {
+            result1.push(result2);
+            pos1 = pos;
+            result2 = parse_SEMI();
+
+            if (result2 !== null) {
+              result3 = parse_subexp_params();
+
+              if (result3 !== null) {
+                result2 = [result2, result3];
+              } else {
+                result2 = null;
+                pos = pos1;
+              }
+            } else {
+              result2 = null;
+              pos = pos1;
+            }
+          }
+
+          if (result1 !== null) {
+            result0 = [result0, result1];
+          } else {
+            result0 = null;
+            pos = pos0;
+          }
+        } else {
+          result0 = null;
+          pos = pos0;
+        }
+
+        return result0;
+      }
+
+      function parse_substate_value() {
+        var result0;
+        var pos0;
+        pos0 = pos;
+
+        if (input.substr(pos, 6).toLowerCase() === "active") {
+          result0 = input.substr(pos, 6);
+          pos += 6;
+        } else {
+          result0 = null;
+
+          if (reportFailures === 0) {
+            matchFailed("\"active\"");
+          }
+        }
+
+        if (result0 === null) {
+          if (input.substr(pos, 7).toLowerCase() === "pending") {
+            result0 = input.substr(pos, 7);
+            pos += 7;
+          } else {
+            result0 = null;
+
+            if (reportFailures === 0) {
+              matchFailed("\"pending\"");
+            }
+          }
+
+          if (result0 === null) {
+            if (input.substr(pos, 10).toLowerCase() === "terminated") {
+              result0 = input.substr(pos, 10);
+              pos += 10;
+            } else {
+              result0 = null;
+
+              if (reportFailures === 0) {
+                matchFailed("\"terminated\"");
+              }
+            }
+
+            if (result0 === null) {
+              result0 = parse_token();
+            }
+          }
+        }
+
+        if (result0 !== null) {
+          result0 = function (offset) {
+            data.state = input.substring(pos, offset);
+          }(pos0);
+        }
+
+        if (result0 === null) {
+          pos = pos0;
+        }
+
+        return result0;
+      }
+
+      function parse_subexp_params() {
+        var result0, result1, result2;
+        var pos0, pos1;
+        pos0 = pos;
+        pos1 = pos;
+
+        if (input.substr(pos, 6).toLowerCase() === "reason") {
+          result0 = input.substr(pos, 6);
+          pos += 6;
+        } else {
+          result0 = null;
+
+          if (reportFailures === 0) {
+            matchFailed("\"reason\"");
+          }
+        }
+
+        if (result0 !== null) {
+          result1 = parse_EQUAL();
+
+          if (result1 !== null) {
+            result2 = parse_event_reason_value();
+
+            if (result2 !== null) {
+              result0 = [result0, result1, result2];
+            } else {
+              result0 = null;
+              pos = pos1;
+            }
+          } else {
+            result0 = null;
+            pos = pos1;
+          }
+        } else {
+          result0 = null;
+          pos = pos1;
+        }
+
+        if (result0 !== null) {
+          result0 = function (offset, reason) {
+            if (typeof reason !== 'undefined') data.reason = reason;
+          }(pos0, result0[2]);
+        }
+
+        if (result0 === null) {
+          pos = pos0;
+        }
+
+        if (result0 === null) {
+          pos0 = pos;
+          pos1 = pos;
+
+          if (input.substr(pos, 7).toLowerCase() === "expires") {
+            result0 = input.substr(pos, 7);
+            pos += 7;
+          } else {
+            result0 = null;
+
+            if (reportFailures === 0) {
+              matchFailed("\"expires\"");
+            }
+          }
+
+          if (result0 !== null) {
+            result1 = parse_EQUAL();
+
+            if (result1 !== null) {
+              result2 = parse_delta_seconds();
+
+              if (result2 !== null) {
+                result0 = [result0, result1, result2];
+              } else {
+                result0 = null;
+                pos = pos1;
+              }
+            } else {
+              result0 = null;
+              pos = pos1;
+            }
+          } else {
+            result0 = null;
+            pos = pos1;
+          }
+
+          if (result0 !== null) {
+            result0 = function (offset, expires) {
+              if (typeof expires !== 'undefined') data.expires = expires;
+            }(pos0, result0[2]);
+          }
+
+          if (result0 === null) {
+            pos = pos0;
+          }
+
+          if (result0 === null) {
+            pos0 = pos;
+            pos1 = pos;
+
+            if (input.substr(pos, 11).toLowerCase() === "retry_after") {
+              result0 = input.substr(pos, 11);
+              pos += 11;
+            } else {
+              result0 = null;
+
+              if (reportFailures === 0) {
+                matchFailed("\"retry_after\"");
+              }
+            }
+
+            if (result0 !== null) {
+              result1 = parse_EQUAL();
+
+              if (result1 !== null) {
+                result2 = parse_delta_seconds();
+
+                if (result2 !== null) {
+                  result0 = [result0, result1, result2];
+                } else {
+                  result0 = null;
+                  pos = pos1;
+                }
+              } else {
+                result0 = null;
+                pos = pos1;
+              }
+            } else {
+              result0 = null;
+              pos = pos1;
+            }
+
+            if (result0 !== null) {
+              result0 = function (offset, retry_after) {
+                if (typeof retry_after !== 'undefined') data.retry_after = retry_after;
+              }(pos0, result0[2]);
+            }
+
+            if (result0 === null) {
+              pos = pos0;
+            }
+
+            if (result0 === null) {
+              result0 = parse_generic_param();
+            }
+          }
+        }
+
+        return result0;
+      }
+
+      function parse_event_reason_value() {
+        var result0;
+
+        if (input.substr(pos, 11).toLowerCase() === "deactivated") {
+          result0 = input.substr(pos, 11);
+          pos += 11;
+        } else {
+          result0 = null;
+
+          if (reportFailures === 0) {
+            matchFailed("\"deactivated\"");
+          }
+        }
+
+        if (result0 === null) {
+          if (input.substr(pos, 9).toLowerCase() === "probation") {
+            result0 = input.substr(pos, 9);
+            pos += 9;
+          } else {
+            result0 = null;
+
+            if (reportFailures === 0) {
+              matchFailed("\"probation\"");
+            }
+          }
+
+          if (result0 === null) {
+            if (input.substr(pos, 8).toLowerCase() === "rejected") {
+              result0 = input.substr(pos, 8);
+              pos += 8;
+            } else {
+              result0 = null;
+
+              if (reportFailures === 0) {
+                matchFailed("\"rejected\"");
+              }
+            }
+
+            if (result0 === null) {
+              if (input.substr(pos, 7).toLowerCase() === "timeout") {
+                result0 = input.substr(pos, 7);
+                pos += 7;
+              } else {
+                result0 = null;
+
+                if (reportFailures === 0) {
+                  matchFailed("\"timeout\"");
+                }
+              }
+
+              if (result0 === null) {
+                if (input.substr(pos, 6).toLowerCase() === "giveup") {
+                  result0 = input.substr(pos, 6);
+                  pos += 6;
+                } else {
+                  result0 = null;
+
+                  if (reportFailures === 0) {
+                    matchFailed("\"giveup\"");
+                  }
+                }
+
+                if (result0 === null) {
+                  if (input.substr(pos, 10).toLowerCase() === "noresource") {
+                    result0 = input.substr(pos, 10);
+                    pos += 10;
+                  } else {
+                    result0 = null;
+
+                    if (reportFailures === 0) {
+                      matchFailed("\"noresource\"");
+                    }
+                  }
+
+                  if (result0 === null) {
+                    if (input.substr(pos, 9).toLowerCase() === "invariant") {
+                      result0 = input.substr(pos, 9);
+                      pos += 9;
+                    } else {
+                      result0 = null;
+
+                      if (reportFailures === 0) {
+                        matchFailed("\"invariant\"");
+                      }
+                    }
+
+                    if (result0 === null) {
+                      result0 = parse_token();
+                    }
+                  }
+                }
+              }
+            }
+          }
+        }
+
+        return result0;
+      }
+
+      function parse_Subject() {
+        var result0;
+        result0 = parse_TEXT_UTF8_TRIM();
+        result0 = result0 !== null ? result0 : "";
+        return result0;
+      }
+
+      function parse_Supported() {
+        var result0, result1, result2, result3;
+        var pos0, pos1;
+        pos0 = pos;
+        result0 = parse_token();
+
+        if (result0 !== null) {
+          result1 = [];
+          pos1 = pos;
+          result2 = parse_COMMA();
+
+          if (result2 !== null) {
+            result3 = parse_token();
+
+            if (result3 !== null) {
+              result2 = [result2, result3];
+            } else {
+              result2 = null;
+              pos = pos1;
+            }
+          } else {
+            result2 = null;
+            pos = pos1;
+          }
+
+          while (result2 !== null) {
+            result1.push(result2);
+            pos1 = pos;
+            result2 = parse_COMMA();
+
+            if (result2 !== null) {
+              result3 = parse_token();
+
+              if (result3 !== null) {
+                result2 = [result2, result3];
+              } else {
+                result2 = null;
+                pos = pos1;
+              }
+            } else {
+              result2 = null;
+              pos = pos1;
+            }
+          }
+
+          if (result1 !== null) {
+            result0 = [result0, result1];
+          } else {
+            result0 = null;
+            pos = pos0;
+          }
+        } else {
+          result0 = null;
+          pos = pos0;
+        }
+
+        result0 = result0 !== null ? result0 : "";
+        return result0;
+      }
+
+      function parse_To() {
+        var result0, result1, result2, result3;
+        var pos0, pos1, pos2;
+        pos0 = pos;
+        pos1 = pos;
+        result0 = parse_SIP_URI_noparams();
+
+        if (result0 === null) {
+          result0 = parse_name_addr();
+        }
+
+        if (result0 !== null) {
+          result1 = [];
+          pos2 = pos;
+          result2 = parse_SEMI();
+
+          if (result2 !== null) {
+            result3 = parse_to_param();
+
+            if (result3 !== null) {
+              result2 = [result2, result3];
+            } else {
+              result2 = null;
+              pos = pos2;
+            }
+          } else {
+            result2 = null;
+            pos = pos2;
+          }
+
+          while (result2 !== null) {
+            result1.push(result2);
+            pos2 = pos;
+            result2 = parse_SEMI();
+
+            if (result2 !== null) {
+              result3 = parse_to_param();
+
+              if (result3 !== null) {
+                result2 = [result2, result3];
+              } else {
+                result2 = null;
+                pos = pos2;
+              }
+            } else {
+              result2 = null;
+              pos = pos2;
+            }
+          }
+
+          if (result1 !== null) {
+            result0 = [result0, result1];
+          } else {
+            result0 = null;
+            pos = pos1;
+          }
+        } else {
+          result0 = null;
+          pos = pos1;
+        }
+
+        if (result0 !== null) {
+          result0 = function (offset) {
+            var tag = data.tag;
+
+            try {
+              data = new NameAddrHeader(data.uri, data.display_name, data.params);
+
+              if (tag) {
+                data.setParam('tag', tag);
+              }
+            } catch (e) {
+              data = -1;
+            }
+          }(pos0);
+        }
+
+        if (result0 === null) {
+          pos = pos0;
+        }
+
+        return result0;
+      }
+
+      function parse_to_param() {
+        var result0;
+        result0 = parse_tag_param();
+
+        if (result0 === null) {
+          result0 = parse_generic_param();
+        }
+
+        return result0;
+      }
+
+      function parse_Via() {
+        var result0, result1, result2, result3;
+        var pos0, pos1;
+        pos0 = pos;
+        result0 = parse_via_param();
+
+        if (result0 !== null) {
+          result1 = [];
+          pos1 = pos;
+          result2 = parse_COMMA();
+
+          if (result2 !== null) {
+            result3 = parse_via_param();
+
+            if (result3 !== null) {
+              result2 = [result2, result3];
+            } else {
+              result2 = null;
+              pos = pos1;
+            }
+          } else {
+            result2 = null;
+            pos = pos1;
+          }
+
+          while (result2 !== null) {
+            result1.push(result2);
+            pos1 = pos;
+            result2 = parse_COMMA();
+
+            if (result2 !== null) {
+              result3 = parse_via_param();
+
+              if (result3 !== null) {
+                result2 = [result2, result3];
+              } else {
+                result2 = null;
+                pos = pos1;
+              }
+            } else {
+              result2 = null;
+              pos = pos1;
+            }
+          }
+
+          if (result1 !== null) {
+            result0 = [result0, result1];
+          } else {
+            result0 = null;
+            pos = pos0;
+          }
+        } else {
+          result0 = null;
+          pos = pos0;
+        }
+
+        return result0;
+      }
+
+      function parse_via_param() {
+        var result0, result1, result2, result3, result4, result5;
+        var pos0, pos1;
+        pos0 = pos;
+        result0 = parse_sent_protocol();
+
+        if (result0 !== null) {
+          result1 = parse_LWS();
+
+          if (result1 !== null) {
+            result2 = parse_sent_by();
+
+            if (result2 !== null) {
+              result3 = [];
+              pos1 = pos;
+              result4 = parse_SEMI();
+
+              if (result4 !== null) {
+                result5 = parse_via_params();
+
+                if (result5 !== null) {
+                  result4 = [result4, result5];
+                } else {
+                  result4 = null;
+                  pos = pos1;
+                }
+              } else {
+                result4 = null;
+                pos = pos1;
+              }
+
+              while (result4 !== null) {
+                result3.push(result4);
+                pos1 = pos;
+                result4 = parse_SEMI();
+
+                if (result4 !== null) {
+                  result5 = parse_via_params();
+
+                  if (result5 !== null) {
+                    result4 = [result4, result5];
+                  } else {
+                    result4 = null;
+                    pos = pos1;
+                  }
+                } else {
+                  result4 = null;
+                  pos = pos1;
+                }
+              }
+
+              if (result3 !== null) {
+                result0 = [result0, result1, result2, result3];
+              } else {
+                result0 = null;
+                pos = pos0;
+              }
+            } else {
+              result0 = null;
+              pos = pos0;
+            }
+          } else {
+            result0 = null;
+            pos = pos0;
+          }
+        } else {
+          result0 = null;
+          pos = pos0;
+        }
+
+        return result0;
+      }
+
+      function parse_via_params() {
+        var result0;
+        result0 = parse_via_ttl();
+
+        if (result0 === null) {
+          result0 = parse_via_maddr();
+
+          if (result0 === null) {
+            result0 = parse_via_received();
+
+            if (result0 === null) {
+              result0 = parse_via_branch();
+
+              if (result0 === null) {
+                result0 = parse_response_port();
+
+                if (result0 === null) {
+                  result0 = parse_generic_param();
+                }
+              }
+            }
+          }
+        }
+
+        return result0;
+      }
+
+      function parse_via_ttl() {
+        var result0, result1, result2;
+        var pos0, pos1;
+        pos0 = pos;
+        pos1 = pos;
+
+        if (input.substr(pos, 3).toLowerCase() === "ttl") {
+          result0 = input.substr(pos, 3);
+          pos += 3;
+        } else {
+          result0 = null;
+
+          if (reportFailures === 0) {
+            matchFailed("\"ttl\"");
+          }
+        }
+
+        if (result0 !== null) {
+          result1 = parse_EQUAL();
+
+          if (result1 !== null) {
+            result2 = parse_ttl();
+
+            if (result2 !== null) {
+              result0 = [result0, result1, result2];
+            } else {
+              result0 = null;
+              pos = pos1;
+            }
+          } else {
+            result0 = null;
+            pos = pos1;
+          }
+        } else {
+          result0 = null;
+          pos = pos1;
+        }
+
+        if (result0 !== null) {
+          result0 = function (offset, via_ttl_value) {
+            data.ttl = via_ttl_value;
+          }(pos0, result0[2]);
+        }
+
+        if (result0 === null) {
+          pos = pos0;
+        }
+
+        return result0;
+      }
+
+      function parse_via_maddr() {
+        var result0, result1, result2;
+        var pos0, pos1;
+        pos0 = pos;
+        pos1 = pos;
+
+        if (input.substr(pos, 5).toLowerCase() === "maddr") {
+          result0 = input.substr(pos, 5);
+          pos += 5;
+        } else {
+          result0 = null;
+
+          if (reportFailures === 0) {
+            matchFailed("\"maddr\"");
+          }
+        }
+
+        if (result0 !== null) {
+          result1 = parse_EQUAL();
+
+          if (result1 !== null) {
+            result2 = parse_host();
+
+            if (result2 !== null) {
+              result0 = [result0, result1, result2];
+            } else {
+              result0 = null;
+              pos = pos1;
+            }
+          } else {
+            result0 = null;
+            pos = pos1;
+          }
+        } else {
+          result0 = null;
+          pos = pos1;
+        }
+
+        if (result0 !== null) {
+          result0 = function (offset, via_maddr) {
+            data.maddr = via_maddr;
+          }(pos0, result0[2]);
+        }
+
+        if (result0 === null) {
+          pos = pos0;
+        }
+
+        return result0;
+      }
+
+      function parse_via_received() {
+        var result0, result1, result2;
+        var pos0, pos1;
+        pos0 = pos;
+        pos1 = pos;
+
+        if (input.substr(pos, 8).toLowerCase() === "received") {
+          result0 = input.substr(pos, 8);
+          pos += 8;
+        } else {
+          result0 = null;
+
+          if (reportFailures === 0) {
+            matchFailed("\"received\"");
+          }
+        }
+
+        if (result0 !== null) {
+          result1 = parse_EQUAL();
+
+          if (result1 !== null) {
+            result2 = parse_IPv4address();
+
+            if (result2 === null) {
+              result2 = parse_IPv6address();
+            }
+
+            if (result2 !== null) {
+              result0 = [result0, result1, result2];
+            } else {
+              result0 = null;
+              pos = pos1;
+            }
+          } else {
+            result0 = null;
+            pos = pos1;
+          }
+        } else {
+          result0 = null;
+          pos = pos1;
+        }
+
+        if (result0 !== null) {
+          result0 = function (offset, via_received) {
+            data.received = via_received;
+          }(pos0, result0[2]);
+        }
+
+        if (result0 === null) {
+          pos = pos0;
+        }
+
+        return result0;
+      }
+
+      function parse_via_branch() {
+        var result0, result1, result2;
+        var pos0, pos1;
+        pos0 = pos;
+        pos1 = pos;
+
+        if (input.substr(pos, 6).toLowerCase() === "branch") {
+          result0 = input.substr(pos, 6);
+          pos += 6;
+        } else {
+          result0 = null;
+
+          if (reportFailures === 0) {
+            matchFailed("\"branch\"");
+          }
+        }
+
+        if (result0 !== null) {
+          result1 = parse_EQUAL();
+
+          if (result1 !== null) {
+            result2 = parse_token();
+
+            if (result2 !== null) {
+              result0 = [result0, result1, result2];
+            } else {
+              result0 = null;
+              pos = pos1;
+            }
+          } else {
+            result0 = null;
+            pos = pos1;
+          }
+        } else {
+          result0 = null;
+          pos = pos1;
+        }
+
+        if (result0 !== null) {
+          result0 = function (offset, via_branch) {
+            data.branch = via_branch;
+          }(pos0, result0[2]);
+        }
+
+        if (result0 === null) {
+          pos = pos0;
+        }
+
+        return result0;
+      }
+
+      function parse_response_port() {
+        var result0, result1, result2;
+        var pos0, pos1;
+        pos0 = pos;
+
+        if (input.substr(pos, 5).toLowerCase() === "rport") {
+          result0 = input.substr(pos, 5);
+          pos += 5;
+        } else {
+          result0 = null;
+
+          if (reportFailures === 0) {
+            matchFailed("\"rport\"");
+          }
+        }
+
+        if (result0 !== null) {
+          pos1 = pos;
+          result1 = parse_EQUAL();
+
+          if (result1 !== null) {
+            result2 = parse_rport();
+
+            if (result2 !== null) {
+              result1 = [result1, result2];
+            } else {
+              result1 = null;
+              pos = pos1;
+            }
+          } else {
+            result1 = null;
+            pos = pos1;
+          }
+
+          result1 = result1 !== null ? result1 : "";
+
+          if (result1 !== null) {
+            result0 = [result0, result1];
+          } else {
+            result0 = null;
+            pos = pos0;
+          }
+        } else {
+          result0 = null;
+          pos = pos0;
+        }
+
+        return result0;
+      }
+
+      function parse_rport() {
+        var result0, result1, result2, result3, result4;
+        var pos0, pos1;
+        pos0 = pos;
+        pos1 = pos;
+        result0 = parse_DIGIT();
+        result0 = result0 !== null ? result0 : "";
+
+        if (result0 !== null) {
+          result1 = parse_DIGIT();
+          result1 = result1 !== null ? result1 : "";
+
+          if (result1 !== null) {
+            result2 = parse_DIGIT();
+            result2 = result2 !== null ? result2 : "";
+
+            if (result2 !== null) {
+              result3 = parse_DIGIT();
+              result3 = result3 !== null ? result3 : "";
+
+              if (result3 !== null) {
+                result4 = parse_DIGIT();
+                result4 = result4 !== null ? result4 : "";
+
+                if (result4 !== null) {
+                  result0 = [result0, result1, result2, result3, result4];
+                } else {
+                  result0 = null;
+                  pos = pos1;
+                }
+              } else {
+                result0 = null;
+                pos = pos1;
+              }
+            } else {
+              result0 = null;
+              pos = pos1;
+            }
+          } else {
+            result0 = null;
+            pos = pos1;
+          }
+        } else {
+          result0 = null;
+          pos = pos1;
+        }
+
+        if (result0 !== null) {
+          result0 = function (offset, rport) {
+            data.rport = parseInt(rport.join(''));
+          }(pos0, result0);
+        }
+
+        if (result0 === null) {
+          pos = pos0;
+        }
+
+        return result0;
+      }
+
+      function parse_sent_protocol() {
+        var result0, result1, result2, result3, result4;
+        var pos0;
+        pos0 = pos;
+        result0 = parse_protocol_name();
+
+        if (result0 !== null) {
+          result1 = parse_SLASH();
+
+          if (result1 !== null) {
+            result2 = parse_token();
+
+            if (result2 !== null) {
+              result3 = parse_SLASH();
+
+              if (result3 !== null) {
+                result4 = parse_transport();
+
+                if (result4 !== null) {
+                  result0 = [result0, result1, result2, result3, result4];
+                } else {
+                  result0 = null;
+                  pos = pos0;
+                }
+              } else {
+                result0 = null;
+                pos = pos0;
+              }
+            } else {
+              result0 = null;
+              pos = pos0;
+            }
+          } else {
+            result0 = null;
+            pos = pos0;
+          }
+        } else {
+          result0 = null;
+          pos = pos0;
+        }
+
+        return result0;
+      }
+
+      function parse_protocol_name() {
+        var result0;
+        var pos0;
+        pos0 = pos;
+
+        if (input.substr(pos, 3).toLowerCase() === "sip") {
+          result0 = input.substr(pos, 3);
+          pos += 3;
+        } else {
+          result0 = null;
+
+          if (reportFailures === 0) {
+            matchFailed("\"SIP\"");
+          }
+        }
+
+        if (result0 === null) {
+          result0 = parse_token();
+        }
+
+        if (result0 !== null) {
+          result0 = function (offset, via_protocol) {
+            data.protocol = via_protocol;
+          }(pos0, result0);
+        }
+
+        if (result0 === null) {
+          pos = pos0;
+        }
+
+        return result0;
+      }
+
+      function parse_transport() {
+        var result0;
+        var pos0;
+        pos0 = pos;
+
+        if (input.substr(pos, 3).toLowerCase() === "udp") {
+          result0 = input.substr(pos, 3);
+          pos += 3;
+        } else {
+          result0 = null;
+
+          if (reportFailures === 0) {
+            matchFailed("\"UDP\"");
+          }
+        }
+
+        if (result0 === null) {
+          if (input.substr(pos, 3).toLowerCase() === "tcp") {
+            result0 = input.substr(pos, 3);
+            pos += 3;
+          } else {
+            result0 = null;
+
+            if (reportFailures === 0) {
+              matchFailed("\"TCP\"");
+            }
+          }
+
+          if (result0 === null) {
+            if (input.substr(pos, 3).toLowerCase() === "tls") {
+              result0 = input.substr(pos, 3);
+              pos += 3;
+            } else {
+              result0 = null;
+
+              if (reportFailures === 0) {
+                matchFailed("\"TLS\"");
+              }
+            }
+
+            if (result0 === null) {
+              if (input.substr(pos, 4).toLowerCase() === "sctp") {
+                result0 = input.substr(pos, 4);
+                pos += 4;
+              } else {
+                result0 = null;
+
+                if (reportFailures === 0) {
+                  matchFailed("\"SCTP\"");
+                }
+              }
+
+              if (result0 === null) {
+                result0 = parse_token();
+              }
+            }
+          }
+        }
+
+        if (result0 !== null) {
+          result0 = function (offset, via_transport) {
+            data.transport = via_transport;
+          }(pos0, result0);
+        }
+
+        if (result0 === null) {
+          pos = pos0;
+        }
+
+        return result0;
+      }
+
+      function parse_sent_by() {
+        var result0, result1, result2;
+        var pos0, pos1;
+        pos0 = pos;
+        result0 = parse_via_host();
+
+        if (result0 !== null) {
+          pos1 = pos;
+          result1 = parse_COLON();
+
+          if (result1 !== null) {
+            result2 = parse_via_port();
+
+            if (result2 !== null) {
+              result1 = [result1, result2];
+            } else {
+              result1 = null;
+              pos = pos1;
+            }
+          } else {
+            result1 = null;
+            pos = pos1;
+          }
+
+          result1 = result1 !== null ? result1 : "";
+
+          if (result1 !== null) {
+            result0 = [result0, result1];
+          } else {
+            result0 = null;
+            pos = pos0;
+          }
+        } else {
+          result0 = null;
+          pos = pos0;
+        }
+
+        return result0;
+      }
+
+      function parse_via_host() {
+        var result0;
+        var pos0;
+        pos0 = pos;
+        result0 = parse_IPv4address();
+
+        if (result0 === null) {
+          result0 = parse_IPv6reference();
+
+          if (result0 === null) {
+            result0 = parse_hostname();
+          }
+        }
+
+        if (result0 !== null) {
+          result0 = function (offset) {
+            data.host = input.substring(pos, offset);
+          }(pos0);
+        }
+
+        if (result0 === null) {
+          pos = pos0;
+        }
+
+        return result0;
+      }
+
+      function parse_via_port() {
+        var result0, result1, result2, result3, result4;
+        var pos0, pos1;
+        pos0 = pos;
+        pos1 = pos;
+        result0 = parse_DIGIT();
+        result0 = result0 !== null ? result0 : "";
+
+        if (result0 !== null) {
+          result1 = parse_DIGIT();
+          result1 = result1 !== null ? result1 : "";
+
+          if (result1 !== null) {
+            result2 = parse_DIGIT();
+            result2 = result2 !== null ? result2 : "";
+
+            if (result2 !== null) {
+              result3 = parse_DIGIT();
+              result3 = result3 !== null ? result3 : "";
+
+              if (result3 !== null) {
+                result4 = parse_DIGIT();
+                result4 = result4 !== null ? result4 : "";
+
+                if (result4 !== null) {
+                  result0 = [result0, result1, result2, result3, result4];
+                } else {
+                  result0 = null;
+                  pos = pos1;
+                }
+              } else {
+                result0 = null;
+                pos = pos1;
+              }
+            } else {
+              result0 = null;
+              pos = pos1;
+            }
+          } else {
+            result0 = null;
+            pos = pos1;
+          }
+        } else {
+          result0 = null;
+          pos = pos1;
+        }
+
+        if (result0 !== null) {
+          result0 = function (offset, via_sent_by_port) {
+            data.port = parseInt(via_sent_by_port.join(''));
+          }(pos0, result0);
+        }
+
+        if (result0 === null) {
+          pos = pos0;
+        }
+
+        return result0;
+      }
+
+      function parse_ttl() {
+        var result0, result1, result2;
+        var pos0, pos1;
+        pos0 = pos;
+        pos1 = pos;
+        result0 = parse_DIGIT();
+
+        if (result0 !== null) {
+          result1 = parse_DIGIT();
+          result1 = result1 !== null ? result1 : "";
+
+          if (result1 !== null) {
+            result2 = parse_DIGIT();
+            result2 = result2 !== null ? result2 : "";
+
+            if (result2 !== null) {
+              result0 = [result0, result1, result2];
+            } else {
+              result0 = null;
+              pos = pos1;
+            }
+          } else {
+            result0 = null;
+            pos = pos1;
+          }
+        } else {
+          result0 = null;
+          pos = pos1;
+        }
+
+        if (result0 !== null) {
+          result0 = function (offset, ttl) {
+            return parseInt(ttl.join(''));
+          }(pos0, result0);
+        }
+
+        if (result0 === null) {
+          pos = pos0;
+        }
+
+        return result0;
+      }
+
+      function parse_WWW_Authenticate() {
+        var result0;
+        result0 = parse_challenge();
+        return result0;
+      }
+
+      function parse_Session_Expires() {
+        var result0, result1, result2, result3;
+        var pos0, pos1;
+        pos0 = pos;
+        result0 = parse_s_e_expires();
+
+        if (result0 !== null) {
+          result1 = [];
+          pos1 = pos;
+          result2 = parse_SEMI();
+
+          if (result2 !== null) {
+            result3 = parse_s_e_params();
+
+            if (result3 !== null) {
+              result2 = [result2, result3];
+            } else {
+              result2 = null;
+              pos = pos1;
+            }
+          } else {
+            result2 = null;
+            pos = pos1;
+          }
+
+          while (result2 !== null) {
+            result1.push(result2);
+            pos1 = pos;
+            result2 = parse_SEMI();
+
+            if (result2 !== null) {
+              result3 = parse_s_e_params();
+
+              if (result3 !== null) {
+                result2 = [result2, result3];
+              } else {
+                result2 = null;
+                pos = pos1;
+              }
+            } else {
+              result2 = null;
+              pos = pos1;
+            }
+          }
+
+          if (result1 !== null) {
+            result0 = [result0, result1];
+          } else {
+            result0 = null;
+            pos = pos0;
+          }
+        } else {
+          result0 = null;
+          pos = pos0;
+        }
+
+        return result0;
+      }
+
+      function parse_s_e_expires() {
+        var result0;
+        var pos0;
+        pos0 = pos;
+        result0 = parse_delta_seconds();
+
+        if (result0 !== null) {
+          result0 = function (offset, expires) {
+            data.expires = expires;
+          }(pos0, result0);
+        }
+
+        if (result0 === null) {
+          pos = pos0;
+        }
+
+        return result0;
+      }
+
+      function parse_s_e_params() {
+        var result0;
+        result0 = parse_s_e_refresher();
+
+        if (result0 === null) {
+          result0 = parse_generic_param();
+        }
+
+        return result0;
+      }
+
+      function parse_s_e_refresher() {
+        var result0, result1, result2;
+        var pos0, pos1;
+        pos0 = pos;
+        pos1 = pos;
+
+        if (input.substr(pos, 9).toLowerCase() === "refresher") {
+          result0 = input.substr(pos, 9);
+          pos += 9;
+        } else {
+          result0 = null;
+
+          if (reportFailures === 0) {
+            matchFailed("\"refresher\"");
+          }
+        }
+
+        if (result0 !== null) {
+          result1 = parse_EQUAL();
+
+          if (result1 !== null) {
+            if (input.substr(pos, 3).toLowerCase() === "uac") {
+              result2 = input.substr(pos, 3);
+              pos += 3;
+            } else {
+              result2 = null;
+
+              if (reportFailures === 0) {
+                matchFailed("\"uac\"");
+              }
+            }
+
+            if (result2 === null) {
+              if (input.substr(pos, 3).toLowerCase() === "uas") {
+                result2 = input.substr(pos, 3);
+                pos += 3;
+              } else {
+                result2 = null;
+
+                if (reportFailures === 0) {
+                  matchFailed("\"uas\"");
+                }
+              }
+            }
+
+            if (result2 !== null) {
+              result0 = [result0, result1, result2];
+            } else {
+              result0 = null;
+              pos = pos1;
+            }
+          } else {
+            result0 = null;
+            pos = pos1;
+          }
+        } else {
+          result0 = null;
+          pos = pos1;
+        }
+
+        if (result0 !== null) {
+          result0 = function (offset, s_e_refresher_value) {
+            data.refresher = s_e_refresher_value.toLowerCase();
+          }(pos0, result0[2]);
+        }
+
+        if (result0 === null) {
+          pos = pos0;
+        }
+
+        return result0;
+      }
+
+      function parse_extension_header() {
+        var result0, result1, result2;
+        var pos0;
+        pos0 = pos;
+        result0 = parse_token();
+
+        if (result0 !== null) {
+          result1 = parse_HCOLON();
+
+          if (result1 !== null) {
+            result2 = parse_header_value();
+
+            if (result2 !== null) {
+              result0 = [result0, result1, result2];
+            } else {
+              result0 = null;
+              pos = pos0;
+            }
+          } else {
+            result0 = null;
+            pos = pos0;
+          }
+        } else {
+          result0 = null;
+          pos = pos0;
+        }
+
+        return result0;
+      }
+
+      function parse_header_value() {
+        var result0, result1;
+        result0 = [];
+        result1 = parse_TEXT_UTF8char();
+
+        if (result1 === null) {
+          result1 = parse_UTF8_CONT();
+
+          if (result1 === null) {
+            result1 = parse_LWS();
+          }
+        }
+
+        while (result1 !== null) {
+          result0.push(result1);
+          result1 = parse_TEXT_UTF8char();
+
+          if (result1 === null) {
+            result1 = parse_UTF8_CONT();
+
+            if (result1 === null) {
+              result1 = parse_LWS();
+            }
+          }
+        }
+
+        return result0;
+      }
+
+      function parse_message_body() {
+        var result0, result1;
+        result0 = [];
+        result1 = parse_OCTET();
+
+        while (result1 !== null) {
+          result0.push(result1);
+          result1 = parse_OCTET();
+        }
+
+        return result0;
+      }
+
+      function parse_uuid_URI() {
+        var result0, result1;
+        var pos0;
+        pos0 = pos;
+
+        if (input.substr(pos, 5) === "uuid:") {
+          result0 = "uuid:";
+          pos += 5;
+        } else {
+          result0 = null;
+
+          if (reportFailures === 0) {
+            matchFailed("\"uuid:\"");
+          }
+        }
+
+        if (result0 !== null) {
+          result1 = parse_uuid();
+
+          if (result1 !== null) {
+            result0 = [result0, result1];
+          } else {
+            result0 = null;
+            pos = pos0;
+          }
+        } else {
+          result0 = null;
+          pos = pos0;
+        }
+
+        return result0;
+      }
+
+      function parse_uuid() {
+        var result0, result1, result2, result3, result4, result5, result6, result7, result8;
+        var pos0, pos1;
+        pos0 = pos;
+        pos1 = pos;
+        result0 = parse_hex8();
+
+        if (result0 !== null) {
+          if (input.charCodeAt(pos) === 45) {
+            result1 = "-";
+            pos++;
+          } else {
+            result1 = null;
+
+            if (reportFailures === 0) {
+              matchFailed("\"-\"");
+            }
+          }
+
+          if (result1 !== null) {
+            result2 = parse_hex4();
+
+            if (result2 !== null) {
+              if (input.charCodeAt(pos) === 45) {
+                result3 = "-";
+                pos++;
+              } else {
+                result3 = null;
+
+                if (reportFailures === 0) {
+                  matchFailed("\"-\"");
+                }
+              }
+
+              if (result3 !== null) {
+                result4 = parse_hex4();
+
+                if (result4 !== null) {
+                  if (input.charCodeAt(pos) === 45) {
+                    result5 = "-";
+                    pos++;
+                  } else {
+                    result5 = null;
+
+                    if (reportFailures === 0) {
+                      matchFailed("\"-\"");
+                    }
+                  }
+
+                  if (result5 !== null) {
+                    result6 = parse_hex4();
+
+                    if (result6 !== null) {
+                      if (input.charCodeAt(pos) === 45) {
+                        result7 = "-";
+                        pos++;
+                      } else {
+                        result7 = null;
+
+                        if (reportFailures === 0) {
+                          matchFailed("\"-\"");
+                        }
+                      }
+
+                      if (result7 !== null) {
+                        result8 = parse_hex12();
+
+                        if (result8 !== null) {
+                          result0 = [result0, result1, result2, result3, result4, result5, result6, result7, result8];
+                        } else {
+                          result0 = null;
+                          pos = pos1;
+                        }
+                      } else {
+                        result0 = null;
+                        pos = pos1;
+                      }
+                    } else {
+                      result0 = null;
+                      pos = pos1;
+                    }
+                  } else {
+                    result0 = null;
+                    pos = pos1;
+                  }
+                } else {
+                  result0 = null;
+                  pos = pos1;
+                }
+              } else {
+                result0 = null;
+                pos = pos1;
+              }
+            } else {
+              result0 = null;
+              pos = pos1;
+            }
+          } else {
+            result0 = null;
+            pos = pos1;
+          }
+        } else {
+          result0 = null;
+          pos = pos1;
+        }
+
+        if (result0 !== null) {
+          result0 = function (offset, uuid) {
+            data = input.substring(pos + 5, offset);
+          }(pos0, result0[0]);
+        }
+
+        if (result0 === null) {
+          pos = pos0;
+        }
+
+        return result0;
+      }
+
+      function parse_hex4() {
+        var result0, result1, result2, result3;
+        var pos0;
+        pos0 = pos;
+        result0 = parse_HEXDIG();
+
+        if (result0 !== null) {
+          result1 = parse_HEXDIG();
+
+          if (result1 !== null) {
+            result2 = parse_HEXDIG();
+
+            if (result2 !== null) {
+              result3 = parse_HEXDIG();
+
+              if (result3 !== null) {
+                result0 = [result0, result1, result2, result3];
+              } else {
+                result0 = null;
+                pos = pos0;
+              }
+            } else {
+              result0 = null;
+              pos = pos0;
+            }
+          } else {
+            result0 = null;
+            pos = pos0;
+          }
+        } else {
+          result0 = null;
+          pos = pos0;
+        }
+
+        return result0;
+      }
+
+      function parse_hex8() {
+        var result0, result1;
+        var pos0;
+        pos0 = pos;
+        result0 = parse_hex4();
+
+        if (result0 !== null) {
+          result1 = parse_hex4();
+
+          if (result1 !== null) {
+            result0 = [result0, result1];
+          } else {
+            result0 = null;
+            pos = pos0;
+          }
+        } else {
+          result0 = null;
+          pos = pos0;
+        }
+
+        return result0;
+      }
+
+      function parse_hex12() {
+        var result0, result1, result2;
+        var pos0;
+        pos0 = pos;
+        result0 = parse_hex4();
+
+        if (result0 !== null) {
+          result1 = parse_hex4();
+
+          if (result1 !== null) {
+            result2 = parse_hex4();
+
+            if (result2 !== null) {
+              result0 = [result0, result1, result2];
+            } else {
+              result0 = null;
+              pos = pos0;
+            }
+          } else {
+            result0 = null;
+            pos = pos0;
+          }
+        } else {
+          result0 = null;
+          pos = pos0;
+        }
+
+        return result0;
+      }
+
+      function parse_Refer_To() {
+        var result0, result1, result2, result3;
+        var pos0, pos1, pos2;
+        pos0 = pos;
+        pos1 = pos;
+        result0 = parse_SIP_URI_noparams();
+
+        if (result0 === null) {
+          result0 = parse_name_addr();
+        }
+
+        if (result0 !== null) {
+          result1 = [];
+          pos2 = pos;
+          result2 = parse_SEMI();
+
+          if (result2 !== null) {
+            result3 = parse_generic_param();
+
+            if (result3 !== null) {
+              result2 = [result2, result3];
+            } else {
+              result2 = null;
+              pos = pos2;
+            }
+          } else {
+            result2 = null;
+            pos = pos2;
+          }
+
+          while (result2 !== null) {
+            result1.push(result2);
+            pos2 = pos;
+            result2 = parse_SEMI();
+
+            if (result2 !== null) {
+              result3 = parse_generic_param();
+
+              if (result3 !== null) {
+                result2 = [result2, result3];
+              } else {
+                result2 = null;
+                pos = pos2;
+              }
+            } else {
+              result2 = null;
+              pos = pos2;
+            }
+          }
+
+          if (result1 !== null) {
+            result0 = [result0, result1];
+          } else {
+            result0 = null;
+            pos = pos1;
+          }
+        } else {
+          result0 = null;
+          pos = pos1;
+        }
+
+        if (result0 !== null) {
+          result0 = function (offset) {
+            try {
+              data = new NameAddrHeader(data.uri, data.display_name, data.params);
+            } catch (e) {
+              data = -1;
+            }
+          }(pos0);
+        }
+
+        if (result0 === null) {
+          pos = pos0;
+        }
+
+        return result0;
+      }
+
+      function parse_Replaces() {
+        var result0, result1, result2, result3;
+        var pos0, pos1;
+        pos0 = pos;
+        result0 = parse_call_id();
+
+        if (result0 !== null) {
+          result1 = [];
+          pos1 = pos;
+          result2 = parse_SEMI();
+
+          if (result2 !== null) {
+            result3 = parse_replaces_param();
+
+            if (result3 !== null) {
+              result2 = [result2, result3];
+            } else {
+              result2 = null;
+              pos = pos1;
+            }
+          } else {
+            result2 = null;
+            pos = pos1;
+          }
+
+          while (result2 !== null) {
+            result1.push(result2);
+            pos1 = pos;
+            result2 = parse_SEMI();
+
+            if (result2 !== null) {
+              result3 = parse_replaces_param();
+
+              if (result3 !== null) {
+                result2 = [result2, result3];
+              } else {
+                result2 = null;
+                pos = pos1;
+              }
+            } else {
+              result2 = null;
+              pos = pos1;
+            }
+          }
+
+          if (result1 !== null) {
+            result0 = [result0, result1];
+          } else {
+            result0 = null;
+            pos = pos0;
+          }
+        } else {
+          result0 = null;
+          pos = pos0;
+        }
+
+        return result0;
+      }
+
+      function parse_call_id() {
+        var result0, result1, result2;
+        var pos0, pos1, pos2;
+        pos0 = pos;
+        pos1 = pos;
+        result0 = parse_word();
+
+        if (result0 !== null) {
+          pos2 = pos;
+
+          if (input.charCodeAt(pos) === 64) {
+            result1 = "@";
+            pos++;
+          } else {
+            result1 = null;
+
+            if (reportFailures === 0) {
+              matchFailed("\"@\"");
+            }
+          }
+
+          if (result1 !== null) {
+            result2 = parse_word();
+
+            if (result2 !== null) {
+              result1 = [result1, result2];
+            } else {
+              result1 = null;
+              pos = pos2;
+            }
+          } else {
+            result1 = null;
+            pos = pos2;
+          }
+
+          result1 = result1 !== null ? result1 : "";
+
+          if (result1 !== null) {
+            result0 = [result0, result1];
+          } else {
+            result0 = null;
+            pos = pos1;
+          }
+        } else {
+          result0 = null;
+          pos = pos1;
+        }
+
+        if (result0 !== null) {
+          result0 = function (offset) {
+            data.call_id = input.substring(pos, offset);
+          }(pos0);
+        }
+
+        if (result0 === null) {
+          pos = pos0;
+        }
+
+        return result0;
+      }
+
+      function parse_replaces_param() {
+        var result0;
+        result0 = parse_to_tag();
+
+        if (result0 === null) {
+          result0 = parse_from_tag();
+
+          if (result0 === null) {
+            result0 = parse_early_flag();
+
+            if (result0 === null) {
+              result0 = parse_generic_param();
+            }
+          }
+        }
+
+        return result0;
+      }
+
+      function parse_to_tag() {
+        var result0, result1, result2;
+        var pos0, pos1;
+        pos0 = pos;
+        pos1 = pos;
+
+        if (input.substr(pos, 6) === "to-tag") {
+          result0 = "to-tag";
+          pos += 6;
+        } else {
+          result0 = null;
+
+          if (reportFailures === 0) {
+            matchFailed("\"to-tag\"");
+          }
+        }
+
+        if (result0 !== null) {
+          result1 = parse_EQUAL();
+
+          if (result1 !== null) {
+            result2 = parse_token();
+
+            if (result2 !== null) {
+              result0 = [result0, result1, result2];
+            } else {
+              result0 = null;
+              pos = pos1;
+            }
+          } else {
+            result0 = null;
+            pos = pos1;
+          }
+        } else {
+          result0 = null;
+          pos = pos1;
+        }
+
+        if (result0 !== null) {
+          result0 = function (offset, to_tag) {
+            data.to_tag = to_tag;
+          }(pos0, result0[2]);
+        }
+
+        if (result0 === null) {
+          pos = pos0;
+        }
+
+        return result0;
+      }
+
+      function parse_from_tag() {
+        var result0, result1, result2;
+        var pos0, pos1;
+        pos0 = pos;
+        pos1 = pos;
+
+        if (input.substr(pos, 8) === "from-tag") {
+          result0 = "from-tag";
+          pos += 8;
+        } else {
+          result0 = null;
+
+          if (reportFailures === 0) {
+            matchFailed("\"from-tag\"");
+          }
+        }
+
+        if (result0 !== null) {
+          result1 = parse_EQUAL();
+
+          if (result1 !== null) {
+            result2 = parse_token();
+
+            if (result2 !== null) {
+              result0 = [result0, result1, result2];
+            } else {
+              result0 = null;
+              pos = pos1;
+            }
+          } else {
+            result0 = null;
+            pos = pos1;
+          }
+        } else {
+          result0 = null;
+          pos = pos1;
+        }
+
+        if (result0 !== null) {
+          result0 = function (offset, from_tag) {
+            data.from_tag = from_tag;
+          }(pos0, result0[2]);
+        }
+
+        if (result0 === null) {
+          pos = pos0;
+        }
+
+        return result0;
+      }
+
+      function parse_early_flag() {
+        var result0;
+        var pos0;
+        pos0 = pos;
+
+        if (input.substr(pos, 10) === "early-only") {
+          result0 = "early-only";
+          pos += 10;
+        } else {
+          result0 = null;
+
+          if (reportFailures === 0) {
+            matchFailed("\"early-only\"");
+          }
+        }
+
+        if (result0 !== null) {
+          result0 = function (offset) {
+            data.early_only = true;
+          }(pos0);
+        }
+
+        if (result0 === null) {
+          pos = pos0;
+        }
+
+        return result0;
+      }
+
+      function cleanupExpected(expected) {
+        expected.sort();
+        var lastExpected = null;
+        var cleanExpected = [];
+
+        for (var i = 0; i < expected.length; i++) {
+          if (expected[i] !== lastExpected) {
+            cleanExpected.push(expected[i]);
+            lastExpected = expected[i];
+          }
+        }
+
+        return cleanExpected;
+      }
+
+      function computeErrorPosition() {
+        /*
+         * The first idea was to use |String.split| to break the input up to the
+         * error position along newlines and derive the line and column from
+         * there. However IE's |split| implementation is so broken that it was
+         * enough to prevent it.
+         */
+        var line = 1;
+        var column = 1;
+        var seenCR = false;
+
+        for (var i = 0; i < Math.max(pos, rightmostFailuresPos); i++) {
+          var ch = input.charAt(i);
+
+          if (ch === "\n") {
+            if (!seenCR) {
+              line++;
+            }
+
+            column = 1;
+            seenCR = false;
+          } else if (ch === "\r" || ch === "\u2028" || ch === "\u2029") {
+            line++;
+            column = 1;
+            seenCR = true;
+          } else {
+            column++;
+            seenCR = false;
+          }
+        }
+
+        return {
+          line: line,
+          column: column
+        };
+      }
+
+      var URI = require('./URI');
+
+      var NameAddrHeader = require('./NameAddrHeader');
+
+      var data = {};
+      var result = parseFunctions[startRule]();
+      /*
+       * The parser is now in one of the following three states:
+       *
+       * 1. The parser successfully parsed the whole input.
+       *
+       *    - |result !== null|
+       *    - |pos === input.length|
+       *    - |rightmostFailuresExpected| may or may not contain something
+       *
+       * 2. The parser successfully parsed only a part of the input.
+       *
+       *    - |result !== null|
+       *    - |pos < input.length|
+       *    - |rightmostFailuresExpected| may or may not contain something
+       *
+       * 3. The parser did not successfully parse any part of the input.
+       *
+       *   - |result === null|
+       *   - |pos === 0|
+       *   - |rightmostFailuresExpected| contains at least one failure
+       *
+       * All code following this comment (including called functions) must
+       * handle these states.
+       */
+
+      if (result === null || pos !== input.length) {
+        var offset = Math.max(pos, rightmostFailuresPos);
+        var found = offset < input.length ? input.charAt(offset) : null;
+        var errorPosition = computeErrorPosition();
+        new this.SyntaxError(cleanupExpected(rightmostFailuresExpected), found, offset, errorPosition.line, errorPosition.column);
+        return -1;
+      }
+
+      return data;
+    },
+
+    /* Returns the parser source code. */
+    toSource: function toSource() {
+      return this._source;
+    }
+  };
+  /* Thrown when a parser encounters a syntax error. */
+
+  result.SyntaxError = function (expected, found, offset, line, column) {
+    function buildMessage(expected, found) {
+      var expectedHumanized, foundHumanized;
+
+      switch (expected.length) {
+        case 0:
+          expectedHumanized = "end of input";
+          break;
+
+        case 1:
+          expectedHumanized = expected[0];
+          break;
+
+        default:
+          expectedHumanized = expected.slice(0, expected.length - 1).join(", ") + " or " + expected[expected.length - 1];
+      }
+
+      foundHumanized = found ? quote(found) : "end of input";
+      return "Expected " + expectedHumanized + " but " + foundHumanized + " found.";
+    }
+
+    this.name = "SyntaxError";
+    this.expected = expected;
+    this.found = found;
+    this.message = buildMessage(expected, found);
+    this.offset = offset;
+    this.line = line;
+    this.column = column;
+  };
+
+  result.SyntaxError.prototype = Error.prototype;
+  return result;
+}();
+},{"./NameAddrHeader":11,"./URI":27}],8:[function(require,module,exports){
+"use strict";
+
+var pkg = require('../package.json');
+
+var C = require('./Constants');
+
+var Exceptions = require('./Exceptions');
+
+var Utils = require('./Utils');
+
+var UA = require('./UA');
+
+var URI = require('./URI');
+
+var NameAddrHeader = require('./NameAddrHeader');
+
+var Grammar = require('./Grammar');
+
+var WebSocketInterface = require('./WebSocketInterface');
+
+var debug = require('debug')('JsSIP');
+
+debug('version %s', pkg.version);
+/**
+ * Expose the JsSIP module.
+ */
+
+module.exports = {
+  C: C,
+  Exceptions: Exceptions,
+  Utils: Utils,
+  UA: UA,
+  URI: URI,
+  NameAddrHeader: NameAddrHeader,
+  WebSocketInterface: WebSocketInterface,
+  Grammar: Grammar,
+  // Expose the debug module.
+  debug: require('debug'),
+
+  get name() {
+    return pkg.title;
+  },
+
+  get version() {
+    return pkg.version;
+  }
+
+};
+},{"../package.json":40,"./Constants":2,"./Exceptions":6,"./Grammar":7,"./NameAddrHeader":11,"./UA":26,"./URI":27,"./Utils":28,"./WebSocketInterface":29,"debug":32}],9:[function(require,module,exports){
+"use strict";
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
+
+function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
+
+var debug = require('debug');
+
+var APP_NAME = 'JsSIP';
+
+module.exports = /*#__PURE__*/function () {
+  function Logger(prefix) {
+    _classCallCheck(this, Logger);
+
+    if (prefix) {
+      this._debug = debug["default"]("".concat(APP_NAME, ":").concat(prefix));
+      this._warn = debug["default"]("".concat(APP_NAME, ":WARN:").concat(prefix));
+      this._error = debug["default"]("".concat(APP_NAME, ":ERROR:").concat(prefix));
+    } else {
+      this._debug = debug["default"](APP_NAME);
+      this._warn = debug["default"]("".concat(APP_NAME, ":WARN"));
+      this._error = debug["default"]("".concat(APP_NAME, ":ERROR"));
+    }
+    /* eslint-disable no-console */
+
+
+    this._debug.log = console.info.bind(console);
+    this._warn.log = console.warn.bind(console);
+    this._error.log = console.error.bind(console);
+    /* eslint-enable no-console */
+  }
+
+  _createClass(Logger, [{
+    key: "debug",
+    get: function get() {
+      return this._debug;
+    }
+  }, {
+    key: "warn",
+    get: function get() {
+      return this._warn;
+    }
+  }, {
+    key: "error",
+    get: function get() {
+      return this._error;
+    }
+  }]);
+
+  return Logger;
+}();
+},{"debug":32}],10:[function(require,module,exports){
+"use strict";
+
+function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
+
+function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
+
+function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); }
+
+function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }
+
+function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; }
+
+function _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } return _assertThisInitialized(self); }
+
+function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; }
+
+function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Date.prototype.toString.call(Reflect.construct(Date, [], function () {})); return true; } catch (e) { return false; } }
+
+function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }
+
+var EventEmitter = require('events').EventEmitter;
+
+var Logger = require('./Logger');
+
+var JsSIP_C = require('./Constants');
+
+var SIPMessage = require('./SIPMessage');
+
+var Utils = require('./Utils');
+
+var RequestSender = require('./RequestSender');
+
+var Exceptions = require('./Exceptions');
+
+var URI = require('./URI');
+
+var logger = new Logger('Message');
+
+module.exports = /*#__PURE__*/function (_EventEmitter) {
+  _inherits(Message, _EventEmitter);
+
+  var _super = _createSuper(Message);
+
+  function Message(ua) {
+    var _this;
+
+    _classCallCheck(this, Message);
+
+    _this = _super.call(this);
+    _this._ua = ua;
+    _this._request = null;
+    _this._closed = false;
+    _this._direction = null;
+    _this._local_identity = null;
+    _this._remote_identity = null; // Whether an incoming message has been replied.
+
+    _this._is_replied = false; // Custom message empty object for high level use.
+
+    _this._data = {};
+    return _this;
+  }
+
+  _createClass(Message, [{
+    key: "send",
+    value: function send(target, body) {
+      var _this2 = this;
+
+      var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
+      var originalTarget = target;
+
+      if (target === undefined || body === undefined) {
+        throw new TypeError('Not enough arguments');
+      } // Check target validity.
+
+
+      target = this._ua.normalizeTarget(target);
+
+      if (!target) {
+        throw new TypeError("Invalid target: ".concat(originalTarget));
+      } // Get call options.
+
+
+      var extraHeaders = Utils.cloneArray(options.extraHeaders);
+      var eventHandlers = Utils.cloneObject(options.eventHandlers);
+      var contentType = options.contentType || 'text/plain';
+      var requestParams = {};
+
+      if (options.fromUserName) {
+        requestParams.from_uri = new URI('sip', options.fromUserName, this._ua.configuration.uri.host);
+        extraHeaders.push("P-Preferred-Identity: ".concat(this._ua.configuration.uri.toString()));
+      }
+
+      if (options.fromDisplayName) {
+        requestParams.from_display_name = options.fromDisplayName;
+      } // Set event handlers.
+
+
+      for (var event in eventHandlers) {
+        if (Object.prototype.hasOwnProperty.call(eventHandlers, event)) {
+          this.on(event, eventHandlers[event]);
+        }
+      }
+
+      extraHeaders.push("Content-Type: ".concat(contentType));
+      this._request = new SIPMessage.OutgoingRequest(JsSIP_C.MESSAGE, target, this._ua, requestParams, extraHeaders);
+
+      if (body) {
+        this._request.body = body;
+      }
+
+      var request_sender = new RequestSender(this._ua, this._request, {
+        onRequestTimeout: function onRequestTimeout() {
+          _this2._onRequestTimeout();
+        },
+        onTransportError: function onTransportError() {
+          _this2._onTransportError();
+        },
+        onReceiveResponse: function onReceiveResponse(response) {
+          _this2._receiveResponse(response);
+        }
+      });
+
+      this._newMessage('local', this._request);
+
+      request_sender.send();
+    }
+  }, {
+    key: "init_incoming",
+    value: function init_incoming(request) {
+      this._request = request;
+
+      this._newMessage('remote', request); // Reply with a 200 OK if the user didn't reply.
+
+
+      if (!this._is_replied) {
+        this._is_replied = true;
+        request.reply(200);
+      }
+
+      this._close();
+    }
+    /**
+     * Accept the incoming Message
+     * Only valid for incoming Messages
+     */
+
+  }, {
+    key: "accept",
+    value: function accept() {
+      var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
+      var extraHeaders = Utils.cloneArray(options.extraHeaders);
+      var body = options.body;
+
+      if (this._direction !== 'incoming') {
+        throw new Exceptions.NotSupportedError('"accept" not supported for outgoing Message');
+      }
+
+      if (this._is_replied) {
+        throw new Error('incoming Message already replied');
+      }
+
+      this._is_replied = true;
+
+      this._request.reply(200, null, extraHeaders, body);
+    }
+    /**
+     * Reject the incoming Message
+     * Only valid for incoming Messages
+     */
+
+  }, {
+    key: "reject",
+    value: function reject() {
+      var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
+      var status_code = options.status_code || 480;
+      var reason_phrase = options.reason_phrase;
+      var extraHeaders = Utils.cloneArray(options.extraHeaders);
+      var body = options.body;
+
+      if (this._direction !== 'incoming') {
+        throw new Exceptions.NotSupportedError('"reject" not supported for outgoing Message');
+      }
+
+      if (this._is_replied) {
+        throw new Error('incoming Message already replied');
+      }
+
+      if (status_code < 300 || status_code >= 700) {
+        throw new TypeError("Invalid status_code: ".concat(status_code));
+      }
+
+      this._is_replied = true;
+
+      this._request.reply(status_code, reason_phrase, extraHeaders, body);
+    }
+  }, {
+    key: "_receiveResponse",
+    value: function _receiveResponse(response) {
+      if (this._closed) {
+        return;
+      }
+
+      switch (true) {
+        case /^1[0-9]{2}$/.test(response.status_code):
+          // Ignore provisional responses.
+          break;
+
+        case /^2[0-9]{2}$/.test(response.status_code):
+          this._succeeded('remote', response);
+
+          break;
+
+        default:
+          {
+            var cause = Utils.sipErrorCause(response.status_code);
+
+            this._failed('remote', response, cause);
+
+            break;
+          }
+      }
+    }
+  }, {
+    key: "_onRequestTimeout",
+    value: function _onRequestTimeout() {
+      if (this._closed) {
+        return;
+      }
+
+      this._failed('system', null, JsSIP_C.causes.REQUEST_TIMEOUT);
+    }
+  }, {
+    key: "_onTransportError",
+    value: function _onTransportError() {
+      if (this._closed) {
+        return;
+      }
+
+      this._failed('system', null, JsSIP_C.causes.CONNECTION_ERROR);
+    }
+  }, {
+    key: "_close",
+    value: function _close() {
+      this._closed = true;
+
+      this._ua.destroyMessage(this);
+    }
+    /**
+     * Internal Callbacks
+     */
+
+  }, {
+    key: "_newMessage",
+    value: function _newMessage(originator, request) {
+      if (originator === 'remote') {
+        this._direction = 'incoming';
+        this._local_identity = request.to;
+        this._remote_identity = request.from;
+      } else if (originator === 'local') {
+        this._direction = 'outgoing';
+        this._local_identity = request.from;
+        this._remote_identity = request.to;
+      }
+
+      this._ua.newMessage(this, {
+        originator: originator,
+        message: this,
+        request: request
+      });
+    }
+  }, {
+    key: "_failed",
+    value: function _failed(originator, response, cause) {
+      logger.debug('MESSAGE failed');
+
+      this._close();
+
+      logger.debug('emit "failed"');
+      this.emit('failed', {
+        originator: originator,
+        response: response || null,
+        cause: cause
+      });
+    }
+  }, {
+    key: "_succeeded",
+    value: function _succeeded(originator, response) {
+      logger.debug('MESSAGE succeeded');
+
+      this._close();
+
+      logger.debug('emit "succeeded"');
+      this.emit('succeeded', {
+        originator: originator,
+        response: response
+      });
+    }
+  }, {
+    key: "direction",
+    get: function get() {
+      return this._direction;
+    }
+  }, {
+    key: "local_identity",
+    get: function get() {
+      return this._local_identity;
+    }
+  }, {
+    key: "remote_identity",
+    get: function get() {
+      return this._remote_identity;
+    }
+  }]);
+
+  return Message;
+}(EventEmitter);
+},{"./Constants":2,"./Exceptions":6,"./Logger":9,"./RequestSender":20,"./SIPMessage":21,"./URI":27,"./Utils":28,"events":31}],11:[function(require,module,exports){
+"use strict";
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
+
+function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
+
+var URI = require('./URI');
+
+var Grammar = require('./Grammar');
+
+module.exports = /*#__PURE__*/function () {
+  _createClass(NameAddrHeader, null, [{
+    key: "parse",
+
+    /**
+     * Parse the given string and returns a NameAddrHeader instance or undefined if
+     * it is an invalid NameAddrHeader.
+     */
+    value: function parse(name_addr_header) {
+      name_addr_header = Grammar.parse(name_addr_header, 'Name_Addr_Header');
+
+      if (name_addr_header !== -1) {
+        return name_addr_header;
+      } else {
+        return undefined;
+      }
+    }
+  }]);
+
+  function NameAddrHeader(uri, display_name, parameters) {
+    _classCallCheck(this, NameAddrHeader);
+
+    // Checks.
+    if (!uri || !(uri instanceof URI)) {
+      throw new TypeError('missing or invalid "uri" parameter');
+    } // Initialize parameters.
+
+
+    this._uri = uri;
+    this._parameters = {};
+    this.display_name = display_name;
+
+    for (var param in parameters) {
+      if (Object.prototype.hasOwnProperty.call(parameters, param)) {
+        this.setParam(param, parameters[param]);
+      }
+    }
+  }
+
+  _createClass(NameAddrHeader, [{
+    key: "setParam",
+    value: function setParam(key, value) {
+      if (key) {
+        this._parameters[key.toLowerCase()] = typeof value === 'undefined' || value === null ? null : value.toString();
+      }
+    }
+  }, {
+    key: "getParam",
+    value: function getParam(key) {
+      if (key) {
+        return this._parameters[key.toLowerCase()];
+      }
+    }
+  }, {
+    key: "hasParam",
+    value: function hasParam(key) {
+      if (key) {
+        return this._parameters.hasOwnProperty(key.toLowerCase()) && true || false;
+      }
+    }
+  }, {
+    key: "deleteParam",
+    value: function deleteParam(parameter) {
+      parameter = parameter.toLowerCase();
+
+      if (this._parameters.hasOwnProperty(parameter)) {
+        var value = this._parameters[parameter];
+        delete this._parameters[parameter];
+        return value;
+      }
+    }
+  }, {
+    key: "clearParams",
+    value: function clearParams() {
+      this._parameters = {};
+    }
+  }, {
+    key: "clone",
+    value: function clone() {
+      return new NameAddrHeader(this._uri.clone(), this._display_name, JSON.parse(JSON.stringify(this._parameters)));
+    }
+  }, {
+    key: "_quote",
+    value: function _quote(str) {
+      return str.replace(/\\/g, '\\\\').replace(/"/g, '\\"');
+    }
+  }, {
+    key: "toString",
+    value: function toString() {
+      var body = this._display_name ? "\"".concat(this._quote(this._display_name), "\" ") : '';
+      body += "<".concat(this._uri.toString(), ">");
+
+      for (var parameter in this._parameters) {
+        if (Object.prototype.hasOwnProperty.call(this._parameters, parameter)) {
+          body += ";".concat(parameter);
+
+          if (this._parameters[parameter] !== null) {
+            body += "=".concat(this._parameters[parameter]);
+          }
+        }
+      }
+
+      return body;
+    }
+  }, {
+    key: "uri",
+    get: function get() {
+      return this._uri;
+    }
+  }, {
+    key: "display_name",
+    get: function get() {
+      return this._display_name;
+    },
+    set: function set(value) {
+      this._display_name = value === 0 ? '0' : value;
+    }
+  }]);
+
+  return NameAddrHeader;
+}();
+},{"./Grammar":7,"./URI":27}],12:[function(require,module,exports){
+"use strict";
+
+function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
+
+function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
+
+function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); }
+
+function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }
+
+function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; }
+
+function _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } return _assertThisInitialized(self); }
+
+function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; }
+
+function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Date.prototype.toString.call(Reflect.construct(Date, [], function () {})); return true; } catch (e) { return false; } }
+
+function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }
+
+var EventEmitter = require('events').EventEmitter;
+
+var Logger = require('./Logger');
+
+var JsSIP_C = require('./Constants');
+
+var SIPMessage = require('./SIPMessage');
+
+var Utils = require('./Utils');
+
+var RequestSender = require('./RequestSender');
+
+var Exceptions = require('./Exceptions');
+
+var logger = new Logger('Options');
+
+module.exports = /*#__PURE__*/function (_EventEmitter) {
+  _inherits(Options, _EventEmitter);
+
+  var _super = _createSuper(Options);
+
+  function Options(ua) {
+    var _this;
+
+    _classCallCheck(this, Options);
+
+    _this = _super.call(this);
+    _this._ua = ua;
+    _this._request = null;
+    _this._closed = false;
+    _this._direction = null;
+    _this._local_identity = null;
+    _this._remote_identity = null; // Whether an incoming message has been replied.
+
+    _this._is_replied = false; // Custom message empty object for high level use.
+
+    _this._data = {};
+    return _this;
+  }
+
+  _createClass(Options, [{
+    key: "send",
+    value: function send(target, body) {
+      var _this2 = this;
+
+      var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
+      var originalTarget = target;
+
+      if (target === undefined) {
+        throw new TypeError('A target is required for OPTIONS');
+      } // Check target validity.
+
+
+      target = this._ua.normalizeTarget(target);
+
+      if (!target) {
+        throw new TypeError("Invalid target: ".concat(originalTarget));
+      } // Get call options.
+
+
+      var extraHeaders = Utils.cloneArray(options.extraHeaders);
+      var eventHandlers = Utils.cloneObject(options.eventHandlers);
+      var contentType = options.contentType || 'application/sdp'; // Set event handlers.
+
+      for (var event in eventHandlers) {
+        if (Object.prototype.hasOwnProperty.call(eventHandlers, event)) {
+          this.on(event, eventHandlers[event]);
+        }
+      }
+
+      extraHeaders.push("Content-Type: ".concat(contentType));
+      this._request = new SIPMessage.OutgoingRequest(JsSIP_C.OPTIONS, target, this._ua, null, extraHeaders);
+
+      if (body) {
+        this._request.body = body;
+      }
+
+      var request_sender = new RequestSender(this._ua, this._request, {
+        onRequestTimeout: function onRequestTimeout() {
+          _this2._onRequestTimeout();
+        },
+        onTransportError: function onTransportError() {
+          _this2._onTransportError();
+        },
+        onReceiveResponse: function onReceiveResponse(response) {
+          _this2._receiveResponse(response);
+        }
+      });
+
+      this._newOptions('local', this._request);
+
+      request_sender.send();
+    }
+  }, {
+    key: "init_incoming",
+    value: function init_incoming(request) {
+      this._request = request;
+
+      this._newOptions('remote', request); // Reply with a 200 OK if the user didn't reply.
+
+
+      if (!this._is_replied) {
+        this._is_replied = true;
+        request.reply(200);
+      }
+
+      this._close();
+    }
+    /**
+     * Accept the incoming Options
+     * Only valid for incoming Options
+     */
+
+  }, {
+    key: "accept",
+    value: function accept() {
+      var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
+      var extraHeaders = Utils.cloneArray(options.extraHeaders);
+      var body = options.body;
+
+      if (this._direction !== 'incoming') {
+        throw new Exceptions.NotSupportedError('"accept" not supported for outgoing Options');
+      }
+
+      if (this._is_replied) {
+        throw new Error('incoming Options already replied');
+      }
+
+      this._is_replied = true;
+
+      this._request.reply(200, null, extraHeaders, body);
+    }
+    /**
+     * Reject the incoming Options
+     * Only valid for incoming Options
+     */
+
+  }, {
+    key: "reject",
+    value: function reject() {
+      var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
+      var status_code = options.status_code || 480;
+      var reason_phrase = options.reason_phrase;
+      var extraHeaders = Utils.cloneArray(options.extraHeaders);
+      var body = options.body;
+
+      if (this._direction !== 'incoming') {
+        throw new Exceptions.NotSupportedError('"reject" not supported for outgoing Options');
+      }
+
+      if (this._is_replied) {
+        throw new Error('incoming Options already replied');
+      }
+
+      if (status_code < 300 || status_code >= 700) {
+        throw new TypeError("Invalid status_code: ".concat(status_code));
+      }
+
+      this._is_replied = true;
+
+      this._request.reply(status_code, reason_phrase, extraHeaders, body);
+    }
+  }, {
+    key: "_receiveResponse",
+    value: function _receiveResponse(response) {
+      if (this._closed) {
+        return;
+      }
+
+      switch (true) {
+        case /^1[0-9]{2}$/.test(response.status_code):
+          // Ignore provisional responses.
+          break;
+
+        case /^2[0-9]{2}$/.test(response.status_code):
+          this._succeeded('remote', response);
+
+          break;
+
+        default:
+          {
+            var cause = Utils.sipErrorCause(response.status_code);
+
+            this._failed('remote', response, cause);
+
+            break;
+          }
+      }
+    }
+  }, {
+    key: "_onRequestTimeout",
+    value: function _onRequestTimeout() {
+      if (this._closed) {
+        return;
+      }
+
+      this._failed('system', null, JsSIP_C.causes.REQUEST_TIMEOUT);
+    }
+  }, {
+    key: "_onTransportError",
+    value: function _onTransportError() {
+      if (this._closed) {
+        return;
+      }
+
+      this._failed('system', null, JsSIP_C.causes.CONNECTION_ERROR);
+    }
+  }, {
+    key: "_close",
+    value: function _close() {
+      this._closed = true;
+
+      this._ua.destroyMessage(this);
+    }
+    /**
+     * Internal Callbacks
+     */
+
+  }, {
+    key: "_newOptions",
+    value: function _newOptions(originator, request) {
+      if (originator === 'remote') {
+        this._direction = 'incoming';
+        this._local_identity = request.to;
+        this._remote_identity = request.from;
+      } else if (originator === 'local') {
+        this._direction = 'outgoing';
+        this._local_identity = request.from;
+        this._remote_identity = request.to;
+      }
+
+      this._ua.newOptions(this, {
+        originator: originator,
+        message: this,
+        request: request
+      });
+    }
+  }, {
+    key: "_failed",
+    value: function _failed(originator, response, cause) {
+      logger.debug('OPTIONS failed');
+
+      this._close();
+
+      logger.debug('emit "failed"');
+      this.emit('failed', {
+        originator: originator,
+        response: response || null,
+        cause: cause
+      });
+    }
+  }, {
+    key: "_succeeded",
+    value: function _succeeded(originator, response) {
+      logger.debug('OPTIONS succeeded');
+
+      this._close();
+
+      logger.debug('emit "succeeded"');
+      this.emit('succeeded', {
+        originator: originator,
+        response: response
+      });
+    }
+  }, {
+    key: "direction",
+    get: function get() {
+      return this._direction;
+    }
+  }, {
+    key: "local_identity",
+    get: function get() {
+      return this._local_identity;
+    }
+  }, {
+    key: "remote_identity",
+    get: function get() {
+      return this._remote_identity;
+    }
+  }]);
+
+  return Options;
+}(EventEmitter);
+},{"./Constants":2,"./Exceptions":6,"./Logger":9,"./RequestSender":20,"./SIPMessage":21,"./Utils":28,"events":31}],13:[function(require,module,exports){
+"use strict";
+
+function _createForOfIteratorHelper(o, allowArrayLike) { var it; if (typeof Symbol === "undefined" || o[Symbol.iterator] == null) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = o[Symbol.iterator](); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it["return"] != null) it["return"](); } finally { if (didErr) throw err; } } }; }
+
+function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
+
+function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; }
+
+var Logger = require('./Logger');
+
+var Grammar = require('./Grammar');
+
+var SIPMessage = require('./SIPMessage');
+
+var logger = new Logger('Parser');
+/**
+ * Parse SIP Message
+ */
+
+exports.parseMessage = function (data, ua) {
+  var message;
+  var bodyStart;
+  var headerEnd = data.indexOf('\r\n');
+
+  if (headerEnd === -1) {
+    logger.warn('parseMessage() | no CRLF found, not a SIP message');
+    return;
+  } // Parse first line. Check if it is a Request or a Reply.
+
+
+  var firstLine = data.substring(0, headerEnd);
+  var parsed = Grammar.parse(firstLine, 'Request_Response');
+
+  if (parsed === -1) {
+    logger.warn("parseMessage() | error parsing first line of SIP message: \"".concat(firstLine, "\""));
+    return;
+  } else if (!parsed.status_code) {
+    message = new SIPMessage.IncomingRequest(ua);
+    message.method = parsed.method;
+    message.ruri = parsed.uri;
+  } else {
+    message = new SIPMessage.IncomingResponse();
+    message.status_code = parsed.status_code;
+    message.reason_phrase = parsed.reason_phrase;
+  }
+
+  message.data = data;
+  var headerStart = headerEnd + 2;
+  /* Loop over every line in data. Detect the end of each header and parse
+  * it or simply add to the headers collection.
+  */
+
+  while (true) {
+    headerEnd = getHeader(data, headerStart); // The SIP message has normally finished.
+
+    if (headerEnd === -2) {
+      bodyStart = headerStart + 2;
+      break;
+    } // Data.indexOf returned -1 due to a malformed message.
+    else if (headerEnd === -1) {
+        logger.warn('parseMessage() | malformed message');
+        return;
+      }
+
+    parsed = parseHeader(message, data, headerStart, headerEnd);
+
+    if (parsed !== true) {
+      logger.warn('parseMessage() |', parsed.error);
+      return;
+    }
+
+    headerStart = headerEnd + 2;
+  }
+  /* RFC3261 18.3.
+   * If there are additional bytes in the transport packet
+   * beyond the end of the body, they MUST be discarded.
+   */
+
+
+  if (message.hasHeader('content-length')) {
+    var contentLength = message.getHeader('content-length');
+    message.body = data.substr(bodyStart, contentLength);
+  } else {
+    message.body = data.substring(bodyStart);
+  }
+
+  return message;
+};
+/**
+ * Extract and parse every header of a SIP message.
+ */
+
+
+function getHeader(data, headerStart) {
+  // 'start' position of the header.
+  var start = headerStart; // 'end' position of the header.
+
+  var end = 0; // 'partial end' position of the header.
+
+  var partialEnd = 0; // End of message.
+
+  if (data.substring(start, start + 2).match(/(^\r\n)/)) {
+    return -2;
+  }
+
+  while (end === 0) {
+    // Partial End of Header.
+    partialEnd = data.indexOf('\r\n', start); // 'indexOf' returns -1 if the value to be found never occurs.
+
+    if (partialEnd === -1) {
+      return partialEnd;
+    }
+
+    if (!data.substring(partialEnd + 2, partialEnd + 4).match(/(^\r\n)/) && data.charAt(partialEnd + 2).match(/(^\s+)/)) {
+      // Not the end of the message. Continue from the next position.
+      start = partialEnd + 2;
+    } else {
+      end = partialEnd;
+    }
+  }
+
+  return end;
+}
+
+function parseHeader(message, data, headerStart, headerEnd) {
+  var parsed;
+  var hcolonIndex = data.indexOf(':', headerStart);
+  var headerName = data.substring(headerStart, hcolonIndex).trim();
+  var headerValue = data.substring(hcolonIndex + 1, headerEnd).trim(); // If header-field is well-known, parse it.
+
+  switch (headerName.toLowerCase()) {
+    case 'via':
+    case 'v':
+      message.addHeader('via', headerValue);
+
+      if (message.getHeaders('via').length === 1) {
+        parsed = message.parseHeader('Via');
+
+        if (parsed) {
+          message.via = parsed;
+          message.via_branch = parsed.branch;
+        }
+      } else {
+        parsed = 0;
+      }
+
+      break;
+
+    case 'from':
+    case 'f':
+      message.setHeader('from', headerValue);
+      parsed = message.parseHeader('from');
+
+      if (parsed) {
+        message.from = parsed;
+        message.from_tag = parsed.getParam('tag');
+      }
+
+      break;
+
+    case 'to':
+    case 't':
+      message.setHeader('to', headerValue);
+      parsed = message.parseHeader('to');
+
+      if (parsed) {
+        message.to = parsed;
+        message.to_tag = parsed.getParam('tag');
+      }
+
+      break;
+
+    case 'record-route':
+      parsed = Grammar.parse(headerValue, 'Record_Route');
+
+      if (parsed === -1) {
+        parsed = undefined;
+      } else {
+        var _iterator = _createForOfIteratorHelper(parsed),
+            _step;
+
+        try {
+          for (_iterator.s(); !(_step = _iterator.n()).done;) {
+            var header = _step.value;
+            message.addHeader('record-route', headerValue.substring(header.possition, header.offset));
+            message.headers['Record-Route'][message.getHeaders('record-route').length - 1].parsed = header.parsed;
+          }
+        } catch (err) {
+          _iterator.e(err);
+        } finally {
+          _iterator.f();
+        }
+      }
+
+      break;
+
+    case 'call-id':
+    case 'i':
+      message.setHeader('call-id', headerValue);
+      parsed = message.parseHeader('call-id');
+
+      if (parsed) {
+        message.call_id = headerValue;
+      }
+
+      break;
+
+    case 'contact':
+    case 'm':
+      parsed = Grammar.parse(headerValue, 'Contact');
+
+      if (parsed === -1) {
+        parsed = undefined;
+      } else {
+        var _iterator2 = _createForOfIteratorHelper(parsed),
+            _step2;
+
+        try {
+          for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
+            var _header = _step2.value;
+            message.addHeader('contact', headerValue.substring(_header.possition, _header.offset));
+            message.headers.Contact[message.getHeaders('contact').length - 1].parsed = _header.parsed;
+          }
+        } catch (err) {
+          _iterator2.e(err);
+        } finally {
+          _iterator2.f();
+        }
+      }
+
+      break;
+
+    case 'content-length':
+    case 'l':
+      message.setHeader('content-length', headerValue);
+      parsed = message.parseHeader('content-length');
+      break;
+
+    case 'content-type':
+    case 'c':
+      message.setHeader('content-type', headerValue);
+      parsed = message.parseHeader('content-type');
+      break;
+
+    case 'cseq':
+      message.setHeader('cseq', headerValue);
+      parsed = message.parseHeader('cseq');
+
+      if (parsed) {
+        message.cseq = parsed.value;
+      }
+
+      if (message instanceof SIPMessage.IncomingResponse) {
+        message.method = parsed.method;
+      }
+
+      break;
+
+    case 'max-forwards':
+      message.setHeader('max-forwards', headerValue);
+      parsed = message.parseHeader('max-forwards');
+      break;
+
+    case 'www-authenticate':
+      message.setHeader('www-authenticate', headerValue);
+      parsed = message.parseHeader('www-authenticate');
+      break;
+
+    case 'proxy-authenticate':
+      message.setHeader('proxy-authenticate', headerValue);
+      parsed = message.parseHeader('proxy-authenticate');
+      break;
+
+    case 'session-expires':
+    case 'x':
+      message.setHeader('session-expires', headerValue);
+      parsed = message.parseHeader('session-expires');
+
+      if (parsed) {
+        message.session_expires = parsed.expires;
+        message.session_expires_refresher = parsed.refresher;
+      }
+
+      break;
+
+    case 'refer-to':
+    case 'r':
+      message.setHeader('refer-to', headerValue);
+      parsed = message.parseHeader('refer-to');
+
+      if (parsed) {
+        message.refer_to = parsed;
+      }
+
+      break;
+
+    case 'replaces':
+      message.setHeader('replaces', headerValue);
+      parsed = message.parseHeader('replaces');
+
+      if (parsed) {
+        message.replaces = parsed;
+      }
+
+      break;
+
+    case 'event':
+    case 'o':
+      message.setHeader('event', headerValue);
+      parsed = message.parseHeader('event');
+
+      if (parsed) {
+        message.event = parsed;
+      }
+
+      break;
+
+    default:
+      // Do not parse this header.
+      message.addHeader(headerName, headerValue);
+      parsed = 0;
+  }
+
+  if (parsed === undefined) {
+    return {
+      error: "error parsing header \"".concat(headerName, "\"")
+    };
+  } else {
+    return true;
+  }
+}
+},{"./Grammar":7,"./Logger":9,"./SIPMessage":21}],14:[function(require,module,exports){
+"use strict";
+
+function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }
+
+function _createForOfIteratorHelper(o, allowArrayLike) { var it; if (typeof Symbol === "undefined" || o[Symbol.iterator] == null) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e2) { throw _e2; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = o[Symbol.iterator](); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e3) { didErr = true; err = _e3; }, f: function f() { try { if (!normalCompletion && it["return"] != null) it["return"](); } finally { if (didErr) throw err; } } }; }
+
+function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
+
+function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; }
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
+
+function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
+
+function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); }
+
+function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }
+
+function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; }
+
+function _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } return _assertThisInitialized(self); }
+
+function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; }
+
+function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Date.prototype.toString.call(Reflect.construct(Date, [], function () {})); return true; } catch (e) { return false; } }
+
+function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }
+
+/* globals RTCPeerConnection: false, RTCSessionDescription: false */
+var EventEmitter = require('events').EventEmitter;
+
+var sdp_transform = require('sdp-transform');
+
+var Logger = require('./Logger');
+
+var JsSIP_C = require('./Constants');
+
+var Exceptions = require('./Exceptions');
+
+var Transactions = require('./Transactions');
+
+var Utils = require('./Utils');
+
+var Timers = require('./Timers');
+
+var SIPMessage = require('./SIPMessage');
+
+var Dialog = require('./Dialog');
+
+var RequestSender = require('./RequestSender');
+
+var RTCSession_DTMF = require('./RTCSession/DTMF');
+
+var RTCSession_Info = require('./RTCSession/Info');
+
+var RTCSession_ReferNotifier = require('./RTCSession/ReferNotifier');
+
+var RTCSession_ReferSubscriber = require('./RTCSession/ReferSubscriber');
+
+var URI = require('./URI');
+
+var logger = new Logger('RTCSession');
+var C = {
+  // RTCSession states.
+  STATUS_NULL: 0,
+  STATUS_INVITE_SENT: 1,
+  STATUS_1XX_RECEIVED: 2,
+  STATUS_INVITE_RECEIVED: 3,
+  STATUS_WAITING_FOR_ANSWER: 4,
+  STATUS_ANSWERED: 5,
+  STATUS_WAITING_FOR_ACK: 6,
+  STATUS_CANCELED: 7,
+  STATUS_TERMINATED: 8,
+  STATUS_CONFIRMED: 9
+};
+/**
+ * Local variables.
+ */
+
+var holdMediaTypes = ['audio', 'video'];
+
+module.exports = /*#__PURE__*/function (_EventEmitter) {
+  _inherits(RTCSession, _EventEmitter);
+
+  var _super = _createSuper(RTCSession);
+
+  _createClass(RTCSession, null, [{
+    key: "C",
+
+    /**
+     * Expose C object.
+     */
+    get: function get() {
+      return C;
+    }
+  }]);
+
+  function RTCSession(ua) {
+    var _this;
+
+    _classCallCheck(this, RTCSession);
+
+    logger.debug('new');
+    _this = _super.call(this);
+    _this._id = null;
+    _this._ua = ua;
+    _this._status = C.STATUS_NULL;
+    _this._dialog = null;
+    _this._earlyDialogs = {};
+    _this._contact = null;
+    _this._from_tag = null;
+    _this._to_tag = null; // The RTCPeerConnection instance (public attribute).
+
+    _this._connection = null; // Prevent races on serial PeerConnction operations.
+
+    _this._connectionPromiseQueue = Promise.resolve(); // Incoming/Outgoing request being currently processed.
+
+    _this._request = null; // Cancel state for initial outgoing request.
+
+    _this._is_canceled = false;
+    _this._cancel_reason = ''; // RTCSession confirmation flag.
+
+    _this._is_confirmed = false; // Is late SDP being negotiated.
+
+    _this._late_sdp = false; // Default rtcOfferConstraints and rtcAnswerConstrainsts (passed in connect() or answer()).
+
+    _this._rtcOfferConstraints = null;
+    _this._rtcAnswerConstraints = null; // Local MediaStream.
+
+    _this._localMediaStream = null;
+    _this._localMediaStreamLocallyGenerated = false; // Flag to indicate PeerConnection ready for new actions.
+
+    _this._rtcReady = true; // Flag to indicate ICE candidate gathering is finished even if iceGatheringState is not yet 'complete'.
+
+    _this._iceReady = false; // SIP Timers.
+
+    _this._timers = {
+      ackTimer: null,
+      expiresTimer: null,
+      invite2xxTimer: null,
+      userNoAnswerTimer: null
+    }; // Session info.
+
+    _this._direction = null;
+    _this._local_identity = null;
+    _this._remote_identity = null;
+    _this._start_time = null;
+    _this._end_time = null;
+    _this._tones = null; // Mute/Hold state.
+
+    _this._audioMuted = false;
+    _this._videoMuted = false;
+    _this._localHold = false;
+    _this._remoteHold = false; // Session Timers (RFC 4028).
+
+    _this._sessionTimers = {
+      enabled: _this._ua.configuration.session_timers,
+      refreshMethod: _this._ua.configuration.session_timers_refresh_method,
+      defaultExpires: JsSIP_C.SESSION_EXPIRES,
+      currentExpires: null,
+      running: false,
+      refresher: false,
+      timer: null // A setTimeout.
+
+    }; // Map of ReferSubscriber instances indexed by the REFER's CSeq number.
+
+    _this._referSubscribers = {}; // Custom session empty object for high level use.
+
+    _this._data = {};
+    return _this;
+  }
+  /**
+   * User API
+   */
+  // Expose RTCSession constants as a property of the RTCSession instance.
+
+
+  _createClass(RTCSession, [{
+    key: "isInProgress",
+    value: function isInProgress() {
+      switch (this._status) {
+        case C.STATUS_NULL:
+        case C.STATUS_INVITE_SENT:
+        case C.STATUS_1XX_RECEIVED:
+        case C.STATUS_INVITE_RECEIVED:
+        case C.STATUS_WAITING_FOR_ANSWER:
+          return true;
+
+        default:
+          return false;
+      }
+    }
+  }, {
+    key: "isEstablished",
+    value: function isEstablished() {
+      switch (this._status) {
+        case C.STATUS_ANSWERED:
+        case C.STATUS_WAITING_FOR_ACK:
+        case C.STATUS_CONFIRMED:
+          return true;
+
+        default:
+          return false;
+      }
+    }
+  }, {
+    key: "isEnded",
+    value: function isEnded() {
+      switch (this._status) {
+        case C.STATUS_CANCELED:
+        case C.STATUS_TERMINATED:
+          return true;
+
+        default:
+          return false;
+      }
+    }
+  }, {
+    key: "isMuted",
+    value: function isMuted() {
+      return {
+        audio: this._audioMuted,
+        video: this._videoMuted
+      };
+    }
+  }, {
+    key: "isOnHold",
+    value: function isOnHold() {
+      return {
+        local: this._localHold,
+        remote: this._remoteHold
+      };
+    }
+  }, {
+    key: "connect",
+    value: function connect(target) {
+      var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
+      var initCallback = arguments.length > 2 ? arguments[2] : undefined;
+      logger.debug('connect()');
+      var originalTarget = target;
+      var eventHandlers = Utils.cloneObject(options.eventHandlers);
+      var extraHeaders = Utils.cloneArray(options.extraHeaders);
+      var mediaConstraints = Utils.cloneObject(options.mediaConstraints, {
+        audio: true,
+        video: true
+      });
+      var mediaStream = options.mediaStream || null;
+      var pcConfig = Utils.cloneObject(options.pcConfig, {
+        iceServers: []
+      });
+      var rtcConstraints = options.rtcConstraints || null;
+      var rtcOfferConstraints = options.rtcOfferConstraints || null;
+      this._rtcOfferConstraints = rtcOfferConstraints;
+      this._rtcAnswerConstraints = options.rtcAnswerConstraints || null;
+      this._data = options.data || this._data; // Check target.
+
+      if (target === undefined) {
+        throw new TypeError('Not enough arguments');
+      } // Check Session Status.
+
+
+      if (this._status !== C.STATUS_NULL) {
+        throw new Exceptions.InvalidStateError(this._status);
+      } // Check WebRTC support.
+
+
+      if (!window.RTCPeerConnection) {
+        throw new Exceptions.NotSupportedError('WebRTC not supported');
+      } // Check target validity.
+
+
+      target = this._ua.normalizeTarget(target);
+
+      if (!target) {
+        throw new TypeError("Invalid target: ".concat(originalTarget));
+      } // Session Timers.
+
+
+      if (this._sessionTimers.enabled) {
+        if (Utils.isDecimal(options.sessionTimersExpires)) {
+          if (options.sessionTimersExpires >= JsSIP_C.MIN_SESSION_EXPIRES) {
+            this._sessionTimers.defaultExpires = options.sessionTimersExpires;
+          } else {
+            this._sessionTimers.defaultExpires = JsSIP_C.SESSION_EXPIRES;
+          }
+        }
+      } // Set event handlers.
+
+
+      for (var event in eventHandlers) {
+        if (Object.prototype.hasOwnProperty.call(eventHandlers, event)) {
+          this.on(event, eventHandlers[event]);
+        }
+      } // Session parameter initialization.
+
+
+      this._from_tag = Utils.newTag(); // Set anonymous property.
+
+      var anonymous = options.anonymous || false;
+      var requestParams = {
+        from_tag: this._from_tag
+      };
+      this._contact = this._ua.contact.toString({
+        anonymous: anonymous,
+        outbound: true
+      });
+
+      if (anonymous) {
+        requestParams.from_display_name = 'Anonymous';
+        requestParams.from_uri = new URI('sip', 'anonymous', 'anonymous.invalid');
+        extraHeaders.push("P-Preferred-Identity: ".concat(this._ua.configuration.uri.toString()));
+        extraHeaders.push('Privacy: id');
+      } else if (options.fromUserName) {
+        requestParams.from_uri = new URI('sip', options.fromUserName, this._ua.configuration.uri.host);
+        extraHeaders.push("P-Preferred-Identity: ".concat(this._ua.configuration.uri.toString()));
+      }
+
+      if (options.fromDisplayName) {
+        requestParams.from_display_name = options.fromDisplayName;
+      }
+
+      extraHeaders.push("Contact: ".concat(this._contact));
+      extraHeaders.push('Content-Type: application/sdp');
+
+      if (this._sessionTimers.enabled) {
+        extraHeaders.push("Session-Expires: ".concat(this._sessionTimers.defaultExpires).concat(this._ua.configuration.session_timers_force_refresher ? ';refresher=uac' : ''));
+      }
+
+      this._request = new SIPMessage.InitialOutgoingInviteRequest(target, this._ua, requestParams, extraHeaders);
+      this._id = this._request.call_id + this._from_tag; // Create a new RTCPeerConnection instance.
+
+      this._createRTCConnection(pcConfig, rtcConstraints); // Set internal properties.
+
+
+      this._direction = 'outgoing';
+      this._local_identity = this._request.from;
+      this._remote_identity = this._request.to; // User explicitly provided a newRTCSession callback for this session.
+
+      if (initCallback) {
+        initCallback(this);
+      }
+
+      this._newRTCSession('local', this._request);
+
+      this._sendInitialRequest(mediaConstraints, rtcOfferConstraints, mediaStream);
+    }
+  }, {
+    key: "init_incoming",
+    value: function init_incoming(request, initCallback) {
+      var _this2 = this;
+
+      logger.debug('init_incoming()');
+      var expires;
+      var contentType = request.hasHeader('Content-Type') ? request.getHeader('Content-Type').toLowerCase() : undefined; // Check body and content type.
+
+      if (request.body && contentType !== 'application/sdp') {
+        request.reply(415);
+        return;
+      } // Session parameter initialization.
+
+
+      this._status = C.STATUS_INVITE_RECEIVED;
+      this._from_tag = request.from_tag;
+      this._id = request.call_id + this._from_tag;
+      this._request = request;
+      this._contact = this._ua.contact.toString(); // Get the Expires header value if exists.
+
+      if (request.hasHeader('expires')) {
+        expires = request.getHeader('expires') * 1000;
+      }
+      /* Set the to_tag before
+       * replying a response code that will create a dialog.
+       */
+
+
+      request.to_tag = Utils.newTag(); // An error on dialog creation will fire 'failed' event.
+
+      if (!this._createDialog(request, 'UAS', true)) {
+        request.reply(500, 'Missing Contact header field');
+        return;
+      }
+
+      if (request.body) {
+        this._late_sdp = false;
+      } else {
+        this._late_sdp = true;
+      }
+
+      this._status = C.STATUS_WAITING_FOR_ANSWER; // Set userNoAnswerTimer.
+
+      this._timers.userNoAnswerTimer = setTimeout(function () {
+        request.reply(408);
+
+        _this2._failed('local', null, JsSIP_C.causes.NO_ANSWER);
+      }, this._ua.configuration.no_answer_timeout);
+      /* Set expiresTimer
+       * RFC3261 13.3.1
+       */
+
+      if (expires) {
+        this._timers.expiresTimer = setTimeout(function () {
+          if (_this2._status === C.STATUS_WAITING_FOR_ANSWER) {
+            request.reply(487);
+
+            _this2._failed('system', null, JsSIP_C.causes.EXPIRES);
+          }
+        }, expires);
+      } // Set internal properties.
+
+
+      this._direction = 'incoming';
+      this._local_identity = request.to;
+      this._remote_identity = request.from; // A init callback was specifically defined.
+
+      if (initCallback) {
+        initCallback(this);
+      } // Fire 'newRTCSession' event.
+
+
+      this._newRTCSession('remote', request); // The user may have rejected the call in the 'newRTCSession' event.
+
+
+      if (this._status === C.STATUS_TERMINATED) {
+        return;
+      } // Reply 180.
+
+
+      request.reply(180, null, ["Contact: ".concat(this._contact)]); // Fire 'progress' event.
+      // TODO: Document that 'response' field in 'progress' event is null for incoming calls.
+
+      this._progress('local', null);
+    }
+    /**
+     * Answer the call.
+     */
+
+  }, {
+    key: "answer",
+    value: function answer() {
+      var _this3 = this;
+
+      var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
+      logger.debug('answer()');
+      var request = this._request;
+      var extraHeaders = Utils.cloneArray(options.extraHeaders);
+      var mediaConstraints = Utils.cloneObject(options.mediaConstraints);
+      var mediaStream = options.mediaStream || null;
+      var pcConfig = Utils.cloneObject(options.pcConfig, {
+        iceServers: []
+      });
+      var rtcConstraints = options.rtcConstraints || null;
+      var rtcAnswerConstraints = options.rtcAnswerConstraints || null;
+      var rtcOfferConstraints = Utils.cloneObject(options.rtcOfferConstraints);
+      var tracks;
+      var peerHasAudioLine = false;
+      var peerHasVideoLine = false;
+      var peerOffersFullAudio = false;
+      var peerOffersFullVideo = false;
+      this._rtcAnswerConstraints = rtcAnswerConstraints;
+      this._rtcOfferConstraints = options.rtcOfferConstraints || null;
+      this._data = options.data || this._data; // Check Session Direction and Status.
+
+      if (this._direction !== 'incoming') {
+        throw new Exceptions.NotSupportedError('"answer" not supported for outgoing RTCSession');
+      } // Check Session status.
+
+
+      if (this._status !== C.STATUS_WAITING_FOR_ANSWER) {
+        throw new Exceptions.InvalidStateError(this._status);
+      } // Session Timers.
+
+
+      if (this._sessionTimers.enabled) {
+        if (Utils.isDecimal(options.sessionTimersExpires)) {
+          if (options.sessionTimersExpires >= JsSIP_C.MIN_SESSION_EXPIRES) {
+            this._sessionTimers.defaultExpires = options.sessionTimersExpires;
+          } else {
+            this._sessionTimers.defaultExpires = JsSIP_C.SESSION_EXPIRES;
+          }
+        }
+      }
+
+      this._status = C.STATUS_ANSWERED; // An error on dialog creation will fire 'failed' event.
+
+      if (!this._createDialog(request, 'UAS')) {
+        request.reply(500, 'Error creating dialog');
+        return;
+      }
+
+      clearTimeout(this._timers.userNoAnswerTimer);
+      extraHeaders.unshift("Contact: ".concat(this._contact)); // Determine incoming media from incoming SDP offer (if any).
+
+      var sdp = request.parseSDP(); // Make sure sdp.media is an array, not the case if there is only one media.
+
+      if (!Array.isArray(sdp.media)) {
+        sdp.media = [sdp.media];
+      } // Go through all medias in SDP to find offered capabilities to answer with.
+
+
+      var _iterator = _createForOfIteratorHelper(sdp.media),
+          _step;
+
+      try {
+        for (_iterator.s(); !(_step = _iterator.n()).done;) {
+          var m = _step.value;
+
+          if (m.type === 'audio') {
+            peerHasAudioLine = true;
+
+            if (!m.direction || m.direction === 'sendrecv') {
+              peerOffersFullAudio = true;
+            }
+          }
+
+          if (m.type === 'video') {
+            peerHasVideoLine = true;
+
+            if (!m.direction || m.direction === 'sendrecv') {
+              peerOffersFullVideo = true;
+            }
+          }
+        } // Remove audio from mediaStream if suggested by mediaConstraints.
+
+      } catch (err) {
+        _iterator.e(err);
+      } finally {
+        _iterator.f();
+      }
+
+      if (mediaStream && mediaConstraints.audio === false) {
+        tracks = mediaStream.getAudioTracks();
+
+        var _iterator2 = _createForOfIteratorHelper(tracks),
+            _step2;
+
+        try {
+          for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
+            var track = _step2.value;
+            mediaStream.removeTrack(track);
+          }
+        } catch (err) {
+          _iterator2.e(err);
+        } finally {
+          _iterator2.f();
+        }
+      } // Remove video from mediaStream if suggested by mediaConstraints.
+
+
+      if (mediaStream && mediaConstraints.video === false) {
+        tracks = mediaStream.getVideoTracks();
+
+        var _iterator3 = _createForOfIteratorHelper(tracks),
+            _step3;
+
+        try {
+          for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
+            var _track = _step3.value;
+            mediaStream.removeTrack(_track);
+          }
+        } catch (err) {
+          _iterator3.e(err);
+        } finally {
+          _iterator3.f();
+        }
+      } // Set audio constraints based on incoming stream if not supplied.
+
+
+      if (!mediaStream && mediaConstraints.audio === undefined) {
+        mediaConstraints.audio = peerOffersFullAudio;
+      } // Set video constraints based on incoming stream if not supplied.
+
+
+      if (!mediaStream && mediaConstraints.video === undefined) {
+        mediaConstraints.video = peerOffersFullVideo;
+      } // Don't ask for audio if the incoming offer has no audio section.
+
+
+      if (!mediaStream && !peerHasAudioLine && !rtcOfferConstraints.offerToReceiveAudio) {
+        mediaConstraints.audio = false;
+      } // Don't ask for video if the incoming offer has no video section.
+
+
+      if (!mediaStream && !peerHasVideoLine && !rtcOfferConstraints.offerToReceiveVideo) {
+        mediaConstraints.video = false;
+      } // Create a new RTCPeerConnection instance.
+      // TODO: This may throw an error, should react.
+
+
+      this._createRTCConnection(pcConfig, rtcConstraints);
+
+      Promise.resolve() // Handle local MediaStream.
+      .then(function () {
+        // A local MediaStream is given, use it.
+        if (mediaStream) {
+          return mediaStream;
+        } // Audio and/or video requested, prompt getUserMedia.
+        else if (mediaConstraints.audio || mediaConstraints.video) {
+            _this3._localMediaStreamLocallyGenerated = true;
+            return navigator.mediaDevices.getUserMedia(mediaConstraints)["catch"](function (error) {
+              if (_this3._status === C.STATUS_TERMINATED) {
+                throw new Error('terminated');
+              }
+
+              request.reply(480);
+
+              _this3._failed('local', null, JsSIP_C.causes.USER_DENIED_MEDIA_ACCESS);
+
+              logger.warn('emit "getusermediafailed" [error:%o]', error);
+
+              _this3.emit('getusermediafailed', error);
+
+              throw new Error('getUserMedia() failed');
+            });
+          }
+      }) // Attach MediaStream to RTCPeerconnection.
+      .then(function (stream) {
+        if (_this3._status === C.STATUS_TERMINATED) {
+          throw new Error('terminated');
+        }
+
+        _this3._localMediaStream = stream;
+
+        if (stream) {
+          stream.getTracks().forEach(function (track) {
+            _this3._connection.addTrack(track, stream);
+          });
+        }
+      }) // Set remote description.
+      .then(function () {
+        if (_this3._late_sdp) {
+          return;
+        }
+
+        var e = {
+          originator: 'remote',
+          type: 'offer',
+          sdp: request.body
+        };
+        logger.debug('emit "sdp"');
+
+        _this3.emit('sdp', e);
+
+        var offer = new RTCSessionDescription({
+          type: 'offer',
+          sdp: e.sdp
+        });
+        _this3._connectionPromiseQueue = _this3._connectionPromiseQueue.then(function () {
+          return _this3._connection.setRemoteDescription(offer);
+        })["catch"](function (error) {
+          request.reply(488);
+
+          _this3._failed('system', null, JsSIP_C.causes.WEBRTC_ERROR);
+
+          logger.warn('emit "peerconnection:setremotedescriptionfailed" [error:%o]', error);
+
+          _this3.emit('peerconnection:setremotedescriptionfailed', error);
+
+          throw new Error('peerconnection.setRemoteDescription() failed');
+        });
+        return _this3._connectionPromiseQueue;
+      }) // Create local description.
+      .then(function () {
+        if (_this3._status === C.STATUS_TERMINATED) {
+          throw new Error('terminated');
+        } // TODO: Is this event already useful?
+
+
+        _this3._connecting(request);
+
+        if (!_this3._late_sdp) {
+          return _this3._createLocalDescription('answer', rtcAnswerConstraints)["catch"](function () {
+            request.reply(500);
+            throw new Error('_createLocalDescription() failed');
+          });
+        } else {
+          return _this3._createLocalDescription('offer', _this3._rtcOfferConstraints)["catch"](function () {
+            request.reply(500);
+            throw new Error('_createLocalDescription() failed');
+          });
+        }
+      }) // Send reply.
+      .then(function (desc) {
+        if (_this3._status === C.STATUS_TERMINATED) {
+          throw new Error('terminated');
+        }
+
+        _this3._handleSessionTimersInIncomingRequest(request, extraHeaders);
+
+        request.reply(200, null, extraHeaders, desc, function () {
+          _this3._status = C.STATUS_WAITING_FOR_ACK;
+
+          _this3._setInvite2xxTimer(request, desc);
+
+          _this3._setACKTimer();
+
+          _this3._accepted('local');
+        }, function () {
+          _this3._failed('system', null, JsSIP_C.causes.CONNECTION_ERROR);
+        });
+      })["catch"](function (error) {
+        if (_this3._status === C.STATUS_TERMINATED) {
+          return;
+        }
+
+        logger.warn(error);
+      });
+    }
+    /**
+     * Terminate the call.
+     */
+
+  }, {
+    key: "terminate",
+    value: function terminate() {
+      var _this4 = this;
+
+      var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
+      logger.debug('terminate()');
+      var cause = options.cause || JsSIP_C.causes.BYE;
+      var extraHeaders = Utils.cloneArray(options.extraHeaders);
+      var body = options.body;
+      var cancel_reason;
+      var status_code = options.status_code;
+      var reason_phrase = options.reason_phrase; // Check Session Status.
+
+      if (this._status === C.STATUS_TERMINATED) {
+        throw new Exceptions.InvalidStateError(this._status);
+      }
+
+      switch (this._status) {
+        // - UAC -
+        case C.STATUS_NULL:
+        case C.STATUS_INVITE_SENT:
+        case C.STATUS_1XX_RECEIVED:
+          logger.debug('canceling session');
+
+          if (status_code && (status_code < 200 || status_code >= 700)) {
+            throw new TypeError("Invalid status_code: ".concat(status_code));
+          } else if (status_code) {
+            reason_phrase = reason_phrase || JsSIP_C.REASON_PHRASE[status_code] || '';
+            cancel_reason = "SIP ;cause=".concat(status_code, " ;text=\"").concat(reason_phrase, "\"");
+          } // Check Session Status.
+
+
+          if (this._status === C.STATUS_NULL || this._status === C.STATUS_INVITE_SENT) {
+            this._is_canceled = true;
+            this._cancel_reason = cancel_reason;
+          } else if (this._status === C.STATUS_1XX_RECEIVED) {
+            this._request.cancel(cancel_reason);
+          }
+
+          this._status = C.STATUS_CANCELED;
+
+          this._failed('local', null, JsSIP_C.causes.CANCELED);
+
+          break;
+        // - UAS -
+
+        case C.STATUS_WAITING_FOR_ANSWER:
+        case C.STATUS_ANSWERED:
+          logger.debug('rejecting session');
+          status_code = status_code || 480;
+
+          if (status_code < 300 || status_code >= 700) {
+            throw new TypeError("Invalid status_code: ".concat(status_code));
+          }
+
+          this._request.reply(status_code, reason_phrase, extraHeaders, body);
+
+          this._failed('local', null, JsSIP_C.causes.REJECTED);
+
+          break;
+
+        case C.STATUS_WAITING_FOR_ACK:
+        case C.STATUS_CONFIRMED:
+          logger.debug('terminating session');
+          reason_phrase = options.reason_phrase || JsSIP_C.REASON_PHRASE[status_code] || '';
+
+          if (status_code && (status_code < 200 || status_code >= 700)) {
+            throw new TypeError("Invalid status_code: ".concat(status_code));
+          } else if (status_code) {
+            extraHeaders.push("Reason: SIP ;cause=".concat(status_code, "; text=\"").concat(reason_phrase, "\""));
+          }
+          /* RFC 3261 section 15 (Terminating a session):
+            *
+            * "...the callee's UA MUST NOT send a BYE on a confirmed dialog
+            * until it has received an ACK for its 2xx response or until the server
+            * transaction times out."
+            */
+
+
+          if (this._status === C.STATUS_WAITING_FOR_ACK && this._direction === 'incoming' && this._request.server_transaction.state !== Transactions.C.STATUS_TERMINATED) {
+            // Save the dialog for later restoration.
+            var dialog = this._dialog; // Send the BYE as soon as the ACK is received...
+
+            this.receiveRequest = function (_ref) {
+              var method = _ref.method;
+
+              if (method === JsSIP_C.ACK) {
+                _this4.sendRequest(JsSIP_C.BYE, {
+                  extraHeaders: extraHeaders,
+                  body: body
+                });
+
+                dialog.terminate();
+              }
+            }; // .., or when the INVITE transaction times out
+
+
+            this._request.server_transaction.on('stateChanged', function () {
+              if (_this4._request.server_transaction.state === Transactions.C.STATUS_TERMINATED) {
+                _this4.sendRequest(JsSIP_C.BYE, {
+                  extraHeaders: extraHeaders,
+                  body: body
+                });
+
+                dialog.terminate();
+              }
+            });
+
+            this._ended('local', null, cause); // Restore the dialog into 'this' in order to be able to send the in-dialog BYE :-).
+
+
+            this._dialog = dialog; // Restore the dialog into 'ua' so the ACK can reach 'this' session.
+
+            this._ua.newDialog(dialog);
+          } else {
+            this.sendRequest(JsSIP_C.BYE, {
+              extraHeaders: extraHeaders,
+              body: body
+            });
+
+            this._ended('local', null, cause);
+          }
+
+      }
+    }
+  }, {
+    key: "sendDTMF",
+    value: function sendDTMF(tones) {
+      var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
+      logger.debug('sendDTMF() | tones: %s', tones);
+      var position = 0;
+      var duration = options.duration || null;
+      var interToneGap = options.interToneGap || null;
+      var transportType = options.transportType || JsSIP_C.DTMF_TRANSPORT.INFO;
+
+      if (tones === undefined) {
+        throw new TypeError('Not enough arguments');
+      } // Check Session Status.
+
+
+      if (this._status !== C.STATUS_CONFIRMED && this._status !== C.STATUS_WAITING_FOR_ACK && this._status !== C.STATUS_1XX_RECEIVED) {
+        throw new Exceptions.InvalidStateError(this._status);
+      } // Check Transport type.
+
+
+      if (transportType !== JsSIP_C.DTMF_TRANSPORT.INFO && transportType !== JsSIP_C.DTMF_TRANSPORT.RFC2833) {
+        throw new TypeError("invalid transportType: ".concat(transportType));
+      } // Convert to string.
+
+
+      if (typeof tones === 'number') {
+        tones = tones.toString();
+      } // Check tones.
+
+
+      if (!tones || typeof tones !== 'string' || !tones.match(/^[0-9A-DR#*,]+$/i)) {
+        throw new TypeError("Invalid tones: ".concat(tones));
+      } // Check duration.
+
+
+      if (duration && !Utils.isDecimal(duration)) {
+        throw new TypeError("Invalid tone duration: ".concat(duration));
+      } else if (!duration) {
+        duration = RTCSession_DTMF.C.DEFAULT_DURATION;
+      } else if (duration < RTCSession_DTMF.C.MIN_DURATION) {
+        logger.debug("\"duration\" value is lower than the minimum allowed, setting it to ".concat(RTCSession_DTMF.C.MIN_DURATION, " milliseconds"));
+        duration = RTCSession_DTMF.C.MIN_DURATION;
+      } else if (duration > RTCSession_DTMF.C.MAX_DURATION) {
+        logger.debug("\"duration\" value is greater than the maximum allowed, setting it to ".concat(RTCSession_DTMF.C.MAX_DURATION, " milliseconds"));
+        duration = RTCSession_DTMF.C.MAX_DURATION;
+      } else {
+        duration = Math.abs(duration);
+      }
+
+      options.duration = duration; // Check interToneGap.
+
+      if (interToneGap && !Utils.isDecimal(interToneGap)) {
+        throw new TypeError("Invalid interToneGap: ".concat(interToneGap));
+      } else if (!interToneGap) {
+        interToneGap = RTCSession_DTMF.C.DEFAULT_INTER_TONE_GAP;
+      } else if (interToneGap < RTCSession_DTMF.C.MIN_INTER_TONE_GAP) {
+        logger.debug("\"interToneGap\" value is lower than the minimum allowed, setting it to ".concat(RTCSession_DTMF.C.MIN_INTER_TONE_GAP, " milliseconds"));
+        interToneGap = RTCSession_DTMF.C.MIN_INTER_TONE_GAP;
+      } else {
+        interToneGap = Math.abs(interToneGap);
+      } // RFC2833. Let RTCDTMFSender enqueue the DTMFs.
+
+
+      if (transportType === JsSIP_C.DTMF_TRANSPORT.RFC2833) {
+        // Send DTMF in current audio RTP stream.
+        var sender = this._getDTMFRTPSender();
+
+        if (sender) {
+          // Add remaining buffered tones.
+          tones = sender.toneBuffer + tones; // Insert tones.
+
+          sender.insertDTMF(tones, duration, interToneGap);
+        }
+
+        return;
+      }
+
+      if (this._tones) {
+        // Tones are already queued, just add to the queue.
+        this._tones += tones;
+        return;
+      }
+
+      this._tones = tones; // Send the first tone.
+
+      _sendDTMF.call(this);
+
+      function _sendDTMF() {
+        var _this5 = this;
+
+        var timeout;
+
+        if (this._status === C.STATUS_TERMINATED || !this._tones || position >= this._tones.length) {
+          // Stop sending DTMF.
+          this._tones = null;
+          return;
+        }
+
+        var tone = this._tones[position];
+        position += 1;
+
+        if (tone === ',') {
+          timeout = 2000;
+        } else {
+          // Send DTMF via SIP INFO messages.
+          var dtmf = new RTCSession_DTMF(this);
+          options.eventHandlers = {
+            onFailed: function onFailed() {
+              _this5._tones = null;
+            }
+          };
+          dtmf.send(tone, options);
+          timeout = duration + interToneGap;
+        } // Set timeout for the next tone.
+
+
+        setTimeout(_sendDTMF.bind(this), timeout);
+      }
+    }
+  }, {
+    key: "sendInfo",
+    value: function sendInfo(contentType, body) {
+      var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
+      logger.debug('sendInfo()'); // Check Session Status.
+
+      if (this._status !== C.STATUS_CONFIRMED && this._status !== C.STATUS_WAITING_FOR_ACK && this._status !== C.STATUS_1XX_RECEIVED) {
+        throw new Exceptions.InvalidStateError(this._status);
+      }
+
+      var info = new RTCSession_Info(this);
+      info.send(contentType, body, options);
+    }
+    /**
+     * Mute
+     */
+
+  }, {
+    key: "mute",
+    value: function mute() {
+      var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {
+        audio: true,
+        video: false
+      };
+      logger.debug('mute()');
+      var audioMuted = false,
+          videoMuted = false;
+
+      if (this._audioMuted === false && options.audio) {
+        audioMuted = true;
+        this._audioMuted = true;
+
+        this._toggleMuteAudio(true);
+      }
+
+      if (this._videoMuted === false && options.video) {
+        videoMuted = true;
+        this._videoMuted = true;
+
+        this._toggleMuteVideo(true);
+      }
+
+      if (audioMuted === true || videoMuted === true) {
+        this._onmute({
+          audio: audioMuted,
+          video: videoMuted
+        });
+      }
+    }
+    /**
+     * Unmute
+     */
+
+  }, {
+    key: "unmute",
+    value: function unmute() {
+      var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {
+        audio: true,
+        video: true
+      };
+      logger.debug('unmute()');
+      var audioUnMuted = false,
+          videoUnMuted = false;
+
+      if (this._audioMuted === true && options.audio) {
+        audioUnMuted = true;
+        this._audioMuted = false;
+
+        if (this._localHold === false) {
+          this._toggleMuteAudio(false);
+        }
+      }
+
+      if (this._videoMuted === true && options.video) {
+        videoUnMuted = true;
+        this._videoMuted = false;
+
+        if (this._localHold === false) {
+          this._toggleMuteVideo(false);
+        }
+      }
+
+      if (audioUnMuted === true || videoUnMuted === true) {
+        this._onunmute({
+          audio: audioUnMuted,
+          video: videoUnMuted
+        });
+      }
+    }
+    /**
+     * Hold
+     */
+
+  }, {
+    key: "hold",
+    value: function hold() {
+      var _this6 = this;
+
+      var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
+      var done = arguments.length > 1 ? arguments[1] : undefined;
+      logger.debug('hold()');
+
+      if (this._status !== C.STATUS_WAITING_FOR_ACK && this._status !== C.STATUS_CONFIRMED) {
+        return false;
+      }
+
+      if (this._localHold === true) {
+        return false;
+      }
+
+      if (!this._isReadyToReOffer()) {
+        return false;
+      }
+
+      this._localHold = true;
+
+      this._onhold('local');
+
+      var eventHandlers = {
+        succeeded: function succeeded() {
+          if (done) {
+            done();
+          }
+        },
+        failed: function failed() {
+          _this6.terminate({
+            cause: JsSIP_C.causes.WEBRTC_ERROR,
+            status_code: 500,
+            reason_phrase: 'Hold Failed'
+          });
+        }
+      };
+
+      if (options.useUpdate) {
+        this._sendUpdate({
+          sdpOffer: true,
+          eventHandlers: eventHandlers,
+          extraHeaders: options.extraHeaders
+        });
+      } else {
+        this._sendReinvite({
+          eventHandlers: eventHandlers,
+          extraHeaders: options.extraHeaders
+        });
+      }
+
+      return true;
+    }
+  }, {
+    key: "unhold",
+    value: function unhold() {
+      var _this7 = this;
+
+      var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
+      var done = arguments.length > 1 ? arguments[1] : undefined;
+      logger.debug('unhold()');
+
+      if (this._status !== C.STATUS_WAITING_FOR_ACK && this._status !== C.STATUS_CONFIRMED) {
+        return false;
+      }
+
+      if (this._localHold === false) {
+        return false;
+      }
+
+      if (!this._isReadyToReOffer()) {
+        return false;
+      }
+
+      this._localHold = false;
+
+      this._onunhold('local');
+
+      var eventHandlers = {
+        succeeded: function succeeded() {
+          if (done) {
+            done();
+          }
+        },
+        failed: function failed() {
+          _this7.terminate({
+            cause: JsSIP_C.causes.WEBRTC_ERROR,
+            status_code: 500,
+            reason_phrase: 'Unhold Failed'
+          });
+        }
+      };
+
+      if (options.useUpdate) {
+        this._sendUpdate({
+          sdpOffer: true,
+          eventHandlers: eventHandlers,
+          extraHeaders: options.extraHeaders
+        });
+      } else {
+        this._sendReinvite({
+          eventHandlers: eventHandlers,
+          extraHeaders: options.extraHeaders
+        });
+      }
+
+      return true;
+    }
+  }, {
+    key: "renegotiate",
+    value: function renegotiate() {
+      var _this8 = this;
+
+      var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
+      var done = arguments.length > 1 ? arguments[1] : undefined;
+      logger.debug('renegotiate()');
+      var rtcOfferConstraints = options.rtcOfferConstraints || null;
+
+      if (this._status !== C.STATUS_WAITING_FOR_ACK && this._status !== C.STATUS_CONFIRMED) {
+        return false;
+      }
+
+      if (!this._isReadyToReOffer()) {
+        return false;
+      }
+
+      var eventHandlers = {
+        succeeded: function succeeded() {
+          if (done) {
+            done();
+          }
+        },
+        failed: function failed() {
+          _this8.terminate({
+            cause: JsSIP_C.causes.WEBRTC_ERROR,
+            status_code: 500,
+            reason_phrase: 'Media Renegotiation Failed'
+          });
+        }
+      };
+
+      this._setLocalMediaStatus();
+
+      if (options.useUpdate) {
+        this._sendUpdate({
+          sdpOffer: true,
+          eventHandlers: eventHandlers,
+          rtcOfferConstraints: rtcOfferConstraints,
+          extraHeaders: options.extraHeaders
+        });
+      } else {
+        this._sendReinvite({
+          eventHandlers: eventHandlers,
+          rtcOfferConstraints: rtcOfferConstraints,
+          extraHeaders: options.extraHeaders
+        });
+      }
+
+      return true;
+    }
+    /**
+     * Refer
+     */
+
+  }, {
+    key: "refer",
+    value: function refer(target, options) {
+      var _this9 = this;
+
+      logger.debug('refer()');
+      var originalTarget = target;
+
+      if (this._status !== C.STATUS_WAITING_FOR_ACK && this._status !== C.STATUS_CONFIRMED) {
+        return false;
+      } // Check target validity.
+
+
+      target = this._ua.normalizeTarget(target);
+
+      if (!target) {
+        throw new TypeError("Invalid target: ".concat(originalTarget));
+      }
+
+      var referSubscriber = new RTCSession_ReferSubscriber(this);
+      referSubscriber.sendRefer(target, options); // Store in the map.
+
+      var id = referSubscriber.id;
+      this._referSubscribers[id] = referSubscriber; // Listen for ending events so we can remove it from the map.
+
+      referSubscriber.on('requestFailed', function () {
+        delete _this9._referSubscribers[id];
+      });
+      referSubscriber.on('accepted', function () {
+        delete _this9._referSubscribers[id];
+      });
+      referSubscriber.on('failed', function () {
+        delete _this9._referSubscribers[id];
+      });
+      return referSubscriber;
+    }
+    /**
+     * Send a generic in-dialog Request
+     */
+
+  }, {
+    key: "sendRequest",
+    value: function sendRequest(method, options) {
+      logger.debug('sendRequest()');
+      return this._dialog.sendRequest(method, options);
+    }
+    /**
+     * In dialog Request Reception
+     */
+
+  }, {
+    key: "receiveRequest",
+    value: function receiveRequest(request) {
+      var _this10 = this;
+
+      logger.debug('receiveRequest()');
+
+      if (request.method === JsSIP_C.CANCEL) {
+        /* RFC3261 15 States that a UAS may have accepted an invitation while a CANCEL
+        * was in progress and that the UAC MAY continue with the session established by
+        * any 2xx response, or MAY terminate with BYE. JsSIP does continue with the
+        * established session. So the CANCEL is processed only if the session is not yet
+        * established.
+        */
+
+        /*
+        * Terminate the whole session in case the user didn't accept (or yet send the answer)
+        * nor reject the request opening the session.
+        */
+        if (this._status === C.STATUS_WAITING_FOR_ANSWER || this._status === C.STATUS_ANSWERED) {
+          this._status = C.STATUS_CANCELED;
+
+          this._request.reply(487);
+
+          this._failed('remote', request, JsSIP_C.causes.CANCELED);
+        }
+      } else {
+        // Requests arriving here are in-dialog requests.
+        switch (request.method) {
+          case JsSIP_C.ACK:
+            if (this._status !== C.STATUS_WAITING_FOR_ACK) {
+              return;
+            } // Update signaling status.
+
+
+            this._status = C.STATUS_CONFIRMED;
+            clearTimeout(this._timers.ackTimer);
+            clearTimeout(this._timers.invite2xxTimer);
+
+            if (this._late_sdp) {
+              if (!request.body) {
+                this.terminate({
+                  cause: JsSIP_C.causes.MISSING_SDP,
+                  status_code: 400
+                });
+                break;
+              }
+
+              var e = {
+                originator: 'remote',
+                type: 'answer',
+                sdp: request.body
+              };
+              logger.debug('emit "sdp"');
+              this.emit('sdp', e);
+              var answer = new RTCSessionDescription({
+                type: 'answer',
+                sdp: e.sdp
+              });
+              this._connectionPromiseQueue = this._connectionPromiseQueue.then(function () {
+                return _this10._connection.setRemoteDescription(answer);
+              }).then(function () {
+                if (!_this10._is_confirmed) {
+                  _this10._confirmed('remote', request);
+                }
+              })["catch"](function (error) {
+                _this10.terminate({
+                  cause: JsSIP_C.causes.BAD_MEDIA_DESCRIPTION,
+                  status_code: 488
+                });
+
+                logger.warn('emit "peerconnection:setremotedescriptionfailed" [error:%o]', error);
+
+                _this10.emit('peerconnection:setremotedescriptionfailed', error);
+              });
+            } else if (!this._is_confirmed) {
+              this._confirmed('remote', request);
+            }
+
+            break;
+
+          case JsSIP_C.BYE:
+            if (this._status === C.STATUS_CONFIRMED || this._status === C.STATUS_WAITING_FOR_ACK) {
+              request.reply(200);
+
+              this._ended('remote', request, JsSIP_C.causes.BYE);
+            } else if (this._status === C.STATUS_INVITE_RECEIVED || this._status === C.STATUS_WAITING_FOR_ANSWER) {
+              request.reply(200);
+
+              this._request.reply(487, 'BYE Received');
+
+              this._ended('remote', request, JsSIP_C.causes.BYE);
+            } else {
+              request.reply(403, 'Wrong Status');
+            }
+
+            break;
+
+          case JsSIP_C.INVITE:
+            if (this._status === C.STATUS_CONFIRMED) {
+              if (request.hasHeader('replaces')) {
+                this._receiveReplaces(request);
+              } else {
+                this._receiveReinvite(request);
+              }
+            } else {
+              request.reply(403, 'Wrong Status');
+            }
+
+            break;
+
+          case JsSIP_C.INFO:
+            if (this._status === C.STATUS_1XX_RECEIVED || this._status === C.STATUS_WAITING_FOR_ANSWER || this._status === C.STATUS_ANSWERED || this._status === C.STATUS_WAITING_FOR_ACK || this._status === C.STATUS_CONFIRMED) {
+              var contentType = request.hasHeader('Content-Type') ? request.getHeader('Content-Type').toLowerCase() : undefined;
+
+              if (contentType && contentType.match(/^application\/dtmf-relay/i)) {
+                new RTCSession_DTMF(this).init_incoming(request);
+              } else if (contentType !== undefined) {
+                new RTCSession_Info(this).init_incoming(request);
+              } else {
+                request.reply(415);
+              }
+            } else {
+              request.reply(403, 'Wrong Status');
+            }
+
+            break;
+
+          case JsSIP_C.UPDATE:
+            if (this._status === C.STATUS_CONFIRMED) {
+              this._receiveUpdate(request);
+            } else {
+              request.reply(403, 'Wrong Status');
+            }
+
+            break;
+
+          case JsSIP_C.REFER:
+            if (this._status === C.STATUS_CONFIRMED) {
+              this._receiveRefer(request);
+            } else {
+              request.reply(403, 'Wrong Status');
+            }
+
+            break;
+
+          case JsSIP_C.NOTIFY:
+            if (this._status === C.STATUS_CONFIRMED) {
+              this._receiveNotify(request);
+            } else {
+              request.reply(403, 'Wrong Status');
+            }
+
+            break;
+
+          default:
+            request.reply(501);
+        }
+      }
+    }
+    /**
+     * Session Callbacks
+     */
+
+  }, {
+    key: "onTransportError",
+    value: function onTransportError() {
+      logger.warn('onTransportError()');
+
+      if (this._status !== C.STATUS_TERMINATED) {
+        this.terminate({
+          status_code: 500,
+          reason_phrase: JsSIP_C.causes.CONNECTION_ERROR,
+          cause: JsSIP_C.causes.CONNECTION_ERROR
+        });
+      }
+    }
+  }, {
+    key: "onRequestTimeout",
+    value: function onRequestTimeout() {
+      logger.warn('onRequestTimeout()');
+
+      if (this._status !== C.STATUS_TERMINATED) {
+        this.terminate({
+          status_code: 408,
+          reason_phrase: JsSIP_C.causes.REQUEST_TIMEOUT,
+          cause: JsSIP_C.causes.REQUEST_TIMEOUT
+        });
+      }
+    }
+  }, {
+    key: "onDialogError",
+    value: function onDialogError() {
+      logger.warn('onDialogError()');
+
+      if (this._status !== C.STATUS_TERMINATED) {
+        this.terminate({
+          status_code: 500,
+          reason_phrase: JsSIP_C.causes.DIALOG_ERROR,
+          cause: JsSIP_C.causes.DIALOG_ERROR
+        });
+      }
+    } // Called from DTMF handler.
+
+  }, {
+    key: "newDTMF",
+    value: function newDTMF(data) {
+      logger.debug('newDTMF()');
+      this.emit('newDTMF', data);
+    } // Called from Info handler.
+
+  }, {
+    key: "newInfo",
+    value: function newInfo(data) {
+      logger.debug('newInfo()');
+      this.emit('newInfo', data);
+    }
+    /**
+     * Check if RTCSession is ready for an outgoing re-INVITE or UPDATE with SDP.
+     */
+
+  }, {
+    key: "_isReadyToReOffer",
+    value: function _isReadyToReOffer() {
+      if (!this._rtcReady) {
+        logger.debug('_isReadyToReOffer() | internal WebRTC status not ready');
+        return false;
+      } // No established yet.
+
+
+      if (!this._dialog) {
+        logger.debug('_isReadyToReOffer() | session not established yet');
+        return false;
+      } // Another INVITE transaction is in progress.
+
+
+      if (this._dialog.uac_pending_reply === true || this._dialog.uas_pending_reply === true) {
+        logger.debug('_isReadyToReOffer() | there is another INVITE/UPDATE transaction in progress');
+        return false;
+      }
+
+      return true;
+    }
+  }, {
+    key: "_close",
+    value: function _close() {
+      logger.debug('close()'); // Close local MediaStream if it was not given by the user.
+
+      if (this._localMediaStream && this._localMediaStreamLocallyGenerated) {
+        logger.debug('close() | closing local MediaStream');
+        Utils.closeMediaStream(this._localMediaStream);
+      }
+
+      if (this._status === C.STATUS_TERMINATED) {
+        return;
+      }
+
+      this._status = C.STATUS_TERMINATED; // Terminate RTC.
+
+      if (this._connection) {
+        try {
+          this._connection.close();
+        } catch (error) {
+          logger.warn('close() | error closing the RTCPeerConnection: %o', error);
+        }
+      } // Terminate signaling.
+      // Clear SIP timers.
+
+
+      for (var timer in this._timers) {
+        if (Object.prototype.hasOwnProperty.call(this._timers, timer)) {
+          clearTimeout(this._timers[timer]);
+        }
+      } // Clear Session Timers.
+
+
+      clearTimeout(this._sessionTimers.timer); // Terminate confirmed dialog.
+
+      if (this._dialog) {
+        this._dialog.terminate();
+
+        delete this._dialog;
+      } // Terminate early dialogs.
+
+
+      for (var dialog in this._earlyDialogs) {
+        if (Object.prototype.hasOwnProperty.call(this._earlyDialogs, dialog)) {
+          this._earlyDialogs[dialog].terminate();
+
+          delete this._earlyDialogs[dialog];
+        }
+      } // Terminate REFER subscribers.
+
+
+      for (var subscriber in this._referSubscribers) {
+        if (Object.prototype.hasOwnProperty.call(this._referSubscribers, subscriber)) {
+          delete this._referSubscribers[subscriber];
+        }
+      }
+
+      this._ua.destroyRTCSession(this);
+    }
+    /**
+     * Private API.
+     */
+
+    /**
+     * RFC3261 13.3.1.4
+     * Response retransmissions cannot be accomplished by transaction layer
+     *  since it is destroyed when receiving the first 2xx answer
+     */
+
+  }, {
+    key: "_setInvite2xxTimer",
+    value: function _setInvite2xxTimer(request, body) {
+      var timeout = Timers.T1;
+
+      function invite2xxRetransmission() {
+        if (this._status !== C.STATUS_WAITING_FOR_ACK) {
+          return;
+        }
+
+        request.reply(200, null, ["Contact: ".concat(this._contact)], body);
+
+        if (timeout < Timers.T2) {
+          timeout = timeout * 2;
+
+          if (timeout > Timers.T2) {
+            timeout = Timers.T2;
+          }
+        }
+
+        this._timers.invite2xxTimer = setTimeout(invite2xxRetransmission.bind(this), timeout);
+      }
+
+      this._timers.invite2xxTimer = setTimeout(invite2xxRetransmission.bind(this), timeout);
+    }
+    /**
+     * RFC3261 14.2
+     * If a UAS generates a 2xx response and never receives an ACK,
+     *  it SHOULD generate a BYE to terminate the dialog.
+     */
+
+  }, {
+    key: "_setACKTimer",
+    value: function _setACKTimer() {
+      var _this11 = this;
+
+      this._timers.ackTimer = setTimeout(function () {
+        if (_this11._status === C.STATUS_WAITING_FOR_ACK) {
+          logger.debug('no ACK received, terminating the session');
+          clearTimeout(_this11._timers.invite2xxTimer);
+
+          _this11.sendRequest(JsSIP_C.BYE);
+
+          _this11._ended('remote', null, JsSIP_C.causes.NO_ACK);
+        }
+      }, Timers.TIMER_H);
+    }
+  }, {
+    key: "_createRTCConnection",
+    value: function _createRTCConnection(pcConfig, rtcConstraints) {
+      var _this12 = this;
+
+      this._connection = new RTCPeerConnection(pcConfig, rtcConstraints);
+
+      this._connection.addEventListener('iceconnectionstatechange', function () {
+        var state = _this12._connection.iceConnectionState; // TODO: Do more with different states.
+
+        if (state === 'failed') {
+          _this12.terminate({
+            cause: JsSIP_C.causes.RTP_TIMEOUT,
+            status_code: 408,
+            reason_phrase: JsSIP_C.causes.RTP_TIMEOUT
+          });
+        }
+      });
+
+      logger.debug('emit "peerconnection"');
+      this.emit('peerconnection', {
+        peerconnection: this._connection
+      });
+    }
+  }, {
+    key: "_createLocalDescription",
+    value: function _createLocalDescription(type, constraints) {
+      var _this13 = this;
+
+      logger.debug('createLocalDescription()');
+      if (type !== 'offer' && type !== 'answer') throw new Error("createLocalDescription() | invalid type \"".concat(type, "\""));
+      var connection = this._connection;
+      this._rtcReady = false;
+      return Promise.resolve() // Create Offer or Answer.
+      .then(function () {
+        if (type === 'offer') {
+          return connection.createOffer(constraints)["catch"](function (error) {
+            logger.warn('emit "peerconnection:createofferfailed" [error:%o]', error);
+
+            _this13.emit('peerconnection:createofferfailed', error);
+
+            return Promise.reject(error);
+          });
+        } else {
+          return connection.createAnswer(constraints)["catch"](function (error) {
+            logger.warn('emit "peerconnection:createanswerfailed" [error:%o]', error);
+
+            _this13.emit('peerconnection:createanswerfailed', error);
+
+            return Promise.reject(error);
+          });
+        }
+      }) // Set local description.
+      .then(function (desc) {
+        return connection.setLocalDescription(desc)["catch"](function (error) {
+          _this13._rtcReady = true;
+          logger.warn('emit "peerconnection:setlocaldescriptionfailed" [error:%o]', error);
+
+          _this13.emit('peerconnection:setlocaldescriptionfailed', error);
+
+          return Promise.reject(error);
+        });
+      }).then(function () {
+        // Resolve right away if 'pc.iceGatheringState' is 'complete'.
+
+        /**
+         * Resolve right away if:
+         * - 'connection.iceGatheringState' is 'complete' and no 'iceRestart' constraint is set.
+         * - 'connection.iceGatheringState' is 'gathering' and 'iceReady' is true.
+         */
+        var iceRestart = constraints && constraints.iceRestart;
+
+        if (connection.iceGatheringState === 'complete' && !iceRestart || connection.iceGatheringState === 'gathering' && _this13._iceReady) {
+          _this13._rtcReady = true;
+          var e = {
+            originator: 'local',
+            type: type,
+            sdp: connection.localDescription.sdp
+          };
+          logger.debug('emit "sdp"');
+
+          _this13.emit('sdp', e);
+
+          return Promise.resolve(e.sdp);
+        } // Add 'pc.onicencandidate' event handler to resolve on last candidate.
+
+
+        return new Promise(function (resolve) {
+          var finished = false;
+          var iceCandidateListener;
+          var iceGatheringStateListener;
+          _this13._iceReady = false;
+
+          var ready = function ready() {
+            connection.removeEventListener('icecandidate', iceCandidateListener);
+            connection.removeEventListener('icegatheringstatechange', iceGatheringStateListener);
+            finished = true;
+            _this13._rtcReady = true; // connection.iceGatheringState will still indicate 'gathering' and thus be blocking.
+
+            _this13._iceReady = true;
+            var e = {
+              originator: 'local',
+              type: type,
+              sdp: connection.localDescription.sdp
+            };
+            logger.debug('emit "sdp"');
+
+            _this13.emit('sdp', e);
+
+            resolve(e.sdp);
+          };
+
+          connection.addEventListener('icecandidate', iceCandidateListener = function iceCandidateListener(event) {
+            var candidate = event.candidate;
+
+            if (candidate) {
+              _this13.emit('icecandidate', {
+                candidate: candidate,
+                ready: ready
+              });
+            } else if (!finished) {
+              ready();
+            }
+          });
+          connection.addEventListener('icegatheringstatechange', iceGatheringStateListener = function iceGatheringStateListener() {
+            if (connection.iceGatheringState === 'complete' && !finished) {
+              ready();
+            }
+          });
+        });
+      });
+    }
+    /**
+     * Dialog Management
+     */
+
+  }, {
+    key: "_createDialog",
+    value: function _createDialog(message, type, early) {
+      var local_tag = type === 'UAS' ? message.to_tag : message.from_tag;
+      var remote_tag = type === 'UAS' ? message.from_tag : message.to_tag;
+      var id = message.call_id + local_tag + remote_tag;
+      var early_dialog = this._earlyDialogs[id]; // Early Dialog.
+
+      if (early) {
+        if (early_dialog) {
+          return true;
+        } else {
+          early_dialog = new Dialog(this, message, type, Dialog.C.STATUS_EARLY); // Dialog has been successfully created.
+
+          if (early_dialog.error) {
+            logger.debug(early_dialog.error);
+
+            this._failed('remote', message, JsSIP_C.causes.INTERNAL_ERROR);
+
+            return false;
+          } else {
+            this._earlyDialogs[id] = early_dialog;
+            return true;
+          }
+        }
+      } // Confirmed Dialog.
+      else {
+          this._from_tag = message.from_tag;
+          this._to_tag = message.to_tag; // In case the dialog is in _early_ state, update it.
+
+          if (early_dialog) {
+            early_dialog.update(message, type);
+            this._dialog = early_dialog;
+            delete this._earlyDialogs[id];
+            return true;
+          } // Otherwise, create a _confirmed_ dialog.
+
+
+          var dialog = new Dialog(this, message, type);
+
+          if (dialog.error) {
+            logger.debug(dialog.error);
+
+            this._failed('remote', message, JsSIP_C.causes.INTERNAL_ERROR);
+
+            return false;
+          } else {
+            this._dialog = dialog;
+            return true;
+          }
+        }
+    }
+    /**
+     * In dialog INVITE Reception
+     */
+
+  }, {
+    key: "_receiveReinvite",
+    value: function _receiveReinvite(request) {
+      var _this14 = this;
+
+      logger.debug('receiveReinvite()');
+      var contentType = request.hasHeader('Content-Type') ? request.getHeader('Content-Type').toLowerCase() : undefined;
+      var data = {
+        request: request,
+        callback: undefined,
+        reject: reject.bind(this)
+      };
+      var rejected = false;
+
+      function reject() {
+        var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
+        rejected = true;
+        var status_code = options.status_code || 403;
+        var reason_phrase = options.reason_phrase || '';
+        var extraHeaders = Utils.cloneArray(options.extraHeaders);
+
+        if (this._status !== C.STATUS_CONFIRMED) {
+          return false;
+        }
+
+        if (status_code < 300 || status_code >= 700) {
+          throw new TypeError("Invalid status_code: ".concat(status_code));
+        }
+
+        request.reply(status_code, reason_phrase, extraHeaders);
+      } // Emit 'reinvite'.
+
+
+      this.emit('reinvite', data);
+
+      if (rejected) {
+        return;
+      }
+
+      this._late_sdp = false; // Request without SDP.
+
+      if (!request.body) {
+        this._late_sdp = true;
+
+        if (this._remoteHold) {
+          this._remoteHold = false;
+
+          this._onunhold('remote');
+        }
+
+        this._connectionPromiseQueue = this._connectionPromiseQueue.then(function () {
+          return _this14._createLocalDescription('offer', _this14._rtcOfferConstraints);
+        }).then(function (sdp) {
+          sendAnswer.call(_this14, sdp);
+        })["catch"](function () {
+          request.reply(500);
+        });
+        return;
+      } // Request with SDP.
+
+
+      if (contentType !== 'application/sdp') {
+        logger.debug('invalid Content-Type');
+        request.reply(415);
+        return;
+      }
+
+      this._processInDialogSdpOffer(request) // Send answer.
+      .then(function (desc) {
+        if (_this14._status === C.STATUS_TERMINATED) {
+          return;
+        }
+
+        sendAnswer.call(_this14, desc);
+      })["catch"](function (error) {
+        logger.warn(error);
+      });
+
+      function sendAnswer(desc) {
+        var _this15 = this;
+
+        var extraHeaders = ["Contact: ".concat(this._contact)];
+
+        this._handleSessionTimersInIncomingRequest(request, extraHeaders);
+
+        if (this._late_sdp) {
+          desc = this._mangleOffer(desc);
+        }
+
+        request.reply(200, null, extraHeaders, desc, function () {
+          _this15._status = C.STATUS_WAITING_FOR_ACK;
+
+          _this15._setInvite2xxTimer(request, desc);
+
+          _this15._setACKTimer();
+        }); // If callback is given execute it.
+
+        if (typeof data.callback === 'function') {
+          data.callback();
+        }
+      }
+    }
+    /**
+     * In dialog UPDATE Reception
+     */
+
+  }, {
+    key: "_receiveUpdate",
+    value: function _receiveUpdate(request) {
+      var _this16 = this;
+
+      logger.debug('receiveUpdate()');
+      var contentType = request.hasHeader('Content-Type') ? request.getHeader('Content-Type').toLowerCase() : undefined;
+      var data = {
+        request: request,
+        callback: undefined,
+        reject: reject.bind(this)
+      };
+      var rejected = false;
+
+      function reject() {
+        var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
+        rejected = true;
+        var status_code = options.status_code || 403;
+        var reason_phrase = options.reason_phrase || '';
+        var extraHeaders = Utils.cloneArray(options.extraHeaders);
+
+        if (this._status !== C.STATUS_CONFIRMED) {
+          return false;
+        }
+
+        if (status_code < 300 || status_code >= 700) {
+          throw new TypeError("Invalid status_code: ".concat(status_code));
+        }
+
+        request.reply(status_code, reason_phrase, extraHeaders);
+      } // Emit 'update'.
+
+
+      this.emit('update', data);
+
+      if (rejected) {
+        return;
+      }
+
+      if (!request.body) {
+        sendAnswer.call(this, null);
+        return;
+      }
+
+      if (contentType !== 'application/sdp') {
+        logger.debug('invalid Content-Type');
+        request.reply(415);
+        return;
+      }
+
+      this._processInDialogSdpOffer(request) // Send answer.
+      .then(function (desc) {
+        if (_this16._status === C.STATUS_TERMINATED) {
+          return;
+        }
+
+        sendAnswer.call(_this16, desc);
+      })["catch"](function (error) {
+        logger.warn(error);
+      });
+
+      function sendAnswer(desc) {
+        var extraHeaders = ["Contact: ".concat(this._contact)];
+
+        this._handleSessionTimersInIncomingRequest(request, extraHeaders);
+
+        request.reply(200, null, extraHeaders, desc); // If callback is given execute it.
+
+        if (typeof data.callback === 'function') {
+          data.callback();
+        }
+      }
+    }
+  }, {
+    key: "_processInDialogSdpOffer",
+    value: function _processInDialogSdpOffer(request) {
+      var _this17 = this;
+
+      logger.debug('_processInDialogSdpOffer()');
+      var sdp = request.parseSDP();
+      var hold = false;
+
+      var _iterator4 = _createForOfIteratorHelper(sdp.media),
+          _step4;
+
+      try {
+        for (_iterator4.s(); !(_step4 = _iterator4.n()).done;) {
+          var m = _step4.value;
+
+          if (holdMediaTypes.indexOf(m.type) === -1) {
+            continue;
+          }
+
+          var direction = m.direction || sdp.direction || 'sendrecv';
+
+          if (direction === 'sendonly' || direction === 'inactive') {
+            hold = true;
+          } // If at least one of the streams is active don't emit 'hold'.
+          else {
+              hold = false;
+              break;
+            }
+        }
+      } catch (err) {
+        _iterator4.e(err);
+      } finally {
+        _iterator4.f();
+      }
+
+      var e = {
+        originator: 'remote',
+        type: 'offer',
+        sdp: request.body
+      };
+      logger.debug('emit "sdp"');
+      this.emit('sdp', e);
+      var offer = new RTCSessionDescription({
+        type: 'offer',
+        sdp: e.sdp
+      });
+      this._connectionPromiseQueue = this._connectionPromiseQueue // Set remote description.
+      .then(function () {
+        if (_this17._status === C.STATUS_TERMINATED) {
+          throw new Error('terminated');
+        }
+
+        return _this17._connection.setRemoteDescription(offer)["catch"](function (error) {
+          request.reply(488);
+          logger.warn('emit "peerconnection:setremotedescriptionfailed" [error:%o]', error);
+
+          _this17.emit('peerconnection:setremotedescriptionfailed', error);
+
+          throw error;
+        });
+      }).then(function () {
+        if (_this17._status === C.STATUS_TERMINATED) {
+          throw new Error('terminated');
+        }
+
+        if (_this17._remoteHold === true && hold === false) {
+          _this17._remoteHold = false;
+
+          _this17._onunhold('remote');
+        } else if (_this17._remoteHold === false && hold === true) {
+          _this17._remoteHold = true;
+
+          _this17._onhold('remote');
+        }
+      }) // Create local description.
+      .then(function () {
+        if (_this17._status === C.STATUS_TERMINATED) {
+          throw new Error('terminated');
+        }
+
+        return _this17._createLocalDescription('answer', _this17._rtcAnswerConstraints)["catch"](function (error) {
+          request.reply(500);
+          logger.warn('emit "peerconnection:createtelocaldescriptionfailed" [error:%o]', error);
+          throw error;
+        });
+      })["catch"](function (error) {
+        logger.warn('_processInDialogSdpOffer() failed [error: %o]', error);
+      });
+      return this._connectionPromiseQueue;
+    }
+    /**
+     * In dialog Refer Reception
+     */
+
+  }, {
+    key: "_receiveRefer",
+    value: function _receiveRefer(request) {
+      var _this18 = this;
+
+      logger.debug('receiveRefer()');
+
+      if (!request.refer_to) {
+        logger.debug('no Refer-To header field present in REFER');
+        request.reply(400);
+        return;
+      }
+
+      if (request.refer_to.uri.scheme !== JsSIP_C.SIP) {
+        logger.debug('Refer-To header field points to a non-SIP URI scheme');
+        request.reply(416);
+        return;
+      } // Reply before the transaction timer expires.
+
+
+      request.reply(202);
+      var notifier = new RTCSession_ReferNotifier(this, request.cseq);
+      logger.debug('emit "refer"'); // Emit 'refer'.
+
+      this.emit('refer', {
+        request: request,
+        accept: function accept(initCallback, options) {
+          _accept.call(_this18, initCallback, options);
+        },
+        reject: function reject() {
+          _reject.call(_this18);
+        }
+      });
+
+      function _accept(initCallback) {
+        var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
+        initCallback = typeof initCallback === 'function' ? initCallback : null;
+
+        if (this._status !== C.STATUS_WAITING_FOR_ACK && this._status !== C.STATUS_CONFIRMED) {
+          return false;
+        }
+
+        var session = new RTCSession(this._ua);
+        session.on('progress', function (_ref2) {
+          var response = _ref2.response;
+          notifier.notify(response.status_code, response.reason_phrase);
+        });
+        session.on('accepted', function (_ref3) {
+          var response = _ref3.response;
+          notifier.notify(response.status_code, response.reason_phrase);
+        });
+        session.on('_failed', function (_ref4) {
+          var message = _ref4.message,
+              cause = _ref4.cause;
+
+          if (message) {
+            notifier.notify(message.status_code, message.reason_phrase);
+          } else {
+            notifier.notify(487, cause);
+          }
+        }); // Consider the Replaces header present in the Refer-To URI.
+
+        if (request.refer_to.uri.hasHeader('replaces')) {
+          var replaces = decodeURIComponent(request.refer_to.uri.getHeader('replaces'));
+          options.extraHeaders = Utils.cloneArray(options.extraHeaders);
+          options.extraHeaders.push("Replaces: ".concat(replaces));
+        }
+
+        session.connect(request.refer_to.uri.toAor(), options, initCallback);
+      }
+
+      function _reject() {
+        notifier.notify(603);
+      }
+    }
+    /**
+     * In dialog Notify Reception
+     */
+
+  }, {
+    key: "_receiveNotify",
+    value: function _receiveNotify(request) {
+      logger.debug('receiveNotify()');
+
+      if (!request.event) {
+        request.reply(400);
+      }
+
+      switch (request.event.event) {
+        case 'refer':
+          {
+            var id;
+            var referSubscriber;
+
+            if (request.event.params && request.event.params.id) {
+              id = request.event.params.id;
+              referSubscriber = this._referSubscribers[id];
+            } else if (Object.keys(this._referSubscribers).length === 1) {
+              referSubscriber = this._referSubscribers[Object.keys(this._referSubscribers)[0]];
+            } else {
+              request.reply(400, 'Missing event id parameter');
+              return;
+            }
+
+            if (!referSubscriber) {
+              request.reply(481, 'Subscription does not exist');
+              return;
+            }
+
+            referSubscriber.receiveNotify(request);
+            request.reply(200);
+            break;
+          }
+
+        default:
+          {
+            request.reply(489);
+          }
+      }
+    }
+    /**
+     * INVITE with Replaces Reception
+     */
+
+  }, {
+    key: "_receiveReplaces",
+    value: function _receiveReplaces(request) {
+      var _this20 = this;
+
+      logger.debug('receiveReplaces()');
+
+      function _accept2(initCallback) {
+        var _this19 = this;
+
+        if (this._status !== C.STATUS_WAITING_FOR_ACK && this._status !== C.STATUS_CONFIRMED) {
+          return false;
+        }
+
+        var session = new RTCSession(this._ua); // Terminate the current session when the new one is confirmed.
+
+        session.on('confirmed', function () {
+          _this19.terminate();
+        });
+        session.init_incoming(request, initCallback);
+      }
+
+      function _reject2() {
+        logger.debug('Replaced INVITE rejected by the user');
+        request.reply(486);
+      } // Emit 'replace'.
+
+
+      this.emit('replaces', {
+        request: request,
+        accept: function accept(initCallback) {
+          _accept2.call(_this20, initCallback);
+        },
+        reject: function reject() {
+          _reject2.call(_this20);
+        }
+      });
+    }
+    /**
+     * Initial Request Sender
+     */
+
+  }, {
+    key: "_sendInitialRequest",
+    value: function _sendInitialRequest(mediaConstraints, rtcOfferConstraints, mediaStream) {
+      var _this21 = this;
+
+      var request_sender = new RequestSender(this._ua, this._request, {
+        onRequestTimeout: function onRequestTimeout() {
+          _this21.onRequestTimeout();
+        },
+        onTransportError: function onTransportError() {
+          _this21.onTransportError();
+        },
+        // Update the request on authentication.
+        onAuthenticated: function onAuthenticated(request) {
+          _this21._request = request;
+        },
+        onReceiveResponse: function onReceiveResponse(response) {
+          _this21._receiveInviteResponse(response);
+        }
+      }); // This Promise is resolved within the next iteration, so the app has now
+      // a chance to set events such as 'peerconnection' and 'connecting'.
+
+      Promise.resolve() // Get a stream if required.
+      .then(function () {
+        // A stream is given, let the app set events such as 'peerconnection' and 'connecting'.
+        if (mediaStream) {
+          return mediaStream;
+        } // Request for user media access.
+        else if (mediaConstraints.audio || mediaConstraints.video) {
+            _this21._localMediaStreamLocallyGenerated = true;
+            return navigator.mediaDevices.getUserMedia(mediaConstraints)["catch"](function (error) {
+              if (_this21._status === C.STATUS_TERMINATED) {
+                throw new Error('terminated');
+              }
+
+              _this21._failed('local', null, JsSIP_C.causes.USER_DENIED_MEDIA_ACCESS);
+
+              logger.warn('emit "getusermediafailed" [error:%o]', error);
+
+              _this21.emit('getusermediafailed', error);
+
+              throw error;
+            });
+          }
+      }).then(function (stream) {
+        if (_this21._status === C.STATUS_TERMINATED) {
+          throw new Error('terminated');
+        }
+
+        _this21._localMediaStream = stream;
+
+        if (stream) {
+          stream.getTracks().forEach(function (track) {
+            _this21._connection.addTrack(track, stream);
+          });
+        } // TODO: should this be triggered here?
+
+
+        _this21._connecting(_this21._request);
+
+        return _this21._createLocalDescription('offer', rtcOfferConstraints)["catch"](function (error) {
+          _this21._failed('local', null, JsSIP_C.causes.WEBRTC_ERROR);
+
+          throw error;
+        });
+      }).then(function (desc) {
+        if (_this21._is_canceled || _this21._status === C.STATUS_TERMINATED) {
+          throw new Error('terminated');
+        }
+
+        _this21._request.body = desc;
+        _this21._status = C.STATUS_INVITE_SENT;
+        logger.debug('emit "sending" [request:%o]', _this21._request); // Emit 'sending' so the app can mangle the body before the request is sent.
+
+        _this21.emit('sending', {
+          request: _this21._request
+        });
+
+        request_sender.send();
+      })["catch"](function (error) {
+        if (_this21._status === C.STATUS_TERMINATED) {
+          return;
+        }
+
+        logger.warn(error);
+      });
+    }
+    /**
+     * Get DTMF RTCRtpSender.
+     */
+
+  }, {
+    key: "_getDTMFRTPSender",
+    value: function _getDTMFRTPSender() {
+      var sender = this._connection.getSenders().find(function (rtpSender) {
+        return rtpSender.track && rtpSender.track.kind === 'audio';
+      });
+
+      if (!(sender && sender.dtmf)) {
+        logger.warn('sendDTMF() | no local audio track to send DTMF with');
+        return;
+      }
+
+      return sender.dtmf;
+    }
+    /**
+     * Reception of Response for Initial INVITE
+     */
+
+  }, {
+    key: "_receiveInviteResponse",
+    value: function _receiveInviteResponse(response) {
+      var _this22 = this;
+
+      logger.debug('receiveInviteResponse()'); // Handle 2XX retransmissions and responses from forked requests.
+
+      if (this._dialog && response.status_code >= 200 && response.status_code <= 299) {
+        /*
+         * If it is a retransmission from the endpoint that established
+         * the dialog, send an ACK
+         */
+        if (this._dialog.id.call_id === response.call_id && this._dialog.id.local_tag === response.from_tag && this._dialog.id.remote_tag === response.to_tag) {
+          this.sendRequest(JsSIP_C.ACK);
+          return;
+        } // If not, send an ACK  and terminate.
+        else {
+            var dialog = new Dialog(this, response, 'UAC');
+
+            if (dialog.error !== undefined) {
+              logger.debug(dialog.error);
+              return;
+            }
+
+            this.sendRequest(JsSIP_C.ACK);
+            this.sendRequest(JsSIP_C.BYE);
+            return;
+          }
+      } // Proceed to cancellation if the user requested.
+
+
+      if (this._is_canceled) {
+        if (response.status_code >= 100 && response.status_code < 200) {
+          this._request.cancel(this._cancel_reason);
+        } else if (response.status_code >= 200 && response.status_code < 299) {
+          this._acceptAndTerminate(response);
+        }
+
+        return;
+      }
+
+      if (this._status !== C.STATUS_INVITE_SENT && this._status !== C.STATUS_1XX_RECEIVED) {
+        return;
+      }
+
+      switch (true) {
+        case /^100$/.test(response.status_code):
+          this._status = C.STATUS_1XX_RECEIVED;
+          break;
+
+        case /^1[0-9]{2}$/.test(response.status_code):
+          {
+            // Do nothing with 1xx responses without To tag.
+            if (!response.to_tag) {
+              logger.debug('1xx response received without to tag');
+              break;
+            } // Create Early Dialog if 1XX comes with contact.
+
+
+            if (response.hasHeader('contact')) {
+              // An error on dialog creation will fire 'failed' event.
+              if (!this._createDialog(response, 'UAC', true)) {
+                break;
+              }
+            }
+
+            this._status = C.STATUS_1XX_RECEIVED;
+
+            if (!response.body) {
+              this._progress('remote', response);
+
+              break;
+            }
+
+            var e = {
+              originator: 'remote',
+              type: 'answer',
+              sdp: response.body
+            };
+            logger.debug('emit "sdp"');
+            this.emit('sdp', e);
+            var answer = new RTCSessionDescription({
+              type: 'answer',
+              sdp: e.sdp
+            });
+            this._connectionPromiseQueue = this._connectionPromiseQueue.then(function () {
+              return _this22._connection.setRemoteDescription(answer);
+            }).then(function () {
+              return _this22._progress('remote', response);
+            })["catch"](function (error) {
+              logger.warn('emit "peerconnection:setremotedescriptionfailed" [error:%o]', error);
+
+              _this22.emit('peerconnection:setremotedescriptionfailed', error);
+            });
+            break;
+          }
+
+        case /^2[0-9]{2}$/.test(response.status_code):
+          {
+            this._status = C.STATUS_CONFIRMED;
+
+            if (!response.body) {
+              this._acceptAndTerminate(response, 400, JsSIP_C.causes.MISSING_SDP);
+
+              this._failed('remote', response, JsSIP_C.causes.BAD_MEDIA_DESCRIPTION);
+
+              break;
+            } // An error on dialog creation will fire 'failed' event.
+
+
+            if (!this._createDialog(response, 'UAC')) {
+              break;
+            }
+
+            var _e = {
+              originator: 'remote',
+              type: 'answer',
+              sdp: response.body
+            };
+            logger.debug('emit "sdp"');
+            this.emit('sdp', _e);
+
+            var _answer = new RTCSessionDescription({
+              type: 'answer',
+              sdp: _e.sdp
+            });
+
+            this._connectionPromiseQueue = this._connectionPromiseQueue.then(function () {
+              // Be ready for 200 with SDP after a 180/183 with SDP.
+              // We created a SDP 'answer' for it, so check the current signaling state.
+              if (_this22._connection.signalingState === 'stable') {
+                return _this22._connection.createOffer(_this22._rtcOfferConstraints).then(function (offer) {
+                  return _this22._connection.setLocalDescription(offer);
+                })["catch"](function (error) {
+                  _this22._acceptAndTerminate(response, 500, error.toString());
+
+                  _this22._failed('local', response, JsSIP_C.causes.WEBRTC_ERROR);
+                });
+              }
+            }).then(function () {
+              _this22._connection.setRemoteDescription(_answer).then(function () {
+                // Handle Session Timers.
+                _this22._handleSessionTimersInIncomingResponse(response);
+
+                _this22._accepted('remote', response);
+
+                _this22.sendRequest(JsSIP_C.ACK);
+
+                _this22._confirmed('local', null);
+              })["catch"](function (error) {
+                _this22._acceptAndTerminate(response, 488, 'Not Acceptable Here');
+
+                _this22._failed('remote', response, JsSIP_C.causes.BAD_MEDIA_DESCRIPTION);
+
+                logger.warn('emit "peerconnection:setremotedescriptionfailed" [error:%o]', error);
+
+                _this22.emit('peerconnection:setremotedescriptionfailed', error);
+              });
+            });
+            break;
+          }
+
+        default:
+          {
+            var cause = Utils.sipErrorCause(response.status_code);
+
+            this._failed('remote', response, cause);
+          }
+      }
+    }
+    /**
+     * Send Re-INVITE
+     */
+
+  }, {
+    key: "_sendReinvite",
+    value: function _sendReinvite() {
+      var _this23 = this;
+
+      var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
+      logger.debug('sendReinvite()');
+      var extraHeaders = Utils.cloneArray(options.extraHeaders);
+      var eventHandlers = Utils.cloneObject(options.eventHandlers);
+      var rtcOfferConstraints = options.rtcOfferConstraints || this._rtcOfferConstraints || null;
+      var succeeded = false;
+      extraHeaders.push("Contact: ".concat(this._contact));
+      extraHeaders.push('Content-Type: application/sdp'); // Session Timers.
+
+      if (this._sessionTimers.running) {
+        extraHeaders.push("Session-Expires: ".concat(this._sessionTimers.currentExpires, ";refresher=").concat(this._sessionTimers.refresher ? 'uac' : 'uas'));
+      }
+
+      this._connectionPromiseQueue = this._connectionPromiseQueue.then(function () {
+        return _this23._createLocalDescription('offer', rtcOfferConstraints);
+      }).then(function (sdp) {
+        sdp = _this23._mangleOffer(sdp);
+        var e = {
+          originator: 'local',
+          type: 'offer',
+          sdp: sdp
+        };
+        logger.debug('emit "sdp"');
+
+        _this23.emit('sdp', e);
+
+        _this23.sendRequest(JsSIP_C.INVITE, {
+          extraHeaders: extraHeaders,
+          body: sdp,
+          eventHandlers: {
+            onSuccessResponse: function onSuccessResponse(response) {
+              onSucceeded.call(_this23, response);
+              succeeded = true;
+            },
+            onErrorResponse: function onErrorResponse(response) {
+              onFailed.call(_this23, response);
+            },
+            onTransportError: function onTransportError() {
+              _this23.onTransportError(); // Do nothing because session ends.
+
+            },
+            onRequestTimeout: function onRequestTimeout() {
+              _this23.onRequestTimeout(); // Do nothing because session ends.
+
+            },
+            onDialogError: function onDialogError() {
+              _this23.onDialogError(); // Do nothing because session ends.
+
+            }
+          }
+        });
+      })["catch"](function () {
+        onFailed();
+      });
+
+      function onSucceeded(response) {
+        var _this24 = this;
+
+        if (this._status === C.STATUS_TERMINATED) {
+          return;
+        }
+
+        this.sendRequest(JsSIP_C.ACK); // If it is a 2XX retransmission exit now.
+
+        if (succeeded) {
+          return;
+        } // Handle Session Timers.
+
+
+        this._handleSessionTimersInIncomingResponse(response); // Must have SDP answer.
+
+
+        if (!response.body) {
+          onFailed.call(this);
+          return;
+        } else if (!response.hasHeader('Content-Type') || response.getHeader('Content-Type').toLowerCase() !== 'application/sdp') {
+          onFailed.call(this);
+          return;
+        }
+
+        var e = {
+          originator: 'remote',
+          type: 'answer',
+          sdp: response.body
+        };
+        logger.debug('emit "sdp"');
+        this.emit('sdp', e);
+        var answer = new RTCSessionDescription({
+          type: 'answer',
+          sdp: e.sdp
+        });
+        this._connectionPromiseQueue = this._connectionPromiseQueue.then(function () {
+          return _this24._connection.setRemoteDescription(answer);
+        }).then(function () {
+          if (eventHandlers.succeeded) {
+            eventHandlers.succeeded(response);
+          }
+        })["catch"](function (error) {
+          onFailed.call(_this24);
+          logger.warn('emit "peerconnection:setremotedescriptionfailed" [error:%o]', error);
+
+          _this24.emit('peerconnection:setremotedescriptionfailed', error);
+        });
+      }
+
+      function onFailed(response) {
+        if (eventHandlers.failed) {
+          eventHandlers.failed(response);
+        }
+      }
+    }
+    /**
+     * Send UPDATE
+     */
+
+  }, {
+    key: "_sendUpdate",
+    value: function _sendUpdate() {
+      var _this25 = this;
+
+      var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
+      logger.debug('sendUpdate()');
+      var extraHeaders = Utils.cloneArray(options.extraHeaders);
+      var eventHandlers = Utils.cloneObject(options.eventHandlers);
+      var rtcOfferConstraints = options.rtcOfferConstraints || this._rtcOfferConstraints || null;
+      var sdpOffer = options.sdpOffer || false;
+      var succeeded = false;
+      extraHeaders.push("Contact: ".concat(this._contact)); // Session Timers.
+
+      if (this._sessionTimers.running) {
+        extraHeaders.push("Session-Expires: ".concat(this._sessionTimers.currentExpires, ";refresher=").concat(this._sessionTimers.refresher ? 'uac' : 'uas'));
+      }
+
+      if (sdpOffer) {
+        extraHeaders.push('Content-Type: application/sdp');
+        this._connectionPromiseQueue = this._connectionPromiseQueue.then(function () {
+          return _this25._createLocalDescription('offer', rtcOfferConstraints);
+        }).then(function (sdp) {
+          sdp = _this25._mangleOffer(sdp);
+          var e = {
+            originator: 'local',
+            type: 'offer',
+            sdp: sdp
+          };
+          logger.debug('emit "sdp"');
+
+          _this25.emit('sdp', e);
+
+          _this25.sendRequest(JsSIP_C.UPDATE, {
+            extraHeaders: extraHeaders,
+            body: sdp,
+            eventHandlers: {
+              onSuccessResponse: function onSuccessResponse(response) {
+                onSucceeded.call(_this25, response);
+                succeeded = true;
+              },
+              onErrorResponse: function onErrorResponse(response) {
+                onFailed.call(_this25, response);
+              },
+              onTransportError: function onTransportError() {
+                _this25.onTransportError(); // Do nothing because session ends.
+
+              },
+              onRequestTimeout: function onRequestTimeout() {
+                _this25.onRequestTimeout(); // Do nothing because session ends.
+
+              },
+              onDialogError: function onDialogError() {
+                _this25.onDialogError(); // Do nothing because session ends.
+
+              }
+            }
+          });
+        })["catch"](function () {
+          onFailed.call(_this25);
+        });
+      } // No SDP.
+      else {
+          this.sendRequest(JsSIP_C.UPDATE, {
+            extraHeaders: extraHeaders,
+            eventHandlers: {
+              onSuccessResponse: function onSuccessResponse(response) {
+                onSucceeded.call(_this25, response);
+              },
+              onErrorResponse: function onErrorResponse(response) {
+                onFailed.call(_this25, response);
+              },
+              onTransportError: function onTransportError() {
+                _this25.onTransportError(); // Do nothing because session ends.
+
+              },
+              onRequestTimeout: function onRequestTimeout() {
+                _this25.onRequestTimeout(); // Do nothing because session ends.
+
+              },
+              onDialogError: function onDialogError() {
+                _this25.onDialogError(); // Do nothing because session ends.
+
+              }
+            }
+          });
+        }
+
+      function onSucceeded(response) {
+        var _this26 = this;
+
+        if (this._status === C.STATUS_TERMINATED) {
+          return;
+        } // If it is a 2XX retransmission exit now.
+
+
+        if (succeeded) {
+          return;
+        } // Handle Session Timers.
+
+
+        this._handleSessionTimersInIncomingResponse(response); // Must have SDP answer.
+
+
+        if (sdpOffer) {
+          if (!response.body) {
+            onFailed.call(this);
+            return;
+          } else if (!response.hasHeader('Content-Type') || response.getHeader('Content-Type').toLowerCase() !== 'application/sdp') {
+            onFailed.call(this);
+            return;
+          }
+
+          var e = {
+            originator: 'remote',
+            type: 'answer',
+            sdp: response.body
+          };
+          logger.debug('emit "sdp"');
+          this.emit('sdp', e);
+          var answer = new RTCSessionDescription({
+            type: 'answer',
+            sdp: e.sdp
+          });
+          this._connectionPromiseQueue = this._connectionPromiseQueue.then(function () {
+            return _this26._connection.setRemoteDescription(answer);
+          }).then(function () {
+            if (eventHandlers.succeeded) {
+              eventHandlers.succeeded(response);
+            }
+          })["catch"](function (error) {
+            onFailed.call(_this26);
+            logger.warn('emit "peerconnection:setremotedescriptionfailed" [error:%o]', error);
+
+            _this26.emit('peerconnection:setremotedescriptionfailed', error);
+          });
+        } // No SDP answer.
+        else if (eventHandlers.succeeded) {
+            eventHandlers.succeeded(response);
+          }
+      }
+
+      function onFailed(response) {
+        if (eventHandlers.failed) {
+          eventHandlers.failed(response);
+        }
+      }
+    }
+  }, {
+    key: "_acceptAndTerminate",
+    value: function _acceptAndTerminate(response, status_code, reason_phrase) {
+      logger.debug('acceptAndTerminate()');
+      var extraHeaders = [];
+
+      if (status_code) {
+        reason_phrase = reason_phrase || JsSIP_C.REASON_PHRASE[status_code] || '';
+        extraHeaders.push("Reason: SIP ;cause=".concat(status_code, "; text=\"").concat(reason_phrase, "\""));
+      } // An error on dialog creation will fire 'failed' event.
+
+
+      if (this._dialog || this._createDialog(response, 'UAC')) {
+        this.sendRequest(JsSIP_C.ACK);
+        this.sendRequest(JsSIP_C.BYE, {
+          extraHeaders: extraHeaders
+        });
+      } // Update session status.
+
+
+      this._status = C.STATUS_TERMINATED;
+    }
+    /**
+     * Correctly set the SDP direction attributes if the call is on local hold
+     */
+
+  }, {
+    key: "_mangleOffer",
+    value: function _mangleOffer(sdp) {
+      if (!this._localHold && !this._remoteHold) {
+        return sdp;
+      }
+
+      sdp = sdp_transform.parse(sdp); // Local hold.
+
+      if (this._localHold && !this._remoteHold) {
+        logger.debug('mangleOffer() | me on hold, mangling offer');
+
+        var _iterator5 = _createForOfIteratorHelper(sdp.media),
+            _step5;
+
+        try {
+          for (_iterator5.s(); !(_step5 = _iterator5.n()).done;) {
+            var m = _step5.value;
+
+            if (holdMediaTypes.indexOf(m.type) === -1) {
+              continue;
+            }
+
+            if (!m.direction) {
+              m.direction = 'sendonly';
+            } else if (m.direction === 'sendrecv') {
+              m.direction = 'sendonly';
+            } else if (m.direction === 'recvonly') {
+              m.direction = 'inactive';
+            }
+          }
+        } catch (err) {
+          _iterator5.e(err);
+        } finally {
+          _iterator5.f();
+        }
+      } // Local and remote hold.
+      else if (this._localHold && this._remoteHold) {
+          logger.debug('mangleOffer() | both on hold, mangling offer');
+
+          var _iterator6 = _createForOfIteratorHelper(sdp.media),
+              _step6;
+
+          try {
+            for (_iterator6.s(); !(_step6 = _iterator6.n()).done;) {
+              var _m = _step6.value;
+
+              if (holdMediaTypes.indexOf(_m.type) === -1) {
+                continue;
+              }
+
+              _m.direction = 'inactive';
+            }
+          } catch (err) {
+            _iterator6.e(err);
+          } finally {
+            _iterator6.f();
+          }
+        } // Remote hold.
+        else if (this._remoteHold) {
+            logger.debug('mangleOffer() | remote on hold, mangling offer');
+
+            var _iterator7 = _createForOfIteratorHelper(sdp.media),
+                _step7;
+
+            try {
+              for (_iterator7.s(); !(_step7 = _iterator7.n()).done;) {
+                var _m2 = _step7.value;
+
+                if (holdMediaTypes.indexOf(_m2.type) === -1) {
+                  continue;
+                }
+
+                if (!_m2.direction) {
+                  _m2.direction = 'recvonly';
+                } else if (_m2.direction === 'sendrecv') {
+                  _m2.direction = 'recvonly';
+                } else if (_m2.direction === 'recvonly') {
+                  _m2.direction = 'inactive';
+                }
+              }
+            } catch (err) {
+              _iterator7.e(err);
+            } finally {
+              _iterator7.f();
+            }
+          }
+
+      return sdp_transform.write(sdp);
+    }
+  }, {
+    key: "_setLocalMediaStatus",
+    value: function _setLocalMediaStatus() {
+      var enableAudio = true,
+          enableVideo = true;
+
+      if (this._localHold || this._remoteHold) {
+        enableAudio = false;
+        enableVideo = false;
+      }
+
+      if (this._audioMuted) {
+        enableAudio = false;
+      }
+
+      if (this._videoMuted) {
+        enableVideo = false;
+      }
+
+      this._toggleMuteAudio(!enableAudio);
+
+      this._toggleMuteVideo(!enableVideo);
+    }
+    /**
+     * Handle SessionTimers for an incoming INVITE or UPDATE.
+     * @param  {IncomingRequest} request
+     * @param  {Array} responseExtraHeaders  Extra headers for the 200 response.
+     */
+
+  }, {
+    key: "_handleSessionTimersInIncomingRequest",
+    value: function _handleSessionTimersInIncomingRequest(request, responseExtraHeaders) {
+      if (!this._sessionTimers.enabled) {
+        return;
+      }
+
+      var session_expires_refresher;
+
+      if (request.session_expires && request.session_expires >= JsSIP_C.MIN_SESSION_EXPIRES) {
+        this._sessionTimers.currentExpires = request.session_expires;
+        session_expires_refresher = request.session_expires_refresher || 'uas';
+      } else {
+        this._sessionTimers.currentExpires = this._sessionTimers.defaultExpires;
+        session_expires_refresher = 'uas';
+      }
+
+      responseExtraHeaders.push("Session-Expires: ".concat(this._sessionTimers.currentExpires, ";refresher=").concat(session_expires_refresher));
+      this._sessionTimers.refresher = session_expires_refresher === 'uas';
+
+      this._runSessionTimer();
+    }
+    /**
+     * Handle SessionTimers for an incoming response to INVITE or UPDATE.
+     * @param  {IncomingResponse} response
+     */
+
+  }, {
+    key: "_handleSessionTimersInIncomingResponse",
+    value: function _handleSessionTimersInIncomingResponse(response) {
+      if (!this._sessionTimers.enabled) {
+        return;
+      }
+
+      var session_expires_refresher;
+
+      if (response.session_expires && response.session_expires >= JsSIP_C.MIN_SESSION_EXPIRES) {
+        this._sessionTimers.currentExpires = response.session_expires;
+        session_expires_refresher = response.session_expires_refresher || 'uac';
+      } else {
+        this._sessionTimers.currentExpires = this._sessionTimers.defaultExpires;
+        session_expires_refresher = 'uac';
+      }
+
+      this._sessionTimers.refresher = session_expires_refresher === 'uac';
+
+      this._runSessionTimer();
+    }
+  }, {
+    key: "_runSessionTimer",
+    value: function _runSessionTimer() {
+      var _this27 = this;
+
+      var expires = this._sessionTimers.currentExpires;
+      this._sessionTimers.running = true;
+      clearTimeout(this._sessionTimers.timer); // I'm the refresher.
+
+      if (this._sessionTimers.refresher) {
+        this._sessionTimers.timer = setTimeout(function () {
+          if (_this27._status === C.STATUS_TERMINATED) {
+            return;
+          }
+
+          if (!_this27._isReadyToReOffer()) {
+            return;
+          }
+
+          logger.debug('runSessionTimer() | sending session refresh request');
+
+          if (_this27._sessionTimers.refreshMethod === JsSIP_C.UPDATE) {
+            _this27._sendUpdate();
+          } else {
+            _this27._sendReinvite();
+          }
+        }, expires * 500); // Half the given interval (as the RFC states).
+      } // I'm not the refresher.
+      else {
+          this._sessionTimers.timer = setTimeout(function () {
+            if (_this27._status === C.STATUS_TERMINATED) {
+              return;
+            }
+
+            logger.warn('runSessionTimer() | timer expired, terminating the session');
+
+            _this27.terminate({
+              cause: JsSIP_C.causes.REQUEST_TIMEOUT,
+              status_code: 408,
+              reason_phrase: 'Session Timer Expired'
+            });
+          }, expires * 1100);
+        }
+    }
+  }, {
+    key: "_toggleMuteAudio",
+    value: function _toggleMuteAudio(mute) {
+      var senders = this._connection.getSenders().filter(function (sender) {
+        return sender.track && sender.track.kind === 'audio';
+      });
+
+      var _iterator8 = _createForOfIteratorHelper(senders),
+          _step8;
+
+      try {
+        for (_iterator8.s(); !(_step8 = _iterator8.n()).done;) {
+          var sender = _step8.value;
+          sender.track.enabled = !mute;
+        }
+      } catch (err) {
+        _iterator8.e(err);
+      } finally {
+        _iterator8.f();
+      }
+    }
+  }, {
+    key: "_toggleMuteVideo",
+    value: function _toggleMuteVideo(mute) {
+      var senders = this._connection.getSenders().filter(function (sender) {
+        return sender.track && sender.track.kind === 'video';
+      });
+
+      var _iterator9 = _createForOfIteratorHelper(senders),
+          _step9;
+
+      try {
+        for (_iterator9.s(); !(_step9 = _iterator9.n()).done;) {
+          var sender = _step9.value;
+          sender.track.enabled = !mute;
+        }
+      } catch (err) {
+        _iterator9.e(err);
+      } finally {
+        _iterator9.f();
+      }
+    }
+  }, {
+    key: "_newRTCSession",
+    value: function _newRTCSession(originator, request) {
+      logger.debug('newRTCSession()');
+
+      this._ua.newRTCSession(this, {
+        originator: originator,
+        session: this,
+        request: request
+      });
+    }
+  }, {
+    key: "_connecting",
+    value: function _connecting(request) {
+      logger.debug('session connecting');
+      logger.debug('emit "connecting"');
+      this.emit('connecting', {
+        request: request
+      });
+    }
+  }, {
+    key: "_progress",
+    value: function _progress(originator, response) {
+      logger.debug('session progress');
+      logger.debug('emit "progress"');
+      this.emit('progress', {
+        originator: originator,
+        response: response || null
+      });
+    }
+  }, {
+    key: "_accepted",
+    value: function _accepted(originator, message) {
+      logger.debug('session accepted');
+      this._start_time = new Date();
+      logger.debug('emit "accepted"');
+      this.emit('accepted', {
+        originator: originator,
+        response: message || null
+      });
+    }
+  }, {
+    key: "_confirmed",
+    value: function _confirmed(originator, ack) {
+      logger.debug('session confirmed');
+      this._is_confirmed = true;
+      logger.debug('emit "confirmed"');
+      this.emit('confirmed', {
+        originator: originator,
+        ack: ack || null
+      });
+    }
+  }, {
+    key: "_ended",
+    value: function _ended(originator, message, cause) {
+      logger.debug('session ended');
+      this._end_time = new Date();
+
+      this._close();
+
+      logger.debug('emit "ended"');
+      this.emit('ended', {
+        originator: originator,
+        message: message || null,
+        cause: cause
+      });
+    }
+  }, {
+    key: "_failed",
+    value: function _failed(originator, message, cause) {
+      logger.debug('session failed'); // Emit private '_failed' event first.
+
+      logger.debug('emit "_failed"');
+      this.emit('_failed', {
+        originator: originator,
+        message: message || null,
+        cause: cause
+      });
+
+      this._close();
+
+      logger.debug('emit "failed"');
+      this.emit('failed', {
+        originator: originator,
+        message: message || null,
+        cause: cause
+      });
+    }
+  }, {
+    key: "_onhold",
+    value: function _onhold(originator) {
+      logger.debug('session onhold');
+
+      this._setLocalMediaStatus();
+
+      logger.debug('emit "hold"');
+      this.emit('hold', {
+        originator: originator
+      });
+    }
+  }, {
+    key: "_onunhold",
+    value: function _onunhold(originator) {
+      logger.debug('session onunhold');
+
+      this._setLocalMediaStatus();
+
+      logger.debug('emit "unhold"');
+      this.emit('unhold', {
+        originator: originator
+      });
+    }
+  }, {
+    key: "_onmute",
+    value: function _onmute(_ref5) {
+      var audio = _ref5.audio,
+          video = _ref5.video;
+      logger.debug('session onmute');
+
+      this._setLocalMediaStatus();
+
+      logger.debug('emit "muted"');
+      this.emit('muted', {
+        audio: audio,
+        video: video
+      });
+    }
+  }, {
+    key: "_onunmute",
+    value: function _onunmute(_ref6) {
+      var audio = _ref6.audio,
+          video = _ref6.video;
+      logger.debug('session onunmute');
+
+      this._setLocalMediaStatus();
+
+      logger.debug('emit "unmuted"');
+      this.emit('unmuted', {
+        audio: audio,
+        video: video
+      });
+    }
+  }, {
+    key: "C",
+    get: function get() {
+      return C;
+    } // Expose session failed/ended causes as a property of the RTCSession instance.
+
+  }, {
+    key: "causes",
+    get: function get() {
+      return JsSIP_C.causes;
+    }
+  }, {
+    key: "id",
+    get: function get() {
+      return this._id;
+    }
+  }, {
+    key: "connection",
+    get: function get() {
+      return this._connection;
+    }
+  }, {
+    key: "contact",
+    get: function get() {
+      return this._contact;
+    }
+  }, {
+    key: "direction",
+    get: function get() {
+      return this._direction;
+    }
+  }, {
+    key: "local_identity",
+    get: function get() {
+      return this._local_identity;
+    }
+  }, {
+    key: "remote_identity",
+    get: function get() {
+      return this._remote_identity;
+    }
+  }, {
+    key: "start_time",
+    get: function get() {
+      return this._start_time;
+    }
+  }, {
+    key: "end_time",
+    get: function get() {
+      return this._end_time;
+    }
+  }, {
+    key: "data",
+    get: function get() {
+      return this._data;
+    },
+    set: function set(_data) {
+      this._data = _data;
+    }
+  }, {
+    key: "status",
+    get: function get() {
+      return this._status;
+    }
+  }]);
+
+  return RTCSession;
+}(EventEmitter);
+},{"./Constants":2,"./Dialog":3,"./Exceptions":6,"./Logger":9,"./RTCSession/DTMF":15,"./RTCSession/Info":16,"./RTCSession/ReferNotifier":17,"./RTCSession/ReferSubscriber":18,"./RequestSender":20,"./SIPMessage":21,"./Timers":23,"./Transactions":24,"./URI":27,"./Utils":28,"events":31,"sdp-transform":37}],15:[function(require,module,exports){
+"use strict";
+
+function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
+
+function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
+
+function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); }
+
+function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }
+
+function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; }
+
+function _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } return _assertThisInitialized(self); }
+
+function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; }
+
+function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Date.prototype.toString.call(Reflect.construct(Date, [], function () {})); return true; } catch (e) { return false; } }
+
+function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }
+
+var EventEmitter = require('events').EventEmitter;
+
+var Logger = require('../Logger');
+
+var JsSIP_C = require('../Constants');
+
+var Exceptions = require('../Exceptions');
+
+var Utils = require('../Utils');
+
+var logger = new Logger('RTCSession:DTMF');
+var C = {
+  MIN_DURATION: 70,
+  MAX_DURATION: 6000,
+  DEFAULT_DURATION: 100,
+  MIN_INTER_TONE_GAP: 50,
+  DEFAULT_INTER_TONE_GAP: 500
+};
+
+module.exports = /*#__PURE__*/function (_EventEmitter) {
+  _inherits(DTMF, _EventEmitter);
+
+  var _super = _createSuper(DTMF);
+
+  function DTMF(session) {
+    var _this;
+
+    _classCallCheck(this, DTMF);
+
+    _this = _super.call(this);
+    _this._session = session;
+    _this._direction = null;
+    _this._tone = null;
+    _this._duration = null;
+    _this._request = null;
+    return _this;
+  }
+
+  _createClass(DTMF, [{
+    key: "send",
+    value: function send(tone) {
+      var _this2 = this;
+
+      var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
+
+      if (tone === undefined) {
+        throw new TypeError('Not enough arguments');
+      }
+
+      this._direction = 'outgoing'; // Check RTCSession Status.
+
+      if (this._session.status !== this._session.C.STATUS_CONFIRMED && this._session.status !== this._session.C.STATUS_WAITING_FOR_ACK) {
+        throw new Exceptions.InvalidStateError(this._session.status);
+      }
+
+      var extraHeaders = Utils.cloneArray(options.extraHeaders);
+      this.eventHandlers = Utils.cloneObject(options.eventHandlers); // Check tone type.
+
+      if (typeof tone === 'string') {
+        tone = tone.toUpperCase();
+      } else if (typeof tone === 'number') {
+        tone = tone.toString();
+      } else {
+        throw new TypeError("Invalid tone: ".concat(tone));
+      } // Check tone value.
+
+
+      if (!tone.match(/^[0-9A-DR#*]$/)) {
+        throw new TypeError("Invalid tone: ".concat(tone));
+      } else {
+        this._tone = tone;
+      } // Duration is checked/corrected in RTCSession.
+
+
+      this._duration = options.duration;
+      extraHeaders.push('Content-Type: application/dtmf-relay');
+      var body = "Signal=".concat(this._tone, "\r\n");
+      body += "Duration=".concat(this._duration);
+
+      this._session.newDTMF({
+        originator: 'local',
+        dtmf: this,
+        request: this._request
+      });
+
+      this._session.sendRequest(JsSIP_C.INFO, {
+        extraHeaders: extraHeaders,
+        eventHandlers: {
+          onSuccessResponse: function onSuccessResponse(response) {
+            _this2.emit('succeeded', {
+              originator: 'remote',
+              response: response
+            });
+          },
+          onErrorResponse: function onErrorResponse(response) {
+            if (_this2.eventHandlers.onFailed) {
+              _this2.eventHandlers.onFailed();
+            }
+
+            _this2.emit('failed', {
+              originator: 'remote',
+              response: response
+            });
+          },
+          onRequestTimeout: function onRequestTimeout() {
+            _this2._session.onRequestTimeout();
+          },
+          onTransportError: function onTransportError() {
+            _this2._session.onTransportError();
+          },
+          onDialogError: function onDialogError() {
+            _this2._session.onDialogError();
+          }
+        },
+        body: body
+      });
+    }
+  }, {
+    key: "init_incoming",
+    value: function init_incoming(request) {
+      var reg_tone = /^(Signal\s*?=\s*?)([0-9A-D#*]{1})(\s)?.*/;
+      var reg_duration = /^(Duration\s?=\s?)([0-9]{1,4})(\s)?.*/;
+      this._direction = 'incoming';
+      this._request = request;
+      request.reply(200);
+
+      if (request.body) {
+        var body = request.body.split('\n');
+
+        if (body.length >= 1) {
+          if (reg_tone.test(body[0])) {
+            this._tone = body[0].replace(reg_tone, '$2');
+          }
+        }
+
+        if (body.length >= 2) {
+          if (reg_duration.test(body[1])) {
+            this._duration = parseInt(body[1].replace(reg_duration, '$2'), 10);
+          }
+        }
+      }
+
+      if (!this._duration) {
+        this._duration = C.DEFAULT_DURATION;
+      }
+
+      if (!this._tone) {
+        logger.debug('invalid INFO DTMF received, discarded');
+      } else {
+        this._session.newDTMF({
+          originator: 'remote',
+          dtmf: this,
+          request: request
+        });
+      }
+    }
+  }, {
+    key: "tone",
+    get: function get() {
+      return this._tone;
+    }
+  }, {
+    key: "duration",
+    get: function get() {
+      return this._duration;
+    }
+  }]);
+
+  return DTMF;
+}(EventEmitter);
+/**
+ * Expose C object.
+ */
+
+
+module.exports.C = C;
+},{"../Constants":2,"../Exceptions":6,"../Logger":9,"../Utils":28,"events":31}],16:[function(require,module,exports){
+"use strict";
+
+function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
+
+function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
+
+function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); }
+
+function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }
+
+function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; }
+
+function _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } return _assertThisInitialized(self); }
+
+function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; }
+
+function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Date.prototype.toString.call(Reflect.construct(Date, [], function () {})); return true; } catch (e) { return false; } }
+
+function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }
+
+var EventEmitter = require('events').EventEmitter;
+
+var JsSIP_C = require('../Constants');
+
+var Exceptions = require('../Exceptions');
+
+var Utils = require('../Utils');
+
+module.exports = /*#__PURE__*/function (_EventEmitter) {
+  _inherits(Info, _EventEmitter);
+
+  var _super = _createSuper(Info);
+
+  function Info(session) {
+    var _this;
+
+    _classCallCheck(this, Info);
+
+    _this = _super.call(this);
+    _this._session = session;
+    _this._direction = null;
+    _this._contentType = null;
+    _this._body = null;
+    return _this;
+  }
+
+  _createClass(Info, [{
+    key: "send",
+    value: function send(contentType, body) {
+      var _this2 = this;
+
+      var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
+      this._direction = 'outgoing';
+
+      if (contentType === undefined) {
+        throw new TypeError('Not enough arguments');
+      } // Check RTCSession Status.
+
+
+      if (this._session.status !== this._session.C.STATUS_CONFIRMED && this._session.status !== this._session.C.STATUS_WAITING_FOR_ACK) {
+        throw new Exceptions.InvalidStateError(this._session.status);
+      }
+
+      this._contentType = contentType;
+      this._body = body;
+      var extraHeaders = Utils.cloneArray(options.extraHeaders);
+      extraHeaders.push("Content-Type: ".concat(contentType));
+
+      this._session.newInfo({
+        originator: 'local',
+        info: this,
+        request: this.request
+      });
+
+      this._session.sendRequest(JsSIP_C.INFO, {
+        extraHeaders: extraHeaders,
+        eventHandlers: {
+          onSuccessResponse: function onSuccessResponse(response) {
+            _this2.emit('succeeded', {
+              originator: 'remote',
+              response: response
+            });
+          },
+          onErrorResponse: function onErrorResponse(response) {
+            _this2.emit('failed', {
+              originator: 'remote',
+              response: response
+            });
+          },
+          onTransportError: function onTransportError() {
+            _this2._session.onTransportError();
+          },
+          onRequestTimeout: function onRequestTimeout() {
+            _this2._session.onRequestTimeout();
+          },
+          onDialogError: function onDialogError() {
+            _this2._session.onDialogError();
+          }
+        },
+        body: body
+      });
+    }
+  }, {
+    key: "init_incoming",
+    value: function init_incoming(request) {
+      this._direction = 'incoming';
+      this.request = request;
+      request.reply(200);
+      this._contentType = request.hasHeader('Content-Type') ? request.getHeader('Content-Type').toLowerCase() : undefined;
+      this._body = request.body;
+
+      this._session.newInfo({
+        originator: 'remote',
+        info: this,
+        request: request
+      });
+    }
+  }, {
+    key: "contentType",
+    get: function get() {
+      return this._contentType;
+    }
+  }, {
+    key: "body",
+    get: function get() {
+      return this._body;
+    }
+  }]);
+
+  return Info;
+}(EventEmitter);
+},{"../Constants":2,"../Exceptions":6,"../Utils":28,"events":31}],17:[function(require,module,exports){
+"use strict";
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
+
+function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
+
+var Logger = require('../Logger');
+
+var JsSIP_C = require('../Constants');
+
+var logger = new Logger('RTCSession:ReferNotifier');
+var C = {
+  event_type: 'refer',
+  body_type: 'message/sipfrag;version=2.0',
+  expires: 300
+};
+
+module.exports = /*#__PURE__*/function () {
+  function ReferNotifier(session, id, expires) {
+    _classCallCheck(this, ReferNotifier);
+
+    this._session = session;
+    this._id = id;
+    this._expires = expires || C.expires;
+    this._active = true; // The creation of a Notifier results in an immediate NOTIFY.
+
+    this.notify(100);
+  }
+
+  _createClass(ReferNotifier, [{
+    key: "notify",
+    value: function notify(code, reason) {
+      logger.debug('notify()');
+
+      if (this._active === false) {
+        return;
+      }
+
+      reason = reason || JsSIP_C.REASON_PHRASE[code] || '';
+      var state;
+
+      if (code >= 200) {
+        state = 'terminated;reason=noresource';
+      } else {
+        state = "active;expires=".concat(this._expires);
+      } // Put this in a try/catch block.
+
+
+      this._session.sendRequest(JsSIP_C.NOTIFY, {
+        extraHeaders: ["Event: ".concat(C.event_type, ";id=").concat(this._id), "Subscription-State: ".concat(state), "Content-Type: ".concat(C.body_type)],
+        body: "SIP/2.0 ".concat(code, " ").concat(reason),
+        eventHandlers: {
+          // If a negative response is received, subscription is canceled.
+          onErrorResponse: function onErrorResponse() {
+            this._active = false;
+          }
+        }
+      });
+    }
+  }]);
+
+  return ReferNotifier;
+}();
+},{"../Constants":2,"../Logger":9}],18:[function(require,module,exports){
+"use strict";
+
+function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
+
+function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
+
+function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); }
+
+function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }
+
+function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; }
+
+function _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } return _assertThisInitialized(self); }
+
+function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; }
+
+function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Date.prototype.toString.call(Reflect.construct(Date, [], function () {})); return true; } catch (e) { return false; } }
+
+function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }
+
+var EventEmitter = require('events').EventEmitter;
+
+var Logger = require('../Logger');
+
+var JsSIP_C = require('../Constants');
+
+var Grammar = require('../Grammar');
+
+var Utils = require('../Utils');
+
+var logger = new Logger('RTCSession:ReferSubscriber');
+
+module.exports = /*#__PURE__*/function (_EventEmitter) {
+  _inherits(ReferSubscriber, _EventEmitter);
+
+  var _super = _createSuper(ReferSubscriber);
+
+  function ReferSubscriber(session) {
+    var _this;
+
+    _classCallCheck(this, ReferSubscriber);
+
+    _this = _super.call(this);
+    _this._id = null;
+    _this._session = session;
+    return _this;
+  }
+
+  _createClass(ReferSubscriber, [{
+    key: "sendRefer",
+    value: function sendRefer(target) {
+      var _this2 = this;
+
+      var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
+      logger.debug('sendRefer()');
+      var extraHeaders = Utils.cloneArray(options.extraHeaders);
+      var eventHandlers = Utils.cloneObject(options.eventHandlers); // Set event handlers.
+
+      for (var event in eventHandlers) {
+        if (Object.prototype.hasOwnProperty.call(eventHandlers, event)) {
+          this.on(event, eventHandlers[event]);
+        }
+      } // Replaces URI header field.
+
+
+      var replaces = null;
+
+      if (options.replaces) {
+        replaces = options.replaces._request.call_id;
+        replaces += ";to-tag=".concat(options.replaces._to_tag);
+        replaces += ";from-tag=".concat(options.replaces._from_tag);
+        replaces = encodeURIComponent(replaces);
+      } // Refer-To header field.
+
+
+      var referTo = "Refer-To: <".concat(target).concat(replaces ? "?Replaces=".concat(replaces) : '', ">");
+      extraHeaders.push(referTo); // Referred-By header field (if not already present).
+
+      if (!extraHeaders.some(function (header) {
+        return header.toLowerCase().startsWith('referred-by:');
+      })) {
+        var referredBy = "Referred-By: <".concat(this._session._ua._configuration.uri._scheme, ":").concat(this._session._ua._configuration.uri._user, "@").concat(this._session._ua._configuration.uri._host, ">");
+        extraHeaders.push(referredBy);
+      }
+
+      extraHeaders.push("Contact: ".concat(this._session.contact));
+
+      var request = this._session.sendRequest(JsSIP_C.REFER, {
+        extraHeaders: extraHeaders,
+        eventHandlers: {
+          onSuccessResponse: function onSuccessResponse(response) {
+            _this2._requestSucceeded(response);
+          },
+          onErrorResponse: function onErrorResponse(response) {
+            _this2._requestFailed(response, JsSIP_C.causes.REJECTED);
+          },
+          onTransportError: function onTransportError() {
+            _this2._requestFailed(null, JsSIP_C.causes.CONNECTION_ERROR);
+          },
+          onRequestTimeout: function onRequestTimeout() {
+            _this2._requestFailed(null, JsSIP_C.causes.REQUEST_TIMEOUT);
+          },
+          onDialogError: function onDialogError() {
+            _this2._requestFailed(null, JsSIP_C.causes.DIALOG_ERROR);
+          }
+        }
+      });
+
+      this._id = request.cseq;
+    }
+  }, {
+    key: "receiveNotify",
+    value: function receiveNotify(request) {
+      logger.debug('receiveNotify()');
+
+      if (!request.body) {
+        return;
+      }
+
+      var status_line = Grammar.parse(request.body.trim().split('\r\n', 1)[0], 'Status_Line');
+
+      if (status_line === -1) {
+        logger.debug("receiveNotify() | error parsing NOTIFY body: \"".concat(request.body, "\""));
+        return;
+      }
+
+      switch (true) {
+        case /^100$/.test(status_line.status_code):
+          this.emit('trying', {
+            request: request,
+            status_line: status_line
+          });
+          break;
+
+        case /^1[0-9]{2}$/.test(status_line.status_code):
+          this.emit('progress', {
+            request: request,
+            status_line: status_line
+          });
+          break;
+
+        case /^2[0-9]{2}$/.test(status_line.status_code):
+          this.emit('accepted', {
+            request: request,
+            status_line: status_line
+          });
+          break;
+
+        default:
+          this.emit('failed', {
+            request: request,
+            status_line: status_line
+          });
+          break;
+      }
+    }
+  }, {
+    key: "_requestSucceeded",
+    value: function _requestSucceeded(response) {
+      logger.debug('REFER succeeded');
+      logger.debug('emit "requestSucceeded"');
+      this.emit('requestSucceeded', {
+        response: response
+      });
+    }
+  }, {
+    key: "_requestFailed",
+    value: function _requestFailed(response, cause) {
+      logger.debug('REFER failed');
+      logger.debug('emit "requestFailed"');
+      this.emit('requestFailed', {
+        response: response || null,
+        cause: cause
+      });
+    }
+  }, {
+    key: "id",
+    get: function get() {
+      return this._id;
+    }
+  }]);
+
+  return ReferSubscriber;
+}(EventEmitter);
+},{"../Constants":2,"../Grammar":7,"../Logger":9,"../Utils":28,"events":31}],19:[function(require,module,exports){
+"use strict";
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
+
+function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
+
+var Logger = require('./Logger');
+
+var Utils = require('./Utils');
+
+var JsSIP_C = require('./Constants');
+
+var SIPMessage = require('./SIPMessage');
+
+var RequestSender = require('./RequestSender');
+
+var logger = new Logger('Registrator');
+var MIN_REGISTER_EXPIRES = 10; // In seconds.
+
+module.exports = /*#__PURE__*/function () {
+  function Registrator(ua, transport) {
+    _classCallCheck(this, Registrator);
+
+    // Force reg_id to 1.
+    this._reg_id = 1;
+    this._ua = ua;
+    this._transport = transport;
+    this._registrar = ua.configuration.registrar_server;
+    this._expires = ua.configuration.register_expires; // Call-ID and CSeq values RFC3261 10.2.
+
+    this._call_id = Utils.createRandomToken(22);
+    this._cseq = 0;
+    this._to_uri = ua.configuration.uri;
+    this._registrationTimer = null; // Ongoing Register request.
+
+    this._registering = false; // Set status.
+
+    this._registered = false; // Contact header.
+
+    this._contact = this._ua.contact.toString(); // Sip.ice media feature tag (RFC 5768).
+
+    this._contact += ';+sip.ice'; // Custom headers for REGISTER and un-REGISTER.
+
+    this._extraHeaders = []; // Custom Contact header params for REGISTER and un-REGISTER.
+
+    this._extraContactParams = ''; // Contents of the sip.instance Contact header parameter.
+
+    this._sipInstance = "\"<urn:uuid:".concat(this._ua.configuration.instance_id, ">\"");
+    this._contact += ";reg-id=".concat(this._reg_id);
+    this._contact += ";+sip.instance=".concat(this._sipInstance);
+  }
+
+  _createClass(Registrator, [{
+    key: "setExtraHeaders",
+    value: function setExtraHeaders(extraHeaders) {
+      if (!Array.isArray(extraHeaders)) {
+        extraHeaders = [];
+      }
+
+      this._extraHeaders = extraHeaders.slice();
+    }
+  }, {
+    key: "setExtraContactParams",
+    value: function setExtraContactParams(extraContactParams) {
+      if (!(extraContactParams instanceof Object)) {
+        extraContactParams = {};
+      } // Reset it.
+
+
+      this._extraContactParams = '';
+
+      for (var param_key in extraContactParams) {
+        if (Object.prototype.hasOwnProperty.call(extraContactParams, param_key)) {
+          var param_value = extraContactParams[param_key];
+          this._extraContactParams += ";".concat(param_key);
+
+          if (param_value) {
+            this._extraContactParams += "=".concat(param_value);
+          }
+        }
+      }
+    }
+  }, {
+    key: "register",
+    value: function register() {
+      var _this = this;
+
+      if (this._registering) {
+        logger.debug('Register request in progress...');
+        return;
+      }
+
+      var extraHeaders = this._extraHeaders.slice();
+
+      extraHeaders.push("Contact: ".concat(this._contact, ";expires=").concat(this._expires).concat(this._extraContactParams));
+      extraHeaders.push("Expires: ".concat(this._expires));
+      var request = new SIPMessage.OutgoingRequest(JsSIP_C.REGISTER, this._registrar, this._ua, {
+        'to_uri': this._to_uri,
+        'call_id': this._call_id,
+        'cseq': this._cseq += 1
+      }, extraHeaders);
+      var request_sender = new RequestSender(this._ua, request, {
+        onRequestTimeout: function onRequestTimeout() {
+          _this._registrationFailure(null, JsSIP_C.causes.REQUEST_TIMEOUT);
+        },
+        onTransportError: function onTransportError() {
+          _this._registrationFailure(null, JsSIP_C.causes.CONNECTION_ERROR);
+        },
+        // Increase the CSeq on authentication.
+        onAuthenticated: function onAuthenticated() {
+          _this._cseq += 1;
+        },
+        onReceiveResponse: function onReceiveResponse(response) {
+          // Discard responses to older REGISTER/un-REGISTER requests.
+          if (response.cseq !== _this._cseq) {
+            return;
+          } // Clear registration timer.
+
+
+          if (_this._registrationTimer !== null) {
+            clearTimeout(_this._registrationTimer);
+            _this._registrationTimer = null;
+          }
+
+          switch (true) {
+            case /^1[0-9]{2}$/.test(response.status_code):
+              {
+                // Ignore provisional responses.
+                break;
+              }
+
+            case /^2[0-9]{2}$/.test(response.status_code):
+              {
+                _this._registering = false;
+
+                if (!response.hasHeader('Contact')) {
+                  logger.debug('no Contact header in response to REGISTER, response ignored');
+                  break;
+                }
+
+                var contacts = response.headers['Contact'].reduce(function (a, b) {
+                  return a.concat(b.parsed);
+                }, []); // Get the Contact pointing to us and update the expires value accordingly.
+                // Try to find a matching Contact using sip.instance and reg-id.
+
+                var contact = contacts.find(function (element) {
+                  return _this._sipInstance === element.getParam('+sip.instance') && _this._reg_id === parseInt(element.getParam('reg-id'));
+                }); // If no match was found using the sip.instance try comparing the URIs.
+
+                if (!contact) {
+                  contact = contacts.find(function (element) {
+                    return element.uri.user === _this._ua.contact.uri.user;
+                  });
+                }
+
+                if (!contact) {
+                  logger.debug('no Contact header pointing to us, response ignored');
+                  break;
+                }
+
+                var expires = contact.getParam('expires');
+
+                if (!expires && response.hasHeader('expires')) {
+                  expires = response.getHeader('expires');
+                }
+
+                if (!expires) {
+                  expires = _this._expires;
+                }
+
+                expires = Number(expires);
+                if (expires < MIN_REGISTER_EXPIRES) expires = MIN_REGISTER_EXPIRES;
+                var timeout = expires > 64 ? expires * 1000 / 2 + Math.floor((expires / 2 - 32) * 1000 * Math.random()) : expires * 1000 - 5000; // Re-Register or emit an event before the expiration interval has elapsed.
+                // For that, decrease the expires value. ie: 3 seconds.
+
+                _this._registrationTimer = setTimeout(function () {
+                  _this._registrationTimer = null; // If there are no listeners for registrationExpiring, renew registration.
+                  // If there are listeners, let the function listening do the register call.
+
+                  if (_this._ua.listeners('registrationExpiring').length === 0) {
+                    _this.register();
+                  } else {
+                    _this._ua.emit('registrationExpiring');
+                  }
+                }, timeout); // Save gruu values.
+
+                if (contact.hasParam('temp-gruu')) {
+                  _this._ua.contact.temp_gruu = contact.getParam('temp-gruu').replace(/"/g, '');
+                }
+
+                if (contact.hasParam('pub-gruu')) {
+                  _this._ua.contact.pub_gruu = contact.getParam('pub-gruu').replace(/"/g, '');
+                }
+
+                if (!_this._registered) {
+                  _this._registered = true;
+
+                  _this._ua.registered({
+                    response: response
+                  });
+                }
+
+                break;
+              }
+            // Interval too brief RFC3261 10.2.8.
+
+            case /^423$/.test(response.status_code):
+              {
+                if (response.hasHeader('min-expires')) {
+                  // Increase our registration interval to the suggested minimum.
+                  _this._expires = Number(response.getHeader('min-expires'));
+                  if (_this._expires < MIN_REGISTER_EXPIRES) _this._expires = MIN_REGISTER_EXPIRES; // Attempt the registration again immediately.
+
+                  _this.register();
+                } else {
+                  // This response MUST contain a Min-Expires header field.
+                  logger.debug('423 response received for REGISTER without Min-Expires');
+
+                  _this._registrationFailure(response, JsSIP_C.causes.SIP_FAILURE_CODE);
+                }
+
+                break;
+              }
+
+            default:
+              {
+                var cause = Utils.sipErrorCause(response.status_code);
+
+                _this._registrationFailure(response, cause);
+              }
+          }
+        }
+      });
+      this._registering = true;
+      request_sender.send();
+    }
+  }, {
+    key: "unregister",
+    value: function unregister() {
+      var _this2 = this;
+
+      var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
+
+      if (!this._registered) {
+        logger.debug('already unregistered');
+        return;
+      }
+
+      this._registered = false; // Clear the registration timer.
+
+      if (this._registrationTimer !== null) {
+        clearTimeout(this._registrationTimer);
+        this._registrationTimer = null;
+      }
+
+      var extraHeaders = this._extraHeaders.slice();
+
+      if (options.all) {
+        extraHeaders.push("Contact: *".concat(this._extraContactParams));
+      } else {
+        extraHeaders.push("Contact: ".concat(this._contact, ";expires=0").concat(this._extraContactParams));
+      }
+
+      extraHeaders.push('Expires: 0');
+      var request = new SIPMessage.OutgoingRequest(JsSIP_C.REGISTER, this._registrar, this._ua, {
+        'to_uri': this._to_uri,
+        'call_id': this._call_id,
+        'cseq': this._cseq += 1
+      }, extraHeaders);
+      var request_sender = new RequestSender(this._ua, request, {
+        onRequestTimeout: function onRequestTimeout() {
+          _this2._unregistered(null, JsSIP_C.causes.REQUEST_TIMEOUT);
+        },
+        onTransportError: function onTransportError() {
+          _this2._unregistered(null, JsSIP_C.causes.CONNECTION_ERROR);
+        },
+        // Increase the CSeq on authentication.
+        onAuthenticated: function onAuthenticated() {
+          _this2._cseq += 1;
+        },
+        onReceiveResponse: function onReceiveResponse(response) {
+          switch (true) {
+            case /^1[0-9]{2}$/.test(response.status_code):
+              // Ignore provisional responses.
+              break;
+
+            case /^2[0-9]{2}$/.test(response.status_code):
+              _this2._unregistered(response);
+
+              break;
+
+            default:
+              {
+                var cause = Utils.sipErrorCause(response.status_code);
+
+                _this2._unregistered(response, cause);
+              }
+          }
+        }
+      });
+      request_sender.send();
+    }
+  }, {
+    key: "close",
+    value: function close() {
+      if (this._registered) {
+        this.unregister();
+      }
+    }
+  }, {
+    key: "onTransportClosed",
+    value: function onTransportClosed() {
+      this._registering = false;
+
+      if (this._registrationTimer !== null) {
+        clearTimeout(this._registrationTimer);
+        this._registrationTimer = null;
+      }
+
+      if (this._registered) {
+        this._registered = false;
+
+        this._ua.unregistered({});
+      }
+    }
+  }, {
+    key: "_registrationFailure",
+    value: function _registrationFailure(response, cause) {
+      this._registering = false;
+
+      this._ua.registrationFailed({
+        response: response || null,
+        cause: cause
+      });
+
+      if (this._registered) {
+        this._registered = false;
+
+        this._ua.unregistered({
+          response: response || null,
+          cause: cause
+        });
+      }
+    }
+  }, {
+    key: "_unregistered",
+    value: function _unregistered(response, cause) {
+      this._registering = false;
+      this._registered = false;
+
+      this._ua.unregistered({
+        response: response || null,
+        cause: cause || null
+      });
+    }
+  }, {
+    key: "registered",
+    get: function get() {
+      return this._registered;
+    }
+  }]);
+
+  return Registrator;
+}();
+},{"./Constants":2,"./Logger":9,"./RequestSender":20,"./SIPMessage":21,"./Utils":28}],20:[function(require,module,exports){
+"use strict";
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
+
+function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
+
+var Logger = require('./Logger');
+
+var JsSIP_C = require('./Constants');
+
+var DigestAuthentication = require('./DigestAuthentication');
+
+var Transactions = require('./Transactions');
+
+var logger = new Logger('RequestSender'); // Default event handlers.
+
+var EventHandlers = {
+  onRequestTimeout: function onRequestTimeout() {},
+  onTransportError: function onTransportError() {},
+  onReceiveResponse: function onReceiveResponse() {},
+  onAuthenticated: function onAuthenticated() {}
+};
+
+module.exports = /*#__PURE__*/function () {
+  function RequestSender(ua, request, eventHandlers) {
+    _classCallCheck(this, RequestSender);
+
+    this._ua = ua;
+    this._eventHandlers = eventHandlers;
+    this._method = request.method;
+    this._request = request;
+    this._auth = null;
+    this._challenged = false;
+    this._staled = false; // Define the undefined handlers.
+
+    for (var handler in EventHandlers) {
+      if (Object.prototype.hasOwnProperty.call(EventHandlers, handler)) {
+        if (!this._eventHandlers[handler]) {
+          this._eventHandlers[handler] = EventHandlers[handler];
+        }
+      }
+    } // If ua is in closing process or even closed just allow sending Bye and ACK.
+
+
+    if (ua.status === ua.C.STATUS_USER_CLOSED && (this._method !== JsSIP_C.BYE || this._method !== JsSIP_C.ACK)) {
+      this._eventHandlers.onTransportError();
+    }
+  }
+  /**
+  * Create the client transaction and send the message.
+  */
+
+
+  _createClass(RequestSender, [{
+    key: "send",
+    value: function send() {
+      var _this = this;
+
+      var eventHandlers = {
+        onRequestTimeout: function onRequestTimeout() {
+          _this._eventHandlers.onRequestTimeout();
+        },
+        onTransportError: function onTransportError() {
+          _this._eventHandlers.onTransportError();
+        },
+        onReceiveResponse: function onReceiveResponse(response) {
+          _this._receiveResponse(response);
+        }
+      };
+
+      switch (this._method) {
+        case 'INVITE':
+          this.clientTransaction = new Transactions.InviteClientTransaction(this._ua, this._ua.transport, this._request, eventHandlers);
+          break;
+
+        case 'ACK':
+          this.clientTransaction = new Transactions.AckClientTransaction(this._ua, this._ua.transport, this._request, eventHandlers);
+          break;
+
+        default:
+          this.clientTransaction = new Transactions.NonInviteClientTransaction(this._ua, this._ua.transport, this._request, eventHandlers);
+      } // If authorization JWT is present, use it.
+
+
+      if (this._ua._configuration.authorization_jwt) {
+        this._request.setHeader('Authorization', this._ua._configuration.authorization_jwt);
+      }
+
+      this.clientTransaction.send();
+    }
+    /**
+    * Called from client transaction when receiving a correct response to the request.
+    * Authenticate request if needed or pass the response back to the applicant.
+    */
+
+  }, {
+    key: "_receiveResponse",
+    value: function _receiveResponse(response) {
+      var challenge;
+      var authorization_header_name;
+      var status_code = response.status_code;
+      /*
+      * Authentication
+      * Authenticate once. _challenged_ flag used to avoid infinite authentications.
+      */
+
+      if ((status_code === 401 || status_code === 407) && (this._ua.configuration.password !== null || this._ua.configuration.ha1 !== null)) {
+        // Get and parse the appropriate WWW-Authenticate or Proxy-Authenticate header.
+        if (response.status_code === 401) {
+          challenge = response.parseHeader('www-authenticate');
+          authorization_header_name = 'authorization';
+        } else {
+          challenge = response.parseHeader('proxy-authenticate');
+          authorization_header_name = 'proxy-authorization';
+        } // Verify it seems a valid challenge.
+
+
+        if (!challenge) {
+          logger.debug("".concat(response.status_code, " with wrong or missing challenge, cannot authenticate"));
+
+          this._eventHandlers.onReceiveResponse(response);
+
+          return;
+        }
+
+        if (!this._challenged || !this._staled && challenge.stale === true) {
+          if (!this._auth) {
+            this._auth = new DigestAuthentication({
+              username: this._ua.configuration.authorization_user,
+              password: this._ua.configuration.password,
+              realm: this._ua.configuration.realm,
+              ha1: this._ua.configuration.ha1
+            });
+          } // Verify that the challenge is really valid.
+
+
+          if (!this._auth.authenticate(this._request, challenge)) {
+            this._eventHandlers.onReceiveResponse(response);
+
+            return;
+          }
+
+          this._challenged = true; // Update ha1 and realm in the UA.
+
+          this._ua.set('realm', this._auth.get('realm'));
+
+          this._ua.set('ha1', this._auth.get('ha1'));
+
+          if (challenge.stale) {
+            this._staled = true;
+          }
+
+          this._request = this._request.clone();
+          this._request.cseq += 1;
+
+          this._request.setHeader('cseq', "".concat(this._request.cseq, " ").concat(this._method));
+
+          this._request.setHeader(authorization_header_name, this._auth.toString());
+
+          this._eventHandlers.onAuthenticated(this._request);
+
+          this.send();
+        } else {
+          this._eventHandlers.onReceiveResponse(response);
+        }
+      } else {
+        this._eventHandlers.onReceiveResponse(response);
+      }
+    }
+  }]);
+
+  return RequestSender;
+}();
+},{"./Constants":2,"./DigestAuthentication":5,"./Logger":9,"./Transactions":24}],21:[function(require,module,exports){
+"use strict";
+
+function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }
+
+function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); }
+
+function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }
+
+function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; }
+
+function _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } return _assertThisInitialized(self); }
+
+function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; }
+
+function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Date.prototype.toString.call(Reflect.construct(Date, [], function () {})); return true; } catch (e) { return false; } }
+
+function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }
+
+function _createForOfIteratorHelper(o, allowArrayLike) { var it; if (typeof Symbol === "undefined" || o[Symbol.iterator] == null) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = o[Symbol.iterator](); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it["return"] != null) it["return"](); } finally { if (didErr) throw err; } } }; }
+
+function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
+
+function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; }
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
+
+function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
+
+var sdp_transform = require('sdp-transform');
+
+var Logger = require('./Logger');
+
+var JsSIP_C = require('./Constants');
+
+var Utils = require('./Utils');
+
+var NameAddrHeader = require('./NameAddrHeader');
+
+var Grammar = require('./Grammar');
+
+var logger = new Logger('SIPMessage');
+/**
+ * -param {String} method request method
+ * -param {String} ruri request uri
+ * -param {UA} ua
+ * -param {Object} params parameters that will have priority over ua.configuration parameters:
+ * <br>
+ *  - cseq, call_id, from_tag, from_uri, from_display_name, to_uri, to_tag, route_set
+ * -param {Object} [headers] extra headers
+ * -param {String} [body]
+ */
+
+var OutgoingRequest = /*#__PURE__*/function () {
+  function OutgoingRequest(method, ruri, ua, params, extraHeaders, body) {
+    _classCallCheck(this, OutgoingRequest);
+
+    // Mandatory parameters check.
+    if (!method || !ruri || !ua) {
+      return null;
+    }
+
+    params = params || {};
+    this.ua = ua;
+    this.headers = {};
+    this.method = method;
+    this.ruri = ruri;
+    this.body = body;
+    this.extraHeaders = Utils.cloneArray(extraHeaders);
+
+    if (this.ua.configuration.extra_headers) {
+      this.extraHeaders = this.extraHeaders.concat(this.ua.configuration.extra_headers);
+    } // Fill the Common SIP Request Headers.
+    // Route.
+
+
+    if (params.route_set) {
+      this.setHeader('route', params.route_set);
+    } else if (ua.configuration.use_preloaded_route) {
+      this.setHeader('route', "<".concat(ua.transport.sip_uri, ";lr>"));
+    } // Via.
+    // Empty Via header. Will be filled by the client transaction.
+
+
+    this.setHeader('via', ''); // Max-Forwards.
+
+    this.setHeader('max-forwards', JsSIP_C.MAX_FORWARDS); // To
+
+    var to_uri = params.to_uri || ruri;
+    var to_params = params.to_tag ? {
+      tag: params.to_tag
+    } : null;
+    var to_display_name = typeof params.to_display_name !== 'undefined' ? params.to_display_name : null;
+    this.to = new NameAddrHeader(to_uri, to_display_name, to_params);
+    this.setHeader('to', this.to.toString()); // From.
+
+    var from_uri = params.from_uri || ua.configuration.uri;
+    var from_params = {
+      tag: params.from_tag || Utils.newTag()
+    };
+    var display_name;
+
+    if (typeof params.from_display_name !== 'undefined') {
+      display_name = params.from_display_name;
+    } else if (ua.configuration.display_name) {
+      display_name = ua.configuration.display_name;
+    } else {
+      display_name = null;
+    }
+
+    this.from = new NameAddrHeader(from_uri, display_name, from_params);
+    this.setHeader('from', this.from.toString()); // Call-ID.
+
+    var call_id = params.call_id || ua.configuration.jssip_id + Utils.createRandomToken(15);
+    this.call_id = call_id;
+    this.setHeader('call-id', call_id); // CSeq.
+
+    var cseq = params.cseq || Math.floor(Math.random() * 10000);
+    this.cseq = cseq;
+    this.setHeader('cseq', "".concat(cseq, " ").concat(method));
+  }
+  /**
+   * Replace the the given header by the given value.
+   * -param {String} name header name
+   * -param {String | Array} value header value
+   */
+
+
+  _createClass(OutgoingRequest, [{
+    key: "setHeader",
+    value: function setHeader(name, value) {
+      // Remove the header from extraHeaders if present.
+      var regexp = new RegExp("^\\s*".concat(name, "\\s*:"), 'i');
+
+      for (var idx = 0; idx < this.extraHeaders.length; idx++) {
+        if (regexp.test(this.extraHeaders[idx])) {
+          this.extraHeaders.splice(idx, 1);
+        }
+      }
+
+      this.headers[Utils.headerize(name)] = Array.isArray(value) ? value : [value];
+    }
+    /**
+     * Get the value of the given header name at the given position.
+     * -param {String} name header name
+     * -returns {String|undefined} Returns the specified header, null if header doesn't exist.
+     */
+
+  }, {
+    key: "getHeader",
+    value: function getHeader(name) {
+      var headers = this.headers[Utils.headerize(name)];
+
+      if (headers) {
+        if (headers[0]) {
+          return headers[0];
+        }
+      } else {
+        var regexp = new RegExp("^\\s*".concat(name, "\\s*:"), 'i');
+
+        var _iterator = _createForOfIteratorHelper(this.extraHeaders),
+            _step;
+
+        try {
+          for (_iterator.s(); !(_step = _iterator.n()).done;) {
+            var header = _step.value;
+
+            if (regexp.test(header)) {
+              return header.substring(header.indexOf(':') + 1).trim();
+            }
+          }
+        } catch (err) {
+          _iterator.e(err);
+        } finally {
+          _iterator.f();
+        }
+      }
+
+      return;
+    }
+    /**
+     * Get the header/s of the given name.
+     * -param {String} name header name
+     * -returns {Array} Array with all the headers of the specified name.
+     */
+
+  }, {
+    key: "getHeaders",
+    value: function getHeaders(name) {
+      var headers = this.headers[Utils.headerize(name)];
+      var result = [];
+
+      if (headers) {
+        var _iterator2 = _createForOfIteratorHelper(headers),
+            _step2;
+
+        try {
+          for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
+            var header = _step2.value;
+            result.push(header);
+          }
+        } catch (err) {
+          _iterator2.e(err);
+        } finally {
+          _iterator2.f();
+        }
+
+        return result;
+      } else {
+        var regexp = new RegExp("^\\s*".concat(name, "\\s*:"), 'i');
+
+        var _iterator3 = _createForOfIteratorHelper(this.extraHeaders),
+            _step3;
+
+        try {
+          for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
+            var _header = _step3.value;
+
+            if (regexp.test(_header)) {
+              result.push(_header.substring(_header.indexOf(':') + 1).trim());
+            }
+          }
+        } catch (err) {
+          _iterator3.e(err);
+        } finally {
+          _iterator3.f();
+        }
+
+        return result;
+      }
+    }
+    /**
+     * Verify the existence of the given header.
+     * -param {String} name header name
+     * -returns {boolean} true if header with given name exists, false otherwise
+     */
+
+  }, {
+    key: "hasHeader",
+    value: function hasHeader(name) {
+      if (this.headers[Utils.headerize(name)]) {
+        return true;
+      } else {
+        var regexp = new RegExp("^\\s*".concat(name, "\\s*:"), 'i');
+
+        var _iterator4 = _createForOfIteratorHelper(this.extraHeaders),
+            _step4;
+
+        try {
+          for (_iterator4.s(); !(_step4 = _iterator4.n()).done;) {
+            var header = _step4.value;
+
+            if (regexp.test(header)) {
+              return true;
+            }
+          }
+        } catch (err) {
+          _iterator4.e(err);
+        } finally {
+          _iterator4.f();
+        }
+      }
+
+      return false;
+    }
+    /**
+     * Parse the current body as a SDP and store the resulting object
+     * into this.sdp.
+     * -param {Boolean} force: Parse even if this.sdp already exists.
+     *
+     * Returns this.sdp.
+     */
+
+  }, {
+    key: "parseSDP",
+    value: function parseSDP(force) {
+      if (!force && this.sdp) {
+        return this.sdp;
+      } else {
+        this.sdp = sdp_transform.parse(this.body || '');
+        return this.sdp;
+      }
+    }
+  }, {
+    key: "toString",
+    value: function toString() {
+      var msg = "".concat(this.method, " ").concat(this.ruri, " SIP/2.0\r\n");
+
+      for (var headerName in this.headers) {
+        if (Object.prototype.hasOwnProperty.call(this.headers, headerName)) {
+          var _iterator5 = _createForOfIteratorHelper(this.headers[headerName]),
+              _step5;
+
+          try {
+            for (_iterator5.s(); !(_step5 = _iterator5.n()).done;) {
+              var headerValue = _step5.value;
+              msg += "".concat(headerName, ": ").concat(headerValue, "\r\n");
+            }
+          } catch (err) {
+            _iterator5.e(err);
+          } finally {
+            _iterator5.f();
+          }
+        }
+      }
+
+      var _iterator6 = _createForOfIteratorHelper(this.extraHeaders),
+          _step6;
+
+      try {
+        for (_iterator6.s(); !(_step6 = _iterator6.n()).done;) {
+          var header = _step6.value;
+          msg += "".concat(header.trim(), "\r\n");
+        } // Supported.
+
+      } catch (err) {
+        _iterator6.e(err);
+      } finally {
+        _iterator6.f();
+      }
+
+      var supported = [];
+
+      switch (this.method) {
+        case JsSIP_C.REGISTER:
+          supported.push('path', 'gruu');
+          break;
+
+        case JsSIP_C.INVITE:
+          if (this.ua.configuration.session_timers) {
+            supported.push('timer');
+          }
+
+          if (this.ua.contact.pub_gruu || this.ua.contact.temp_gruu) {
+            supported.push('gruu');
+          }
+
+          supported.push('ice', 'replaces');
+          break;
+
+        case JsSIP_C.UPDATE:
+          if (this.ua.configuration.session_timers) {
+            supported.push('timer');
+          }
+
+          supported.push('ice');
+          break;
+      }
+
+      supported.push('outbound');
+      var userAgent = this.ua.configuration.user_agent || JsSIP_C.USER_AGENT; // Allow.
+
+      msg += "Allow: ".concat(JsSIP_C.ALLOWED_METHODS, "\r\n");
+      msg += "Supported: ".concat(supported, "\r\n");
+      msg += "User-Agent: ".concat(userAgent, "\r\n");
+
+      if (this.body) {
+        var length = Utils.str_utf8_length(this.body);
+        msg += "Content-Length: ".concat(length, "\r\n\r\n");
+        msg += this.body;
+      } else {
+        msg += 'Content-Length: 0\r\n\r\n';
+      }
+
+      return msg;
+    }
+  }, {
+    key: "clone",
+    value: function clone() {
+      var request = new OutgoingRequest(this.method, this.ruri, this.ua);
+      Object.keys(this.headers).forEach(function (name) {
+        request.headers[name] = this.headers[name].slice();
+      }, this);
+      request.body = this.body;
+      request.extraHeaders = Utils.cloneArray(this.extraHeaders);
+      request.to = this.to;
+      request.from = this.from;
+      request.call_id = this.call_id;
+      request.cseq = this.cseq;
+      return request;
+    }
+  }]);
+
+  return OutgoingRequest;
+}();
+
+var InitialOutgoingInviteRequest = /*#__PURE__*/function (_OutgoingRequest) {
+  _inherits(InitialOutgoingInviteRequest, _OutgoingRequest);
+
+  var _super = _createSuper(InitialOutgoingInviteRequest);
+
+  function InitialOutgoingInviteRequest(ruri, ua, params, extraHeaders, body) {
+    var _this;
+
+    _classCallCheck(this, InitialOutgoingInviteRequest);
+
+    _this = _super.call(this, JsSIP_C.INVITE, ruri, ua, params, extraHeaders, body);
+    _this.transaction = null;
+    return _this;
+  }
+
+  _createClass(InitialOutgoingInviteRequest, [{
+    key: "cancel",
+    value: function cancel(reason) {
+      this.transaction.cancel(reason);
+    }
+  }, {
+    key: "clone",
+    value: function clone() {
+      var request = new InitialOutgoingInviteRequest(this.ruri, this.ua);
+      Object.keys(this.headers).forEach(function (name) {
+        request.headers[name] = this.headers[name].slice();
+      }, this);
+      request.body = this.body;
+      request.extraHeaders = Utils.cloneArray(this.extraHeaders);
+      request.to = this.to;
+      request.from = this.from;
+      request.call_id = this.call_id;
+      request.cseq = this.cseq;
+      request.transaction = this.transaction;
+      return request;
+    }
+  }]);
+
+  return InitialOutgoingInviteRequest;
+}(OutgoingRequest);
+
+var IncomingMessage = /*#__PURE__*/function () {
+  function IncomingMessage() {
+    _classCallCheck(this, IncomingMessage);
+
+    this.data = null;
+    this.headers = null;
+    this.method = null;
+    this.via = null;
+    this.via_branch = null;
+    this.call_id = null;
+    this.cseq = null;
+    this.from = null;
+    this.from_tag = null;
+    this.to = null;
+    this.to_tag = null;
+    this.body = null;
+    this.sdp = null;
+  }
+  /**
+  * Insert a header of the given name and value into the last position of the
+  * header array.
+  */
+
+
+  _createClass(IncomingMessage, [{
+    key: "addHeader",
+    value: function addHeader(name, value) {
+      var header = {
+        raw: value
+      };
+      name = Utils.headerize(name);
+
+      if (this.headers[name]) {
+        this.headers[name].push(header);
+      } else {
+        this.headers[name] = [header];
+      }
+    }
+    /**
+     * Get the value of the given header name at the given position.
+     */
+
+  }, {
+    key: "getHeader",
+    value: function getHeader(name) {
+      var header = this.headers[Utils.headerize(name)];
+
+      if (header) {
+        if (header[0]) {
+          return header[0].raw;
+        }
+      } else {
+        return;
+      }
+    }
+    /**
+     * Get the header/s of the given name.
+     */
+
+  }, {
+    key: "getHeaders",
+    value: function getHeaders(name) {
+      var headers = this.headers[Utils.headerize(name)];
+      var result = [];
+
+      if (!headers) {
+        return [];
+      }
+
+      var _iterator7 = _createForOfIteratorHelper(headers),
+          _step7;
+
+      try {
+        for (_iterator7.s(); !(_step7 = _iterator7.n()).done;) {
+          var header = _step7.value;
+          result.push(header.raw);
+        }
+      } catch (err) {
+        _iterator7.e(err);
+      } finally {
+        _iterator7.f();
+      }
+
+      return result;
+    }
+    /**
+     * Verify the existence of the given header.
+     */
+
+  }, {
+    key: "hasHeader",
+    value: function hasHeader(name) {
+      return this.headers[Utils.headerize(name)] ? true : false;
+    }
+    /**
+    * Parse the given header on the given index.
+    * -param {String} name header name
+    * -param {Number} [idx=0] header index
+    * -returns {Object|undefined} Parsed header object, undefined if the header
+    *  is not present or in case of a parsing error.
+    */
+
+  }, {
+    key: "parseHeader",
+    value: function parseHeader(name) {
+      var idx = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;
+      name = Utils.headerize(name);
+
+      if (!this.headers[name]) {
+        logger.debug("header \"".concat(name, "\" not present"));
+        return;
+      } else if (idx >= this.headers[name].length) {
+        logger.debug("not so many \"".concat(name, "\" headers present"));
+        return;
+      }
+
+      var header = this.headers[name][idx];
+      var value = header.raw;
+
+      if (header.parsed) {
+        return header.parsed;
+      } // Substitute '-' by '_' for grammar rule matching.
+
+
+      var parsed = Grammar.parse(value, name.replace(/-/g, '_'));
+
+      if (parsed === -1) {
+        this.headers[name].splice(idx, 1); // delete from headers
+
+        logger.debug("error parsing \"".concat(name, "\" header field with value \"").concat(value, "\""));
+        return;
+      } else {
+        header.parsed = parsed;
+        return parsed;
+      }
+    }
+    /**
+     * Message Header attribute selector. Alias of parseHeader.
+     * -param {String} name header name
+     * -param {Number} [idx=0] header index
+     * -returns {Object|undefined} Parsed header object, undefined if the header
+     *  is not present or in case of a parsing error.
+     *
+     * -example
+     * message.s('via',3).port
+     */
+
+  }, {
+    key: "s",
+    value: function s(name, idx) {
+      return this.parseHeader(name, idx);
+    }
+    /**
+    * Replace the value of the given header by the value.
+    * -param {String} name header name
+    * -param {String} value header value
+    */
+
+  }, {
+    key: "setHeader",
+    value: function setHeader(name, value) {
+      var header = {
+        raw: value
+      };
+      this.headers[Utils.headerize(name)] = [header];
+    }
+    /**
+     * Parse the current body as a SDP and store the resulting object
+     * into this.sdp.
+     * -param {Boolean} force: Parse even if this.sdp already exists.
+     *
+     * Returns this.sdp.
+     */
+
+  }, {
+    key: "parseSDP",
+    value: function parseSDP(force) {
+      if (!force && this.sdp) {
+        return this.sdp;
+      } else {
+        this.sdp = sdp_transform.parse(this.body || '');
+        return this.sdp;
+      }
+    }
+  }, {
+    key: "toString",
+    value: function toString() {
+      return this.data;
+    }
+  }]);
+
+  return IncomingMessage;
+}();
+
+var IncomingRequest = /*#__PURE__*/function (_IncomingMessage) {
+  _inherits(IncomingRequest, _IncomingMessage);
+
+  var _super2 = _createSuper(IncomingRequest);
+
+  function IncomingRequest(ua) {
+    var _this2;
+
+    _classCallCheck(this, IncomingRequest);
+
+    _this2 = _super2.call(this);
+    _this2.ua = ua;
+    _this2.headers = {};
+    _this2.ruri = null;
+    _this2.transport = null;
+    _this2.server_transaction = null;
+    return _this2;
+  }
+  /**
+  * Stateful reply.
+  * -param {Number} code status code
+  * -param {String} reason reason phrase
+  * -param {Object} headers extra headers
+  * -param {String} body body
+  * -param {Function} [onSuccess] onSuccess callback
+  * -param {Function} [onFailure] onFailure callback
+  */
+
+
+  _createClass(IncomingRequest, [{
+    key: "reply",
+    value: function reply(code, reason, extraHeaders, body, onSuccess, onFailure) {
+      var supported = [];
+      var to = this.getHeader('To');
+      code = code || null;
+      reason = reason || null; // Validate code and reason values.
+
+      if (!code || code < 100 || code > 699) {
+        throw new TypeError("Invalid status_code: ".concat(code));
+      } else if (reason && typeof reason !== 'string' && !(reason instanceof String)) {
+        throw new TypeError("Invalid reason_phrase: ".concat(reason));
+      }
+
+      reason = reason || JsSIP_C.REASON_PHRASE[code] || '';
+      extraHeaders = Utils.cloneArray(extraHeaders);
+
+      if (this.ua.configuration.extra_headers) {
+        extraHeaders = extraHeaders.concat(this.ua.configuration.extra_headers);
+      }
+
+      var response = "SIP/2.0 ".concat(code, " ").concat(reason, "\r\n");
+
+      if (this.method === JsSIP_C.INVITE && code > 100 && code <= 200) {
+        var headers = this.getHeaders('record-route');
+
+        var _iterator8 = _createForOfIteratorHelper(headers),
+            _step8;
+
+        try {
+          for (_iterator8.s(); !(_step8 = _iterator8.n()).done;) {
+            var header = _step8.value;
+            response += "Record-Route: ".concat(header, "\r\n");
+          }
+        } catch (err) {
+          _iterator8.e(err);
+        } finally {
+          _iterator8.f();
+        }
+      }
+
+      var vias = this.getHeaders('via');
+
+      var _iterator9 = _createForOfIteratorHelper(vias),
+          _step9;
+
+      try {
+        for (_iterator9.s(); !(_step9 = _iterator9.n()).done;) {
+          var via = _step9.value;
+          response += "Via: ".concat(via, "\r\n");
+        }
+      } catch (err) {
+        _iterator9.e(err);
+      } finally {
+        _iterator9.f();
+      }
+
+      if (!this.to_tag && code > 100) {
+        to += ";tag=".concat(Utils.newTag());
+      } else if (this.to_tag && !this.s('to').hasParam('tag')) {
+        to += ";tag=".concat(this.to_tag);
+      }
+
+      response += "To: ".concat(to, "\r\n");
+      response += "From: ".concat(this.getHeader('From'), "\r\n");
+      response += "Call-ID: ".concat(this.call_id, "\r\n");
+      response += "CSeq: ".concat(this.cseq, " ").concat(this.method, "\r\n");
+
+      var _iterator10 = _createForOfIteratorHelper(extraHeaders),
+          _step10;
+
+      try {
+        for (_iterator10.s(); !(_step10 = _iterator10.n()).done;) {
+          var _header2 = _step10.value;
+          response += "".concat(_header2.trim(), "\r\n");
+        } // Supported.
+
+      } catch (err) {
+        _iterator10.e(err);
+      } finally {
+        _iterator10.f();
+      }
+
+      switch (this.method) {
+        case JsSIP_C.INVITE:
+          if (this.ua.configuration.session_timers) {
+            supported.push('timer');
+          }
+
+          if (this.ua.contact.pub_gruu || this.ua.contact.temp_gruu) {
+            supported.push('gruu');
+          }
+
+          supported.push('ice', 'replaces');
+          break;
+
+        case JsSIP_C.UPDATE:
+          if (this.ua.configuration.session_timers) {
+            supported.push('timer');
+          }
+
+          if (body) {
+            supported.push('ice');
+          }
+
+          supported.push('replaces');
+      }
+
+      supported.push('outbound'); // Allow and Accept.
+
+      if (this.method === JsSIP_C.OPTIONS) {
+        response += "Allow: ".concat(JsSIP_C.ALLOWED_METHODS, "\r\n");
+        response += "Accept: ".concat(JsSIP_C.ACCEPTED_BODY_TYPES, "\r\n");
+      } else if (code === 405) {
+        response += "Allow: ".concat(JsSIP_C.ALLOWED_METHODS, "\r\n");
+      } else if (code === 415) {
+        response += "Accept: ".concat(JsSIP_C.ACCEPTED_BODY_TYPES, "\r\n");
+      }
+
+      response += "Supported: ".concat(supported, "\r\n");
+
+      if (body) {
+        var length = Utils.str_utf8_length(body);
+        response += 'Content-Type: application/sdp\r\n';
+        response += "Content-Length: ".concat(length, "\r\n\r\n");
+        response += body;
+      } else {
+        response += "Content-Length: ".concat(0, "\r\n\r\n");
+      }
+
+      this.server_transaction.receiveResponse(code, response, onSuccess, onFailure);
+    }
+    /**
+    * Stateless reply.
+    * -param {Number} code status code
+    * -param {String} reason reason phrase
+    */
+
+  }, {
+    key: "reply_sl",
+    value: function reply_sl() {
+      var code = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null;
+      var reason = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;
+      var vias = this.getHeaders('via'); // Validate code and reason values.
+
+      if (!code || code < 100 || code > 699) {
+        throw new TypeError("Invalid status_code: ".concat(code));
+      } else if (reason && typeof reason !== 'string' && !(reason instanceof String)) {
+        throw new TypeError("Invalid reason_phrase: ".concat(reason));
+      }
+
+      reason = reason || JsSIP_C.REASON_PHRASE[code] || '';
+      var response = "SIP/2.0 ".concat(code, " ").concat(reason, "\r\n");
+
+      var _iterator11 = _createForOfIteratorHelper(vias),
+          _step11;
+
+      try {
+        for (_iterator11.s(); !(_step11 = _iterator11.n()).done;) {
+          var via = _step11.value;
+          response += "Via: ".concat(via, "\r\n");
+        }
+      } catch (err) {
+        _iterator11.e(err);
+      } finally {
+        _iterator11.f();
+      }
+
+      var to = this.getHeader('To');
+
+      if (!this.to_tag && code > 100) {
+        to += ";tag=".concat(Utils.newTag());
+      } else if (this.to_tag && !this.s('to').hasParam('tag')) {
+        to += ";tag=".concat(this.to_tag);
+      }
+
+      response += "To: ".concat(to, "\r\n");
+      response += "From: ".concat(this.getHeader('From'), "\r\n");
+      response += "Call-ID: ".concat(this.call_id, "\r\n");
+      response += "CSeq: ".concat(this.cseq, " ").concat(this.method, "\r\n");
+
+      if (this.ua.configuration.extra_headers) {
+        var _iterator12 = _createForOfIteratorHelper(this.ua.configuration.extra_headers),
+            _step12;
+
+        try {
+          for (_iterator12.s(); !(_step12 = _iterator12.n()).done;) {
+            var header = _step12.value;
+            response += "".concat(header.trim(), "\r\n");
+          }
+        } catch (err) {
+          _iterator12.e(err);
+        } finally {
+          _iterator12.f();
+        }
+      }
+
+      response += "Content-Length: ".concat(0, "\r\n\r\n");
+      this.transport.send(response);
+    }
+  }]);
+
+  return IncomingRequest;
+}(IncomingMessage);
+
+var IncomingResponse = /*#__PURE__*/function (_IncomingMessage2) {
+  _inherits(IncomingResponse, _IncomingMessage2);
+
+  var _super3 = _createSuper(IncomingResponse);
+
+  function IncomingResponse() {
+    var _this3;
+
+    _classCallCheck(this, IncomingResponse);
+
+    _this3 = _super3.call(this);
+    _this3.headers = {};
+    _this3.status_code = null;
+    _this3.reason_phrase = null;
+    return _this3;
+  }
+
+  return IncomingResponse;
+}(IncomingMessage);
+
+module.exports = {
+  OutgoingRequest: OutgoingRequest,
+  InitialOutgoingInviteRequest: InitialOutgoingInviteRequest,
+  IncomingRequest: IncomingRequest,
+  IncomingResponse: IncomingResponse
+};
+},{"./Constants":2,"./Grammar":7,"./Logger":9,"./NameAddrHeader":11,"./Utils":28,"sdp-transform":37}],22:[function(require,module,exports){
+"use strict";
+
+var Logger = require('./Logger');
+
+var Utils = require('./Utils');
+
+var Grammar = require('./Grammar');
+
+var logger = new Logger('Socket');
+/**
+ * Interface documentation: https://jssip.net/documentation/$last_version/api/socket/
+ *
+ * interface Socket {
+ *  attribute String via_transport
+ *  attribute String url
+ *  attribute String sip_uri
+ *
+ *  method connect();
+ *  method disconnect();
+ *  method send(data);
+ *
+ *  attribute EventHandler onconnect
+ *  attribute EventHandler ondisconnect
+ *  attribute EventHandler ondata
+ * }
+ *
+ */
+
+exports.isSocket = function (socket) {
+  // Ignore if an array is given.
+  if (Array.isArray(socket)) {
+    return false;
+  }
+
+  if (typeof socket === 'undefined') {
+    logger.warn('undefined JsSIP.Socket instance');
+    return false;
+  } // Check Properties.
+
+
+  try {
+    if (!Utils.isString(socket.url)) {
+      logger.warn('missing or invalid JsSIP.Socket url property');
+      throw new Error('Missing or invalid JsSIP.Socket url property');
+    }
+
+    if (!Utils.isString(socket.via_transport)) {
+      logger.warn('missing or invalid JsSIP.Socket via_transport property');
+      throw new Error('Missing or invalid JsSIP.Socket via_transport property');
+    }
+
+    if (Grammar.parse(socket.sip_uri, 'SIP_URI') === -1) {
+      logger.warn('missing or invalid JsSIP.Socket sip_uri property');
+      throw new Error('missing or invalid JsSIP.Socket sip_uri property');
+    }
+  } catch (e) {
+    return false;
+  } // Check Methods.
+
+
+  try {
+    ['connect', 'disconnect', 'send'].forEach(function (method) {
+      if (!Utils.isFunction(socket[method])) {
+        logger.warn("missing or invalid JsSIP.Socket method: ".concat(method));
+        throw new Error("Missing or invalid JsSIP.Socket method: ".concat(method));
+      }
+    });
+  } catch (e) {
+    return false;
+  }
+
+  return true;
+};
+},{"./Grammar":7,"./Logger":9,"./Utils":28}],23:[function(require,module,exports){
+"use strict";
+
+var T1 = 500,
+    T2 = 4000,
+    T4 = 5000;
+module.exports = {
+  T1: T1,
+  T2: T2,
+  T4: T4,
+  TIMER_B: 64 * T1,
+  TIMER_D: 0 * T1,
+  TIMER_F: 64 * T1,
+  TIMER_H: 64 * T1,
+  TIMER_I: 0 * T1,
+  TIMER_J: 0 * T1,
+  TIMER_K: 0 * T4,
+  TIMER_L: 64 * T1,
+  TIMER_M: 64 * T1,
+  PROVISIONAL_RESPONSE_INTERVAL: 60000 // See RFC 3261 Section 13.3.1.1
+
+};
+},{}],24:[function(require,module,exports){
+"use strict";
+
+function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
+
+function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
+
+function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); }
+
+function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }
+
+function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; }
+
+function _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } return _assertThisInitialized(self); }
+
+function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; }
+
+function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Date.prototype.toString.call(Reflect.construct(Date, [], function () {})); return true; } catch (e) { return false; } }
+
+function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }
+
+var EventEmitter = require('events').EventEmitter;
+
+var Logger = require('./Logger');
+
+var JsSIP_C = require('./Constants');
+
+var SIPMessage = require('./SIPMessage');
+
+var Timers = require('./Timers');
+
+var loggernict = new Logger('NonInviteClientTransaction');
+var loggerict = new Logger('InviteClientTransaction');
+var loggeract = new Logger('AckClientTransaction');
+var loggernist = new Logger('NonInviteServerTransaction');
+var loggerist = new Logger('InviteServerTransaction');
+var C = {
+  // Transaction states.
+  STATUS_TRYING: 1,
+  STATUS_PROCEEDING: 2,
+  STATUS_CALLING: 3,
+  STATUS_ACCEPTED: 4,
+  STATUS_COMPLETED: 5,
+  STATUS_TERMINATED: 6,
+  STATUS_CONFIRMED: 7,
+  // Transaction types.
+  NON_INVITE_CLIENT: 'nict',
+  NON_INVITE_SERVER: 'nist',
+  INVITE_CLIENT: 'ict',
+  INVITE_SERVER: 'ist'
+};
+
+var NonInviteClientTransaction = /*#__PURE__*/function (_EventEmitter) {
+  _inherits(NonInviteClientTransaction, _EventEmitter);
+
+  var _super = _createSuper(NonInviteClientTransaction);
+
+  function NonInviteClientTransaction(ua, transport, request, eventHandlers) {
+    var _this;
+
+    _classCallCheck(this, NonInviteClientTransaction);
+
+    _this = _super.call(this);
+    _this.type = C.NON_INVITE_CLIENT;
+    _this.id = "z9hG4bK".concat(Math.floor(Math.random() * 10000000));
+    _this.ua = ua;
+    _this.transport = transport;
+    _this.request = request;
+    _this.eventHandlers = eventHandlers;
+    var via = "SIP/2.0/".concat(transport.via_transport);
+    via += " ".concat(ua.configuration.via_host, ";branch=").concat(_this.id);
+
+    _this.request.setHeader('via', via);
+
+    _this.ua.newTransaction(_assertThisInitialized(_this));
+
+    return _this;
+  }
+
+  _createClass(NonInviteClientTransaction, [{
+    key: "stateChanged",
+    value: function stateChanged(state) {
+      this.state = state;
+      this.emit('stateChanged');
+    }
+  }, {
+    key: "send",
+    value: function send() {
+      var _this2 = this;
+
+      this.stateChanged(C.STATUS_TRYING);
+      this.F = setTimeout(function () {
+        _this2.timer_F();
+      }, Timers.TIMER_F);
+
+      if (!this.transport.send(this.request)) {
+        this.onTransportError();
+      }
+    }
+  }, {
+    key: "onTransportError",
+    value: function onTransportError() {
+      loggernict.debug("transport error occurred, deleting transaction ".concat(this.id));
+      clearTimeout(this.F);
+      clearTimeout(this.K);
+      this.stateChanged(C.STATUS_TERMINATED);
+      this.ua.destroyTransaction(this);
+      this.eventHandlers.onTransportError();
+    }
+  }, {
+    key: "timer_F",
+    value: function timer_F() {
+      loggernict.debug("Timer F expired for transaction ".concat(this.id));
+      this.stateChanged(C.STATUS_TERMINATED);
+      this.ua.destroyTransaction(this);
+      this.eventHandlers.onRequestTimeout();
+    }
+  }, {
+    key: "timer_K",
+    value: function timer_K() {
+      this.stateChanged(C.STATUS_TERMINATED);
+      this.ua.destroyTransaction(this);
+    }
+  }, {
+    key: "receiveResponse",
+    value: function receiveResponse(response) {
+      var _this3 = this;
+
+      var status_code = response.status_code;
+
+      if (status_code < 200) {
+        switch (this.state) {
+          case C.STATUS_TRYING:
+          case C.STATUS_PROCEEDING:
+            this.stateChanged(C.STATUS_PROCEEDING);
+            this.eventHandlers.onReceiveResponse(response);
+            break;
+        }
+      } else {
+        switch (this.state) {
+          case C.STATUS_TRYING:
+          case C.STATUS_PROCEEDING:
+            this.stateChanged(C.STATUS_COMPLETED);
+            clearTimeout(this.F);
+
+            if (status_code === 408) {
+              this.eventHandlers.onRequestTimeout();
+            } else {
+              this.eventHandlers.onReceiveResponse(response);
+            }
+
+            this.K = setTimeout(function () {
+              _this3.timer_K();
+            }, Timers.TIMER_K);
+            break;
+
+          case C.STATUS_COMPLETED:
+            break;
+        }
+      }
+    }
+  }, {
+    key: "C",
+    get: function get() {
+      return C;
+    }
+  }]);
+
+  return NonInviteClientTransaction;
+}(EventEmitter);
+
+var InviteClientTransaction = /*#__PURE__*/function (_EventEmitter2) {
+  _inherits(InviteClientTransaction, _EventEmitter2);
+
+  var _super2 = _createSuper(InviteClientTransaction);
+
+  function InviteClientTransaction(ua, transport, request, eventHandlers) {
+    var _this4;
+
+    _classCallCheck(this, InviteClientTransaction);
+
+    _this4 = _super2.call(this);
+    _this4.type = C.INVITE_CLIENT;
+    _this4.id = "z9hG4bK".concat(Math.floor(Math.random() * 10000000));
+    _this4.ua = ua;
+    _this4.transport = transport;
+    _this4.request = request;
+    _this4.eventHandlers = eventHandlers;
+    request.transaction = _assertThisInitialized(_this4);
+    var via = "SIP/2.0/".concat(transport.via_transport);
+    via += " ".concat(ua.configuration.via_host, ";branch=").concat(_this4.id);
+
+    _this4.request.setHeader('via', via);
+
+    _this4.ua.newTransaction(_assertThisInitialized(_this4));
+
+    return _this4;
+  }
+
+  _createClass(InviteClientTransaction, [{
+    key: "stateChanged",
+    value: function stateChanged(state) {
+      this.state = state;
+      this.emit('stateChanged');
+    }
+  }, {
+    key: "send",
+    value: function send() {
+      var _this5 = this;
+
+      this.stateChanged(C.STATUS_CALLING);
+      this.B = setTimeout(function () {
+        _this5.timer_B();
+      }, Timers.TIMER_B);
+
+      if (!this.transport.send(this.request)) {
+        this.onTransportError();
+      }
+    }
+  }, {
+    key: "onTransportError",
+    value: function onTransportError() {
+      clearTimeout(this.B);
+      clearTimeout(this.D);
+      clearTimeout(this.M);
+
+      if (this.state !== C.STATUS_ACCEPTED) {
+        loggerict.debug("transport error occurred, deleting transaction ".concat(this.id));
+        this.eventHandlers.onTransportError();
+      }
+
+      this.stateChanged(C.STATUS_TERMINATED);
+      this.ua.destroyTransaction(this);
+    } // RFC 6026 7.2.
+
+  }, {
+    key: "timer_M",
+    value: function timer_M() {
+      loggerict.debug("Timer M expired for transaction ".concat(this.id));
+
+      if (this.state === C.STATUS_ACCEPTED) {
+        clearTimeout(this.B);
+        this.stateChanged(C.STATUS_TERMINATED);
+        this.ua.destroyTransaction(this);
+      }
+    } // RFC 3261 17.1.1.
+
+  }, {
+    key: "timer_B",
+    value: function timer_B() {
+      loggerict.debug("Timer B expired for transaction ".concat(this.id));
+
+      if (this.state === C.STATUS_CALLING) {
+        this.stateChanged(C.STATUS_TERMINATED);
+        this.ua.destroyTransaction(this);
+        this.eventHandlers.onRequestTimeout();
+      }
+    }
+  }, {
+    key: "timer_D",
+    value: function timer_D() {
+      loggerict.debug("Timer D expired for transaction ".concat(this.id));
+      clearTimeout(this.B);
+      this.stateChanged(C.STATUS_TERMINATED);
+      this.ua.destroyTransaction(this);
+    }
+  }, {
+    key: "sendACK",
+    value: function sendACK(response) {
+      var _this6 = this;
+
+      var ack = new SIPMessage.OutgoingRequest(JsSIP_C.ACK, this.request.ruri, this.ua, {
+        'route_set': this.request.getHeaders('route'),
+        'call_id': this.request.getHeader('call-id'),
+        'cseq': this.request.cseq
+      });
+      ack.setHeader('from', this.request.getHeader('from'));
+      ack.setHeader('via', this.request.getHeader('via'));
+      ack.setHeader('to', response.getHeader('to'));
+      this.D = setTimeout(function () {
+        _this6.timer_D();
+      }, Timers.TIMER_D);
+      this.transport.send(ack);
+    }
+  }, {
+    key: "cancel",
+    value: function cancel(reason) {
+      // Send only if a provisional response (>100) has been received.
+      if (this.state !== C.STATUS_PROCEEDING) {
+        return;
+      }
+
+      var cancel = new SIPMessage.OutgoingRequest(JsSIP_C.CANCEL, this.request.ruri, this.ua, {
+        'route_set': this.request.getHeaders('route'),
+        'call_id': this.request.getHeader('call-id'),
+        'cseq': this.request.cseq
+      });
+      cancel.setHeader('from', this.request.getHeader('from'));
+      cancel.setHeader('via', this.request.getHeader('via'));
+      cancel.setHeader('to', this.request.getHeader('to'));
+
+      if (reason) {
+        cancel.setHeader('reason', reason);
+      }
+
+      this.transport.send(cancel);
+    }
+  }, {
+    key: "receiveResponse",
+    value: function receiveResponse(response) {
+      var _this7 = this;
+
+      var status_code = response.status_code;
+
+      if (status_code >= 100 && status_code <= 199) {
+        switch (this.state) {
+          case C.STATUS_CALLING:
+            this.stateChanged(C.STATUS_PROCEEDING);
+            this.eventHandlers.onReceiveResponse(response);
+            break;
+
+          case C.STATUS_PROCEEDING:
+            this.eventHandlers.onReceiveResponse(response);
+            break;
+        }
+      } else if (status_code >= 200 && status_code <= 299) {
+        switch (this.state) {
+          case C.STATUS_CALLING:
+          case C.STATUS_PROCEEDING:
+            this.stateChanged(C.STATUS_ACCEPTED);
+            this.M = setTimeout(function () {
+              _this7.timer_M();
+            }, Timers.TIMER_M);
+            this.eventHandlers.onReceiveResponse(response);
+            break;
+
+          case C.STATUS_ACCEPTED:
+            this.eventHandlers.onReceiveResponse(response);
+            break;
+        }
+      } else if (status_code >= 300 && status_code <= 699) {
+        switch (this.state) {
+          case C.STATUS_CALLING:
+          case C.STATUS_PROCEEDING:
+            this.stateChanged(C.STATUS_COMPLETED);
+            this.sendACK(response);
+            this.eventHandlers.onReceiveResponse(response);
+            break;
+
+          case C.STATUS_COMPLETED:
+            this.sendACK(response);
+            break;
+        }
+      }
+    }
+  }, {
+    key: "C",
+    get: function get() {
+      return C;
+    }
+  }]);
+
+  return InviteClientTransaction;
+}(EventEmitter);
+
+var AckClientTransaction = /*#__PURE__*/function (_EventEmitter3) {
+  _inherits(AckClientTransaction, _EventEmitter3);
+
+  var _super3 = _createSuper(AckClientTransaction);
+
+  function AckClientTransaction(ua, transport, request, eventHandlers) {
+    var _this8;
+
+    _classCallCheck(this, AckClientTransaction);
+
+    _this8 = _super3.call(this);
+    _this8.id = "z9hG4bK".concat(Math.floor(Math.random() * 10000000));
+    _this8.transport = transport;
+    _this8.request = request;
+    _this8.eventHandlers = eventHandlers;
+    var via = "SIP/2.0/".concat(transport.via_transport);
+    via += " ".concat(ua.configuration.via_host, ";branch=").concat(_this8.id);
+
+    _this8.request.setHeader('via', via);
+
+    return _this8;
+  }
+
+  _createClass(AckClientTransaction, [{
+    key: "send",
+    value: function send() {
+      if (!this.transport.send(this.request)) {
+        this.onTransportError();
+      }
+    }
+  }, {
+    key: "onTransportError",
+    value: function onTransportError() {
+      loggeract.debug("transport error occurred for transaction ".concat(this.id));
+      this.eventHandlers.onTransportError();
+    }
+  }, {
+    key: "C",
+    get: function get() {
+      return C;
+    }
+  }]);
+
+  return AckClientTransaction;
+}(EventEmitter);
+
+var NonInviteServerTransaction = /*#__PURE__*/function (_EventEmitter4) {
+  _inherits(NonInviteServerTransaction, _EventEmitter4);
+
+  var _super4 = _createSuper(NonInviteServerTransaction);
+
+  function NonInviteServerTransaction(ua, transport, request) {
+    var _this9;
+
+    _classCallCheck(this, NonInviteServerTransaction);
+
+    _this9 = _super4.call(this);
+    _this9.type = C.NON_INVITE_SERVER;
+    _this9.id = request.via_branch;
+    _this9.ua = ua;
+    _this9.transport = transport;
+    _this9.request = request;
+    _this9.last_response = '';
+    request.server_transaction = _assertThisInitialized(_this9);
+    _this9.state = C.STATUS_TRYING;
+    ua.newTransaction(_assertThisInitialized(_this9));
+    return _this9;
+  }
+
+  _createClass(NonInviteServerTransaction, [{
+    key: "stateChanged",
+    value: function stateChanged(state) {
+      this.state = state;
+      this.emit('stateChanged');
+    }
+  }, {
+    key: "timer_J",
+    value: function timer_J() {
+      loggernist.debug("Timer J expired for transaction ".concat(this.id));
+      this.stateChanged(C.STATUS_TERMINATED);
+      this.ua.destroyTransaction(this);
+    }
+  }, {
+    key: "onTransportError",
+    value: function onTransportError() {
+      if (!this.transportError) {
+        this.transportError = true;
+        loggernist.debug("transport error occurred, deleting transaction ".concat(this.id));
+        clearTimeout(this.J);
+        this.stateChanged(C.STATUS_TERMINATED);
+        this.ua.destroyTransaction(this);
+      }
+    }
+  }, {
+    key: "receiveResponse",
+    value: function receiveResponse(status_code, response, onSuccess, onFailure) {
+      var _this10 = this;
+
+      if (status_code === 100) {
+        /* RFC 4320 4.1
+         * 'A SIP element MUST NOT
+         * send any provisional response with a
+         * Status-Code other than 100 to a non-INVITE request.'
+         */
+        switch (this.state) {
+          case C.STATUS_TRYING:
+            this.stateChanged(C.STATUS_PROCEEDING);
+
+            if (!this.transport.send(response)) {
+              this.onTransportError();
+            }
+
+            break;
+
+          case C.STATUS_PROCEEDING:
+            this.last_response = response;
+
+            if (!this.transport.send(response)) {
+              this.onTransportError();
+
+              if (onFailure) {
+                onFailure();
+              }
+            } else if (onSuccess) {
+              onSuccess();
+            }
+
+            break;
+        }
+      } else if (status_code >= 200 && status_code <= 699) {
+        switch (this.state) {
+          case C.STATUS_TRYING:
+          case C.STATUS_PROCEEDING:
+            this.stateChanged(C.STATUS_COMPLETED);
+            this.last_response = response;
+            this.J = setTimeout(function () {
+              _this10.timer_J();
+            }, Timers.TIMER_J);
+
+            if (!this.transport.send(response)) {
+              this.onTransportError();
+
+              if (onFailure) {
+                onFailure();
+              }
+            } else if (onSuccess) {
+              onSuccess();
+            }
+
+            break;
+
+          case C.STATUS_COMPLETED:
+            break;
+        }
+      }
+    }
+  }, {
+    key: "C",
+    get: function get() {
+      return C;
+    }
+  }]);
+
+  return NonInviteServerTransaction;
+}(EventEmitter);
+
+var InviteServerTransaction = /*#__PURE__*/function (_EventEmitter5) {
+  _inherits(InviteServerTransaction, _EventEmitter5);
+
+  var _super5 = _createSuper(InviteServerTransaction);
+
+  function InviteServerTransaction(ua, transport, request) {
+    var _this11;
+
+    _classCallCheck(this, InviteServerTransaction);
+
+    _this11 = _super5.call(this);
+    _this11.type = C.INVITE_SERVER;
+    _this11.id = request.via_branch;
+    _this11.ua = ua;
+    _this11.transport = transport;
+    _this11.request = request;
+    _this11.last_response = '';
+    request.server_transaction = _assertThisInitialized(_this11);
+    _this11.state = C.STATUS_PROCEEDING;
+    ua.newTransaction(_assertThisInitialized(_this11));
+    _this11.resendProvisionalTimer = null;
+    request.reply(100);
+    return _this11;
+  }
+
+  _createClass(InviteServerTransaction, [{
+    key: "stateChanged",
+    value: function stateChanged(state) {
+      this.state = state;
+      this.emit('stateChanged');
+    }
+  }, {
+    key: "timer_H",
+    value: function timer_H() {
+      loggerist.debug("Timer H expired for transaction ".concat(this.id));
+
+      if (this.state === C.STATUS_COMPLETED) {
+        loggerist.debug('ACK not received, dialog will be terminated');
+      }
+
+      this.stateChanged(C.STATUS_TERMINATED);
+      this.ua.destroyTransaction(this);
+    }
+  }, {
+    key: "timer_I",
+    value: function timer_I() {
+      this.stateChanged(C.STATUS_TERMINATED);
+      this.ua.destroyTransaction(this);
+    } // RFC 6026 7.1.
+
+  }, {
+    key: "timer_L",
+    value: function timer_L() {
+      loggerist.debug("Timer L expired for transaction ".concat(this.id));
+
+      if (this.state === C.STATUS_ACCEPTED) {
+        this.stateChanged(C.STATUS_TERMINATED);
+        this.ua.destroyTransaction(this);
+      }
+    }
+  }, {
+    key: "onTransportError",
+    value: function onTransportError() {
+      if (!this.transportError) {
+        this.transportError = true;
+        loggerist.debug("transport error occurred, deleting transaction ".concat(this.id));
+
+        if (this.resendProvisionalTimer !== null) {
+          clearInterval(this.resendProvisionalTimer);
+          this.resendProvisionalTimer = null;
+        }
+
+        clearTimeout(this.L);
+        clearTimeout(this.H);
+        clearTimeout(this.I);
+        this.stateChanged(C.STATUS_TERMINATED);
+        this.ua.destroyTransaction(this);
+      }
+    }
+  }, {
+    key: "resend_provisional",
+    value: function resend_provisional() {
+      if (!this.transport.send(this.last_response)) {
+        this.onTransportError();
+      }
+    } // INVITE Server Transaction RFC 3261 17.2.1.
+
+  }, {
+    key: "receiveResponse",
+    value: function receiveResponse(status_code, response, onSuccess, onFailure) {
+      var _this12 = this;
+
+      if (status_code >= 100 && status_code <= 199) {
+        switch (this.state) {
+          case C.STATUS_PROCEEDING:
+            if (!this.transport.send(response)) {
+              this.onTransportError();
+            }
+
+            this.last_response = response;
+            break;
+        }
+      }
+
+      if (status_code > 100 && status_code <= 199 && this.state === C.STATUS_PROCEEDING) {
+        // Trigger the resendProvisionalTimer only for the first non 100 provisional response.
+        if (this.resendProvisionalTimer === null) {
+          this.resendProvisionalTimer = setInterval(function () {
+            _this12.resend_provisional();
+          }, Timers.PROVISIONAL_RESPONSE_INTERVAL);
+        }
+      } else if (status_code >= 200 && status_code <= 299) {
+        switch (this.state) {
+          case C.STATUS_PROCEEDING:
+            this.stateChanged(C.STATUS_ACCEPTED);
+            this.last_response = response;
+            this.L = setTimeout(function () {
+              _this12.timer_L();
+            }, Timers.TIMER_L);
+
+            if (this.resendProvisionalTimer !== null) {
+              clearInterval(this.resendProvisionalTimer);
+              this.resendProvisionalTimer = null;
+            }
+
+          /* falls through */
+
+          case C.STATUS_ACCEPTED:
+            // Note that this point will be reached for proceeding this.state also.
+            if (!this.transport.send(response)) {
+              this.onTransportError();
+
+              if (onFailure) {
+                onFailure();
+              }
+            } else if (onSuccess) {
+              onSuccess();
+            }
+
+            break;
+        }
+      } else if (status_code >= 300 && status_code <= 699) {
+        switch (this.state) {
+          case C.STATUS_PROCEEDING:
+            if (this.resendProvisionalTimer !== null) {
+              clearInterval(this.resendProvisionalTimer);
+              this.resendProvisionalTimer = null;
+            }
+
+            if (!this.transport.send(response)) {
+              this.onTransportError();
+
+              if (onFailure) {
+                onFailure();
+              }
+            } else {
+              this.stateChanged(C.STATUS_COMPLETED);
+              this.H = setTimeout(function () {
+                _this12.timer_H();
+              }, Timers.TIMER_H);
+
+              if (onSuccess) {
+                onSuccess();
+              }
+            }
+
+            break;
+        }
+      }
+    }
+  }, {
+    key: "C",
+    get: function get() {
+      return C;
+    }
+  }]);
+
+  return InviteServerTransaction;
+}(EventEmitter);
+/**
+ * INVITE:
+ *  _true_ if retransmission
+ *  _false_ new request
+ *
+ * ACK:
+ *  _true_  ACK to non2xx response
+ *  _false_ ACK must be passed to TU (accepted state)
+ *          ACK to 2xx response
+ *
+ * CANCEL:
+ *  _true_  no matching invite transaction
+ *  _false_ matching invite transaction and no final response sent
+ *
+ * OTHER:
+ *  _true_  retransmission
+ *  _false_ new request
+ */
+
+
+function checkTransaction(_ref, request) {
+  var _transactions = _ref._transactions;
+  var tr;
+
+  switch (request.method) {
+    case JsSIP_C.INVITE:
+      tr = _transactions.ist[request.via_branch];
+
+      if (tr) {
+        switch (tr.state) {
+          case C.STATUS_PROCEEDING:
+            tr.transport.send(tr.last_response);
+            break;
+          // RFC 6026 7.1 Invite retransmission.
+          // Received while in C.STATUS_ACCEPTED state. Absorb it.
+
+          case C.STATUS_ACCEPTED:
+            break;
+        }
+
+        return true;
+      }
+
+      break;
+
+    case JsSIP_C.ACK:
+      tr = _transactions.ist[request.via_branch]; // RFC 6026 7.1.
+
+      if (tr) {
+        if (tr.state === C.STATUS_ACCEPTED) {
+          return false;
+        } else if (tr.state === C.STATUS_COMPLETED) {
+          tr.state = C.STATUS_CONFIRMED;
+          tr.I = setTimeout(function () {
+            tr.timer_I();
+          }, Timers.TIMER_I);
+          return true;
+        }
+      } // ACK to 2XX Response.
+      else {
+          return false;
+        }
+
+      break;
+
+    case JsSIP_C.CANCEL:
+      tr = _transactions.ist[request.via_branch];
+
+      if (tr) {
+        request.reply_sl(200);
+
+        if (tr.state === C.STATUS_PROCEEDING) {
+          return false;
+        } else {
+          return true;
+        }
+      } else {
+        request.reply_sl(481);
+        return true;
+      }
+
+    default:
+      // Non-INVITE Server Transaction RFC 3261 17.2.2.
+      tr = _transactions.nist[request.via_branch];
+
+      if (tr) {
+        switch (tr.state) {
+          case C.STATUS_TRYING:
+            break;
+
+          case C.STATUS_PROCEEDING:
+          case C.STATUS_COMPLETED:
+            tr.transport.send(tr.last_response);
+            break;
+        }
+
+        return true;
+      }
+
+      break;
+  }
+}
+
+module.exports = {
+  C: C,
+  NonInviteClientTransaction: NonInviteClientTransaction,
+  InviteClientTransaction: InviteClientTransaction,
+  AckClientTransaction: AckClientTransaction,
+  NonInviteServerTransaction: NonInviteServerTransaction,
+  InviteServerTransaction: InviteServerTransaction,
+  checkTransaction: checkTransaction
+};
+},{"./Constants":2,"./Logger":9,"./SIPMessage":21,"./Timers":23,"events":31}],25:[function(require,module,exports){
+"use strict";
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
+
+function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
+
+var Logger = require('./Logger');
+
+var Socket = require('./Socket');
+
+var JsSIP_C = require('./Constants');
+
+var logger = new Logger('Transport');
+/**
+ * Constants
+ */
+
+var C = {
+  // Transport status.
+  STATUS_CONNECTED: 0,
+  STATUS_CONNECTING: 1,
+  STATUS_DISCONNECTED: 2,
+  // Socket status.
+  SOCKET_STATUS_READY: 0,
+  SOCKET_STATUS_ERROR: 1,
+  // Recovery options.
+  recovery_options: {
+    // minimum interval in seconds between recover attempts.
+    min_interval: JsSIP_C.CONNECTION_RECOVERY_MIN_INTERVAL,
+    // maximum interval in seconds between recover attempts.
+    max_interval: JsSIP_C.CONNECTION_RECOVERY_MAX_INTERVAL
+  }
+};
+/*
+ * Manages one or multiple JsSIP.Socket instances.
+ * Is reponsible for transport recovery logic among all socket instances.
+ *
+ * @socket JsSIP::Socket instance
+ */
+
+module.exports = /*#__PURE__*/function () {
+  function Transport(sockets) {
+    var recovery_options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : C.recovery_options;
+
+    _classCallCheck(this, Transport);
+
+    logger.debug('new()');
+    this.status = C.STATUS_DISCONNECTED; // Current socket.
+
+    this.socket = null; // Socket collection.
+
+    this.sockets = [];
+    this.recovery_options = recovery_options;
+    this.recover_attempts = 0;
+    this.recovery_timer = null;
+    this.close_requested = false; // It seems that TextDecoder is not available in some versions of React-Native.
+    // See https://github.com/versatica/JsSIP/issues/695
+
+    try {
+      this.textDecoder = new TextDecoder('utf8');
+    } catch (error) {
+      logger.warn("cannot use TextDecoder: ".concat(error));
+    }
+
+    if (typeof sockets === 'undefined') {
+      throw new TypeError('Invalid argument.' + ' undefined \'sockets\' argument');
+    }
+
+    if (!(sockets instanceof Array)) {
+      sockets = [sockets];
+    }
+
+    sockets.forEach(function (socket) {
+      if (!Socket.isSocket(socket.socket)) {
+        throw new TypeError('Invalid argument.' + ' invalid \'JsSIP.Socket\' instance');
+      }
+
+      if (socket.weight && !Number(socket.weight)) {
+        throw new TypeError('Invalid argument.' + ' \'weight\' attribute is not a number');
+      }
+
+      this.sockets.push({
+        socket: socket.socket,
+        weight: socket.weight || 0,
+        status: C.SOCKET_STATUS_READY
+      });
+    }, this); // Get the socket with higher weight.
+
+    this._getSocket();
+  }
+  /**
+   * Instance Methods
+   */
+
+
+  _createClass(Transport, [{
+    key: "connect",
+    value: function connect() {
+      logger.debug('connect()');
+
+      if (this.isConnected()) {
+        logger.debug('Transport is already connected');
+        return;
+      } else if (this.isConnecting()) {
+        logger.debug('Transport is connecting');
+        return;
+      }
+
+      this.close_requested = false;
+      this.status = C.STATUS_CONNECTING;
+      this.onconnecting({
+        socket: this.socket,
+        attempts: this.recover_attempts
+      });
+
+      if (!this.close_requested) {
+        // Bind socket event callbacks.
+        this.socket.onconnect = this._onConnect.bind(this);
+        this.socket.ondisconnect = this._onDisconnect.bind(this);
+        this.socket.ondata = this._onData.bind(this);
+        this.socket.connect();
+      }
+
+      return;
+    }
+  }, {
+    key: "disconnect",
+    value: function disconnect() {
+      logger.debug('close()');
+      this.close_requested = true;
+      this.recover_attempts = 0;
+      this.status = C.STATUS_DISCONNECTED; // Clear recovery_timer.
+
+      if (this.recovery_timer !== null) {
+        clearTimeout(this.recovery_timer);
+        this.recovery_timer = null;
+      } // Unbind socket event callbacks.
+
+
+      this.socket.onconnect = function () {};
+
+      this.socket.ondisconnect = function () {};
+
+      this.socket.ondata = function () {};
+
+      this.socket.disconnect();
+      this.ondisconnect({
+        socket: this.socket,
+        error: false
+      });
+    }
+  }, {
+    key: "send",
+    value: function send(data) {
+      logger.debug('send()');
+
+      if (!this.isConnected()) {
+        logger.warn('unable to send message, transport is not connected');
+        return false;
+      }
+
+      var message = data.toString();
+      logger.debug("sending message:\n\n".concat(message, "\n"));
+      return this.socket.send(message);
+    }
+  }, {
+    key: "isConnected",
+    value: function isConnected() {
+      return this.status === C.STATUS_CONNECTED;
+    }
+  }, {
+    key: "isConnecting",
+    value: function isConnecting() {
+      return this.status === C.STATUS_CONNECTING;
+    }
+    /**
+     * Private API.
+     */
+
+  }, {
+    key: "_reconnect",
+    value: function _reconnect() {
+      var _this = this;
+
+      this.recover_attempts += 1;
+      var k = Math.floor(Math.random() * Math.pow(2, this.recover_attempts) + 1);
+
+      if (k < this.recovery_options.min_interval) {
+        k = this.recovery_options.min_interval;
+      } else if (k > this.recovery_options.max_interval) {
+        k = this.recovery_options.max_interval;
+      }
+
+      logger.debug("reconnection attempt: ".concat(this.recover_attempts, ". next connection attempt in ").concat(k, " seconds"));
+      this.recovery_timer = setTimeout(function () {
+        if (!_this.close_requested && !(_this.isConnected() || _this.isConnecting())) {
+          // Get the next available socket with higher weight.
+          _this._getSocket(); // Connect the socket.
+
+
+          _this.connect();
+        }
+      }, k * 1000);
+    }
+    /**
+     * get the next available socket with higher weight
+     */
+
+  }, {
+    key: "_getSocket",
+    value: function _getSocket() {
+      var candidates = [];
+      this.sockets.forEach(function (socket) {
+        if (socket.status === C.SOCKET_STATUS_ERROR) {
+          return; // continue the array iteration
+        } else if (candidates.length === 0) {
+          candidates.push(socket);
+        } else if (socket.weight > candidates[0].weight) {
+          candidates = [socket];
+        } else if (socket.weight === candidates[0].weight) {
+          candidates.push(socket);
+        }
+      });
+
+      if (candidates.length === 0) {
+        // All sockets have failed. reset sockets status.
+        this.sockets.forEach(function (socket) {
+          socket.status = C.SOCKET_STATUS_READY;
+        }); // Get next available socket.
+
+        this._getSocket();
+
+        return;
+      }
+
+      var idx = Math.floor(Math.random() * candidates.length);
+      this.socket = candidates[idx].socket;
+    }
+    /**
+     * Socket Event Handlers
+     */
+
+  }, {
+    key: "_onConnect",
+    value: function _onConnect() {
+      this.recover_attempts = 0;
+      this.status = C.STATUS_CONNECTED; // Clear recovery_timer.
+
+      if (this.recovery_timer !== null) {
+        clearTimeout(this.recovery_timer);
+        this.recovery_timer = null;
+      }
+
+      this.onconnect({
+        socket: this
+      });
+    }
+  }, {
+    key: "_onDisconnect",
+    value: function _onDisconnect(error, code, reason) {
+      this.status = C.STATUS_DISCONNECTED;
+      this.ondisconnect({
+        socket: this.socket,
+        error: error,
+        code: code,
+        reason: reason
+      });
+
+      if (this.close_requested) {
+        return;
+      } // Update socket status.
+      else {
+          this.sockets.forEach(function (socket) {
+            if (this.socket === socket.socket) {
+              socket.status = C.SOCKET_STATUS_ERROR;
+            }
+          }, this);
+        }
+
+      this._reconnect(error);
+    }
+  }, {
+    key: "_onData",
+    value: function _onData(data) {
+      // CRLF Keep Alive response from server. Ignore it.
+      if (data === '\r\n') {
+        logger.debug('received message with CRLF Keep Alive response');
+        return;
+      } // Binary message.
+      else if (typeof data !== 'string') {
+          try {
+            if (this.textDecoder) data = this.textDecoder.decode(data);else data = String.fromCharCode.apply(null, new Uint8Array(data));
+          } catch (evt) {
+            logger.debug('received binary message failed to be converted into string,' + ' message discarded');
+            return;
+          }
+
+          logger.debug("received binary message:\n\n".concat(data, "\n"));
+        } // Text message.
+        else {
+            logger.debug("received text message:\n\n".concat(data, "\n"));
+          }
+
+      this.ondata({
+        transport: this,
+        message: data
+      });
+    }
+  }, {
+    key: "via_transport",
+    get: function get() {
+      return this.socket.via_transport;
+    }
+  }, {
+    key: "url",
+    get: function get() {
+      return this.socket.url;
+    }
+  }, {
+    key: "sip_uri",
+    get: function get() {
+      return this.socket.sip_uri;
+    }
+  }]);
+
+  return Transport;
+}();
+},{"./Constants":2,"./Logger":9,"./Socket":22}],26:[function(require,module,exports){
+"use strict";
+
+function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
+
+function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
+
+function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); }
+
+function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }
+
+function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; }
+
+function _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } return _assertThisInitialized(self); }
+
+function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; }
+
+function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Date.prototype.toString.call(Reflect.construct(Date, [], function () {})); return true; } catch (e) { return false; } }
+
+function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }
+
+var EventEmitter = require('events').EventEmitter;
+
+var Logger = require('./Logger');
+
+var JsSIP_C = require('./Constants');
+
+var Registrator = require('./Registrator');
+
+var RTCSession = require('./RTCSession');
+
+var Message = require('./Message');
+
+var Options = require('./Options');
+
+var Transactions = require('./Transactions');
+
+var Transport = require('./Transport');
+
+var Utils = require('./Utils');
+
+var Exceptions = require('./Exceptions');
+
+var URI = require('./URI');
+
+var Parser = require('./Parser');
+
+var SIPMessage = require('./SIPMessage');
+
+var sanityCheck = require('./sanityCheck');
+
+var config = require('./Config');
+
+var logger = new Logger('UA');
+var C = {
+  // UA status codes.
+  STATUS_INIT: 0,
+  STATUS_READY: 1,
+  STATUS_USER_CLOSED: 2,
+  STATUS_NOT_READY: 3,
+  // UA error codes.
+  CONFIGURATION_ERROR: 1,
+  NETWORK_ERROR: 2
+};
+/**
+ * The User-Agent class.
+ * @class JsSIP.UA
+ * @param {Object} configuration Configuration parameters.
+ * @throws {JsSIP.Exceptions.ConfigurationError} If a configuration parameter is invalid.
+ * @throws {TypeError} If no configuration is given.
+ */
+
+module.exports = /*#__PURE__*/function (_EventEmitter) {
+  _inherits(UA, _EventEmitter);
+
+  var _super = _createSuper(UA);
+
+  _createClass(UA, null, [{
+    key: "C",
+    // Expose C object.
+    get: function get() {
+      return C;
+    }
+  }]);
+
+  function UA(configuration) {
+    var _this;
+
+    _classCallCheck(this, UA);
+
+    logger.debug('new() [configuration:%o]', configuration);
+    _this = _super.call(this);
+    _this._cache = {
+      credentials: {}
+    };
+    _this._configuration = Object.assign({}, config.settings);
+    _this._dynConfiguration = {};
+    _this._dialogs = {}; // User actions outside any session/dialog (MESSAGE/OPTIONS).
+
+    _this._applicants = {};
+    _this._sessions = {};
+    _this._transport = null;
+    _this._contact = null;
+    _this._status = C.STATUS_INIT;
+    _this._error = null;
+    _this._transactions = {
+      nist: {},
+      nict: {},
+      ist: {},
+      ict: {}
+    }; // Custom UA empty object for high level use.
+
+    _this._data = {};
+    _this._closeTimer = null; // Check configuration argument.
+
+    if (configuration === undefined) {
+      throw new TypeError('Not enough arguments');
+    } // Load configuration.
+
+
+    try {
+      _this._loadConfig(configuration);
+    } catch (e) {
+      _this._status = C.STATUS_NOT_READY;
+      _this._error = C.CONFIGURATION_ERROR;
+      throw e;
+    } // Initialize registrator.
+
+
+    _this._registrator = new Registrator(_assertThisInitialized(_this));
+    return _this;
+  }
+
+  _createClass(UA, [{
+    key: "start",
+    // =================
+    //  High Level API
+    // =================
+
+    /**
+     * Connect to the server if status = STATUS_INIT.
+     * Resume UA after being closed.
+     */
+    value: function start() {
+      logger.debug('start()');
+
+      if (this._status === C.STATUS_INIT) {
+        this._transport.connect();
+      } else if (this._status === C.STATUS_USER_CLOSED) {
+        logger.debug('restarting UA'); // Disconnect.
+
+        if (this._closeTimer !== null) {
+          clearTimeout(this._closeTimer);
+          this._closeTimer = null;
+
+          this._transport.disconnect();
+        } // Reconnect.
+
+
+        this._status = C.STATUS_INIT;
+
+        this._transport.connect();
+      } else if (this._status === C.STATUS_READY) {
+        logger.debug('UA is in READY status, not restarted');
+      } else {
+        logger.debug('ERROR: connection is down, Auto-Recovery system is trying to reconnect');
+      } // Set dynamic configuration.
+
+
+      this._dynConfiguration.register = this._configuration.register;
+    }
+    /**
+     * Register.
+     */
+
+  }, {
+    key: "register",
+    value: function register() {
+      logger.debug('register()');
+      this._dynConfiguration.register = true;
+
+      this._registrator.register();
+    }
+    /**
+     * Unregister.
+     */
+
+  }, {
+    key: "unregister",
+    value: function unregister(options) {
+      logger.debug('unregister()');
+      this._dynConfiguration.register = false;
+
+      this._registrator.unregister(options);
+    }
+    /**
+     * Get the Registrator instance.
+     */
+
+  }, {
+    key: "registrator",
+    value: function registrator() {
+      return this._registrator;
+    }
+    /**
+     * Registration state.
+     */
+
+  }, {
+    key: "isRegistered",
+    value: function isRegistered() {
+      return this._registrator.registered;
+    }
+    /**
+     * Connection state.
+     */
+
+  }, {
+    key: "isConnected",
+    value: function isConnected() {
+      return this._transport.isConnected();
+    }
+    /**
+     * Make an outgoing call.
+     *
+     * -param {String} target
+     * -param {Object} [options]
+     *
+     * -throws {TypeError}
+     *
+     */
+
+  }, {
+    key: "call",
+    value: function call(target, options) {
+      logger.debug('call()');
+      var session = new RTCSession(this);
+      session.connect(target, options);
+      return session;
+    }
+    /**
+     * Send a message.
+     *
+     * -param {String} target
+     * -param {String} body
+     * -param {Object} [options]
+     *
+     * -throws {TypeError}
+     *
+     */
+
+  }, {
+    key: "sendMessage",
+    value: function sendMessage(target, body, options) {
+      logger.debug('sendMessage()');
+      var message = new Message(this);
+      message.send(target, body, options);
+      return message;
+    }
+    /**
+     * Send a SIP OPTIONS.
+     *
+     * -param {String} target
+     * -param {String} [body]
+     * -param {Object} [options]
+     *
+     * -throws {TypeError}
+     *
+     */
+
+  }, {
+    key: "sendOptions",
+    value: function sendOptions(target, body, options) {
+      logger.debug('sendOptions()');
+      var message = new Options(this);
+      message.send(target, body, options);
+      return message;
+    }
+    /**
+     * Terminate ongoing sessions.
+     */
+
+  }, {
+    key: "terminateSessions",
+    value: function terminateSessions(options) {
+      logger.debug('terminateSessions()');
+
+      for (var idx in this._sessions) {
+        if (!this._sessions[idx].isEnded()) {
+          this._sessions[idx].terminate(options);
+        }
+      }
+    }
+    /**
+     * Gracefully close.
+     *
+     */
+
+  }, {
+    key: "stop",
+    value: function stop() {
+      var _this2 = this;
+
+      logger.debug('stop()'); // Remove dynamic settings.
+
+      this._dynConfiguration = {};
+
+      if (this._status === C.STATUS_USER_CLOSED) {
+        logger.debug('UA already closed');
+        return;
+      } // Close registrator.
+
+
+      this._registrator.close(); // If there are session wait a bit so CANCEL/BYE can be sent and their responses received.
+
+
+      var num_sessions = Object.keys(this._sessions).length; // Run  _terminate_ on every Session.
+
+      for (var session in this._sessions) {
+        if (Object.prototype.hasOwnProperty.call(this._sessions, session)) {
+          logger.debug("closing session ".concat(session));
+
+          try {
+            this._sessions[session].terminate();
+          } catch (error) {}
+        }
+      } // Run  _close_ on every applicant.
+
+
+      for (var applicant in this._applicants) {
+        if (Object.prototype.hasOwnProperty.call(this._applicants, applicant)) try {
+          this._applicants[applicant].close();
+        } catch (error) {}
+      }
+
+      this._status = C.STATUS_USER_CLOSED;
+      var num_transactions = Object.keys(this._transactions.nict).length + Object.keys(this._transactions.nist).length + Object.keys(this._transactions.ict).length + Object.keys(this._transactions.ist).length;
+
+      if (num_transactions === 0 && num_sessions === 0) {
+        this._transport.disconnect();
+      } else {
+        this._closeTimer = setTimeout(function () {
+          _this2._closeTimer = null;
+
+          _this2._transport.disconnect();
+        }, 2000);
+      }
+    }
+    /**
+     * Normalice a string into a valid SIP request URI
+     * -param {String} target
+     * -returns {JsSIP.URI|undefined}
+     */
+
+  }, {
+    key: "normalizeTarget",
+    value: function normalizeTarget(target) {
+      return Utils.normalizeTarget(target, this._configuration.hostport_params);
+    }
+    /**
+     * Allow retrieving configuration and autogenerated fields in runtime.
+     */
+
+  }, {
+    key: "get",
+    value: function get(parameter) {
+      switch (parameter) {
+        case 'authorization_user':
+          return this._configuration.authorization_user;
+
+        case 'realm':
+          return this._configuration.realm;
+
+        case 'ha1':
+          return this._configuration.ha1;
+
+        case 'authorization_jwt':
+          return this._configuration.authorization_jwt;
+
+        default:
+          logger.warn('get() | cannot get "%s" parameter in runtime', parameter);
+          return undefined;
+      }
+    }
+    /**
+     * Allow configuration changes in runtime.
+     * Returns true if the parameter could be set.
+     */
+
+  }, {
+    key: "set",
+    value: function set(parameter, value) {
+      switch (parameter) {
+        case 'authorization_user':
+          {
+            this._configuration.authorization_user = String(value);
+            break;
+          }
+
+        case 'password':
+          {
+            this._configuration.password = String(value);
+            break;
+          }
+
+        case 'realm':
+          {
+            this._configuration.realm = String(value);
+            break;
+          }
+
+        case 'ha1':
+          {
+            this._configuration.ha1 = String(value); // Delete the plain SIP password.
+
+            this._configuration.password = null;
+            break;
+          }
+
+        case 'authorization_jwt':
+          {
+            this._configuration.authorization_jwt = String(value);
+            break;
+          }
+
+        case 'display_name':
+          {
+            this._configuration.display_name = value;
+            break;
+          }
+
+        default:
+          logger.warn('set() | cannot set "%s" parameter in runtime', parameter);
+          return false;
+      }
+
+      return true;
+    } // ==========================
+    // Event Handlers.
+    // ==========================
+
+    /**
+     * new Transaction
+     */
+
+  }, {
+    key: "newTransaction",
+    value: function newTransaction(transaction) {
+      this._transactions[transaction.type][transaction.id] = transaction;
+      this.emit('newTransaction', {
+        transaction: transaction
+      });
+    }
+    /**
+     * Transaction destroyed.
+     */
+
+  }, {
+    key: "destroyTransaction",
+    value: function destroyTransaction(transaction) {
+      delete this._transactions[transaction.type][transaction.id];
+      this.emit('transactionDestroyed', {
+        transaction: transaction
+      });
+    }
+    /**
+     * new Dialog
+     */
+
+  }, {
+    key: "newDialog",
+    value: function newDialog(dialog) {
+      this._dialogs[dialog.id] = dialog;
+    }
+    /**
+     * Dialog destroyed.
+     */
+
+  }, {
+    key: "destroyDialog",
+    value: function destroyDialog(dialog) {
+      delete this._dialogs[dialog.id];
+    }
+    /**
+     *  new Message
+     */
+
+  }, {
+    key: "newMessage",
+    value: function newMessage(message, data) {
+      this._applicants[message] = message;
+      this.emit('newMessage', data);
+    }
+    /**
+     *  new Options
+     */
+
+  }, {
+    key: "newOptions",
+    value: function newOptions(message, data) {
+      this._applicants[message] = message;
+      this.emit('newOptions', data);
+    }
+    /**
+     *  Message destroyed.
+     */
+
+  }, {
+    key: "destroyMessage",
+    value: function destroyMessage(message) {
+      delete this._applicants[message];
+    }
+    /**
+     * new RTCSession
+     */
+
+  }, {
+    key: "newRTCSession",
+    value: function newRTCSession(session, data) {
+      this._sessions[session.id] = session;
+      this.emit('newRTCSession', data);
+    }
+    /**
+     * RTCSession destroyed.
+     */
+
+  }, {
+    key: "destroyRTCSession",
+    value: function destroyRTCSession(session) {
+      delete this._sessions[session.id];
+    }
+    /**
+     * Registered
+     */
+
+  }, {
+    key: "registered",
+    value: function registered(data) {
+      this.emit('registered', data);
+    }
+    /**
+     * Unregistered
+     */
+
+  }, {
+    key: "unregistered",
+    value: function unregistered(data) {
+      this.emit('unregistered', data);
+    }
+    /**
+     * Registration Failed
+     */
+
+  }, {
+    key: "registrationFailed",
+    value: function registrationFailed(data) {
+      this.emit('registrationFailed', data);
+    } // =========================
+    // ReceiveRequest.
+    // =========================
+
+    /**
+     * Request reception
+     */
+
+  }, {
+    key: "receiveRequest",
+    value: function receiveRequest(request) {
+      var method = request.method; // Check that request URI points to us.
+
+      if (request.ruri.user !== this._configuration.uri.user && request.ruri.user !== this._contact.uri.user) {
+        logger.debug('Request-URI does not point to us');
+
+        if (request.method !== JsSIP_C.ACK) {
+          request.reply_sl(404);
+        }
+
+        return;
+      } // Check request URI scheme.
+
+
+      if (request.ruri.scheme === JsSIP_C.SIPS) {
+        request.reply_sl(416);
+        return;
+      } // Check transaction.
+
+
+      if (Transactions.checkTransaction(this, request)) {
+        return;
+      } // Create the server transaction.
+
+
+      if (method === JsSIP_C.INVITE) {
+        /* eslint-disable no-new */
+        new Transactions.InviteServerTransaction(this, this._transport, request);
+        /* eslint-enable no-new */
+      } else if (method !== JsSIP_C.ACK && method !== JsSIP_C.CANCEL) {
+        /* eslint-disable no-new */
+        new Transactions.NonInviteServerTransaction(this, this._transport, request);
+        /* eslint-enable no-new */
+      }
+      /* RFC3261 12.2.2
+       * Requests that do not change in any way the state of a dialog may be
+       * received within a dialog (for example, an OPTIONS request).
+       * They are processed as if they had been received outside the dialog.
+       */
+
+
+      if (method === JsSIP_C.OPTIONS) {
+        if (this.listeners('newOptions').length === 0) {
+          request.reply(200);
+          return;
+        }
+
+        var message = new Options(this);
+        message.init_incoming(request);
+      } else if (method === JsSIP_C.MESSAGE) {
+        if (this.listeners('newMessage').length === 0) {
+          request.reply(405);
+          return;
+        }
+
+        var _message = new Message(this);
+
+        _message.init_incoming(request);
+      } else if (method === JsSIP_C.INVITE) {
+        // Initial INVITE.
+        if (!request.to_tag && this.listeners('newRTCSession').length === 0) {
+          request.reply(405);
+          return;
+        }
+      }
+
+      var dialog;
+      var session; // Initial Request.
+
+      if (!request.to_tag) {
+        switch (method) {
+          case JsSIP_C.INVITE:
+            if (window.RTCPeerConnection) {
+              // TODO
+              if (request.hasHeader('replaces')) {
+                var replaces = request.replaces;
+                dialog = this._findDialog(replaces.call_id, replaces.from_tag, replaces.to_tag);
+
+                if (dialog) {
+                  session = dialog.owner;
+
+                  if (!session.isEnded()) {
+                    session.receiveRequest(request);
+                  } else {
+                    request.reply(603);
+                  }
+                } else {
+                  request.reply(481);
+                }
+              } else {
+                session = new RTCSession(this);
+                session.init_incoming(request);
+              }
+            } else {
+              logger.warn('INVITE received but WebRTC is not supported');
+              request.reply(488);
+            }
+
+            break;
+
+          case JsSIP_C.BYE:
+            // Out of dialog BYE received.
+            request.reply(481);
+            break;
+
+          case JsSIP_C.CANCEL:
+            session = this._findSession(request);
+
+            if (session) {
+              session.receiveRequest(request);
+            } else {
+              logger.debug('received CANCEL request for a non existent session');
+            }
+
+            break;
+
+          case JsSIP_C.ACK:
+            /* Absorb it.
+             * ACK request without a corresponding Invite Transaction
+             * and without To tag.
+             */
+            break;
+
+          case JsSIP_C.NOTIFY:
+            // Receive new sip event.
+            this.emit('sipEvent', {
+              event: request.event,
+              request: request
+            });
+            request.reply(200);
+            break;
+
+          default:
+            request.reply(405);
+            break;
+        }
+      } // In-dialog request.
+      else {
+          dialog = this._findDialog(request.call_id, request.from_tag, request.to_tag);
+
+          if (dialog) {
+            dialog.receiveRequest(request);
+          } else if (method === JsSIP_C.NOTIFY) {
+            session = this._findSession(request);
+
+            if (session) {
+              session.receiveRequest(request);
+            } else {
+              logger.debug('received NOTIFY request for a non existent subscription');
+              request.reply(481, 'Subscription does not exist');
+            }
+          }
+          /* RFC3261 12.2.2
+           * Request with to tag, but no matching dialog found.
+           * Exception: ACK for an Invite request for which a dialog has not
+           * been created.
+           */
+          else if (method !== JsSIP_C.ACK) {
+              request.reply(481);
+            }
+        }
+    } // =================
+    // Utils.
+    // =================
+
+    /**
+     * Get the session to which the request belongs to, if any.
+     */
+
+  }, {
+    key: "_findSession",
+    value: function _findSession(_ref) {
+      var call_id = _ref.call_id,
+          from_tag = _ref.from_tag,
+          to_tag = _ref.to_tag;
+      var sessionIDa = call_id + from_tag;
+      var sessionA = this._sessions[sessionIDa];
+      var sessionIDb = call_id + to_tag;
+      var sessionB = this._sessions[sessionIDb];
+
+      if (sessionA) {
+        return sessionA;
+      } else if (sessionB) {
+        return sessionB;
+      } else {
+        return null;
+      }
+    }
+    /**
+     * Get the dialog to which the request belongs to, if any.
+     */
+
+  }, {
+    key: "_findDialog",
+    value: function _findDialog(call_id, from_tag, to_tag) {
+      var id = call_id + from_tag + to_tag;
+      var dialog = this._dialogs[id];
+
+      if (dialog) {
+        return dialog;
+      } else {
+        id = call_id + to_tag + from_tag;
+        dialog = this._dialogs[id];
+
+        if (dialog) {
+          return dialog;
+        } else {
+          return null;
+        }
+      }
+    }
+  }, {
+    key: "_loadConfig",
+    value: function _loadConfig(configuration) {
+      // Check and load the given configuration.
+      try {
+        config.load(this._configuration, configuration);
+      } catch (e) {
+        throw e;
+      } // Post Configuration Process.
+      // Allow passing 0 number as display_name.
+
+
+      if (this._configuration.display_name === 0) {
+        this._configuration.display_name = '0';
+      } // Instance-id for GRUU.
+
+
+      if (!this._configuration.instance_id) {
+        this._configuration.instance_id = Utils.newUUID();
+      } // Jssip_id instance parameter. Static random tag of length 5.
+
+
+      this._configuration.jssip_id = Utils.createRandomToken(5); // String containing this._configuration.uri without scheme and user.
+
+      var hostport_params = this._configuration.uri.clone();
+
+      hostport_params.user = null;
+      this._configuration.hostport_params = hostport_params.toString().replace(/^sip:/i, ''); // Transport.
+
+      try {
+        this._transport = new Transport(this._configuration.sockets, {
+          // Recovery options.
+          max_interval: this._configuration.connection_recovery_max_interval,
+          min_interval: this._configuration.connection_recovery_min_interval
+        }); // Transport event callbacks.
+
+        this._transport.onconnecting = onTransportConnecting.bind(this);
+        this._transport.onconnect = onTransportConnect.bind(this);
+        this._transport.ondisconnect = onTransportDisconnect.bind(this);
+        this._transport.ondata = onTransportData.bind(this);
+      } catch (e) {
+        logger.warn(e);
+        throw new Exceptions.ConfigurationError('sockets', this._configuration.sockets);
+      } // Remove sockets instance from configuration object.
+
+
+      delete this._configuration.sockets; // Check whether authorization_user is explicitly defined.
+      // Take 'this._configuration.uri.user' value if not.
+
+      if (!this._configuration.authorization_user) {
+        this._configuration.authorization_user = this._configuration.uri.user;
+      } // If no 'registrar_server' is set use the 'uri' value without user portion and
+      // without URI params/headers.
+
+
+      if (!this._configuration.registrar_server) {
+        var registrar_server = this._configuration.uri.clone();
+
+        registrar_server.user = null;
+        registrar_server.clearParams();
+        registrar_server.clearHeaders();
+        this._configuration.registrar_server = registrar_server;
+      } // User no_answer_timeout.
+
+
+      this._configuration.no_answer_timeout *= 1000; // Via Host.
+
+      if (this._configuration.contact_uri) {
+        this._configuration.via_host = this._configuration.contact_uri.host;
+      } // Contact URI.
+      else {
+          this._configuration.contact_uri = new URI('sip', Utils.createRandomToken(8), this._configuration.via_host, null, {
+            transport: 'ws'
+          });
+        }
+
+      this._contact = {
+        pub_gruu: null,
+        temp_gruu: null,
+        uri: this._configuration.contact_uri,
+        toString: function toString() {
+          var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
+          var anonymous = options.anonymous || null;
+          var outbound = options.outbound || null;
+          var contact = '<';
+
+          if (anonymous) {
+            contact += this.temp_gruu || 'sip:anonymous@anonymous.invalid;transport=ws';
+          } else {
+            contact += this.pub_gruu || this.uri.toString();
+          }
+
+          if (outbound && (anonymous ? !this.temp_gruu : !this.pub_gruu)) {
+            contact += ';ob';
+          }
+
+          contact += '>';
+          return contact;
+        }
+      }; // Seal the configuration.
+
+      var writable_parameters = ['authorization_user', 'password', 'realm', 'ha1', 'authorization_jwt', 'display_name', 'register'];
+
+      for (var parameter in this._configuration) {
+        if (Object.prototype.hasOwnProperty.call(this._configuration, parameter)) {
+          if (writable_parameters.indexOf(parameter) !== -1) {
+            Object.defineProperty(this._configuration, parameter, {
+              writable: true,
+              configurable: false
+            });
+          } else {
+            Object.defineProperty(this._configuration, parameter, {
+              writable: false,
+              configurable: false
+            });
+          }
+        }
+      }
+
+      logger.debug('configuration parameters after validation:');
+
+      for (var _parameter in this._configuration) {
+        // Only show the user user configurable parameters.
+        if (Object.prototype.hasOwnProperty.call(config.settings, _parameter)) {
+          switch (_parameter) {
+            case 'uri':
+            case 'registrar_server':
+              logger.debug("- ".concat(_parameter, ": ").concat(this._configuration[_parameter]));
+              break;
+
+            case 'password':
+            case 'ha1':
+            case 'authorization_jwt':
+              logger.debug("- ".concat(_parameter, ": NOT SHOWN"));
+              break;
+
+            default:
+              logger.debug("- ".concat(_parameter, ": ").concat(JSON.stringify(this._configuration[_parameter])));
+          }
+        }
+      }
+
+      return;
+    }
+  }, {
+    key: "C",
+    get: function get() {
+      return C;
+    }
+  }, {
+    key: "status",
+    get: function get() {
+      return this._status;
+    }
+  }, {
+    key: "contact",
+    get: function get() {
+      return this._contact;
+    }
+  }, {
+    key: "configuration",
+    get: function get() {
+      return this._configuration;
+    }
+  }, {
+    key: "transport",
+    get: function get() {
+      return this._transport;
+    }
+  }]);
+
+  return UA;
+}(EventEmitter);
+/**
+ * Transport event handlers
+ */
+// Transport connecting event.
+
+
+function onTransportConnecting(data) {
+  this.emit('connecting', data);
+} // Transport connected event.
+
+
+function onTransportConnect(data) {
+  if (this._status === C.STATUS_USER_CLOSED) {
+    return;
+  }
+
+  this._status = C.STATUS_READY;
+  this._error = null;
+  this.emit('connected', data);
+
+  if (this._dynConfiguration.register) {
+    this._registrator.register();
+  }
+} // Transport disconnected event.
+
+
+function onTransportDisconnect(data) {
+  // Run _onTransportError_ callback on every client transaction using _transport_.
+  var client_transactions = ['nict', 'ict', 'nist', 'ist'];
+
+  for (var _i = 0, _client_transactions = client_transactions; _i < _client_transactions.length; _i++) {
+    var type = _client_transactions[_i];
+
+    for (var id in this._transactions[type]) {
+      if (Object.prototype.hasOwnProperty.call(this._transactions[type], id)) {
+        this._transactions[type][id].onTransportError();
+      }
+    }
+  }
+
+  this.emit('disconnected', data); // Call registrator _onTransportClosed_.
+
+  this._registrator.onTransportClosed();
+
+  if (this._status !== C.STATUS_USER_CLOSED) {
+    this._status = C.STATUS_NOT_READY;
+    this._error = C.NETWORK_ERROR;
+  }
+} // Transport data event.
+
+
+function onTransportData(data) {
+  var transport = data.transport;
+  var message = data.message;
+  message = Parser.parseMessage(message, this);
+
+  if (!message) {
+    return;
+  }
+
+  if (this._status === C.STATUS_USER_CLOSED && message instanceof SIPMessage.IncomingRequest) {
+    return;
+  } // Do some sanity check.
+
+
+  if (!sanityCheck(message, this, transport)) {
+    return;
+  }
+
+  if (message instanceof SIPMessage.IncomingRequest) {
+    message.transport = transport;
+    this.receiveRequest(message);
+  } else if (message instanceof SIPMessage.IncomingResponse) {
+    /* Unike stated in 18.1.2, if a response does not match
+    * any transaction, it is discarded here and no passed to the core
+    * in order to be discarded there.
+    */
+    var transaction;
+
+    switch (message.method) {
+      case JsSIP_C.INVITE:
+        transaction = this._transactions.ict[message.via_branch];
+
+        if (transaction) {
+          transaction.receiveResponse(message);
+        }
+
+        break;
+
+      case JsSIP_C.ACK:
+        // Just in case ;-).
+        break;
+
+      default:
+        transaction = this._transactions.nict[message.via_branch];
+
+        if (transaction) {
+          transaction.receiveResponse(message);
+        }
+
+        break;
+    }
+  }
+}
+},{"./Config":1,"./Constants":2,"./Exceptions":6,"./Logger":9,"./Message":10,"./Options":12,"./Parser":13,"./RTCSession":14,"./Registrator":19,"./SIPMessage":21,"./Transactions":24,"./Transport":25,"./URI":27,"./Utils":28,"./sanityCheck":30,"events":31}],27:[function(require,module,exports){
+"use strict";
+
+function _createForOfIteratorHelper(o, allowArrayLike) { var it; if (typeof Symbol === "undefined" || o[Symbol.iterator] == null) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = o[Symbol.iterator](); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it["return"] != null) it["return"](); } finally { if (didErr) throw err; } } }; }
+
+function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
+
+function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; }
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
+
+function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
+
+var JsSIP_C = require('./Constants');
+
+var Utils = require('./Utils');
+
+var Grammar = require('./Grammar');
+/**
+ * -param {String} [scheme]
+ * -param {String} [user]
+ * -param {String} host
+ * -param {String} [port]
+ * -param {Object} [parameters]
+ * -param {Object} [headers]
+ *
+ */
+
+
+module.exports = /*#__PURE__*/function () {
+  _createClass(URI, null, [{
+    key: "parse",
+
+    /**
+      * Parse the given string and returns a JsSIP.URI instance or undefined if
+      * it is an invalid URI.
+      */
+    value: function parse(uri) {
+      uri = Grammar.parse(uri, 'SIP_URI');
+
+      if (uri !== -1) {
+        return uri;
+      } else {
+        return undefined;
+      }
+    }
+  }]);
+
+  function URI(scheme, user, host, port) {
+    var parameters = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : {};
+    var headers = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : {};
+
+    _classCallCheck(this, URI);
+
+    // Checks.
+    if (!host) {
+      throw new TypeError('missing or invalid "host" parameter');
+    } // Initialize parameters.
+
+
+    this._parameters = {};
+    this._headers = {};
+    this._scheme = scheme || JsSIP_C.SIP;
+    this._user = user;
+    this._host = host;
+    this._port = port;
+
+    for (var param in parameters) {
+      if (Object.prototype.hasOwnProperty.call(parameters, param)) {
+        this.setParam(param, parameters[param]);
+      }
+    }
+
+    for (var header in headers) {
+      if (Object.prototype.hasOwnProperty.call(headers, header)) {
+        this.setHeader(header, headers[header]);
+      }
+    }
+  }
+
+  _createClass(URI, [{
+    key: "setParam",
+    value: function setParam(key, value) {
+      if (key) {
+        this._parameters[key.toLowerCase()] = typeof value === 'undefined' || value === null ? null : value.toString();
+      }
+    }
+  }, {
+    key: "getParam",
+    value: function getParam(key) {
+      if (key) {
+        return this._parameters[key.toLowerCase()];
+      }
+    }
+  }, {
+    key: "hasParam",
+    value: function hasParam(key) {
+      if (key) {
+        return this._parameters.hasOwnProperty(key.toLowerCase()) && true || false;
+      }
+    }
+  }, {
+    key: "deleteParam",
+    value: function deleteParam(parameter) {
+      parameter = parameter.toLowerCase();
+
+      if (this._parameters.hasOwnProperty(parameter)) {
+        var value = this._parameters[parameter];
+        delete this._parameters[parameter];
+        return value;
+      }
+    }
+  }, {
+    key: "clearParams",
+    value: function clearParams() {
+      this._parameters = {};
+    }
+  }, {
+    key: "setHeader",
+    value: function setHeader(name, value) {
+      this._headers[Utils.headerize(name)] = Array.isArray(value) ? value : [value];
+    }
+  }, {
+    key: "getHeader",
+    value: function getHeader(name) {
+      if (name) {
+        return this._headers[Utils.headerize(name)];
+      }
+    }
+  }, {
+    key: "hasHeader",
+    value: function hasHeader(name) {
+      if (name) {
+        return this._headers.hasOwnProperty(Utils.headerize(name)) && true || false;
+      }
+    }
+  }, {
+    key: "deleteHeader",
+    value: function deleteHeader(header) {
+      header = Utils.headerize(header);
+
+      if (this._headers.hasOwnProperty(header)) {
+        var value = this._headers[header];
+        delete this._headers[header];
+        return value;
+      }
+    }
+  }, {
+    key: "clearHeaders",
+    value: function clearHeaders() {
+      this._headers = {};
+    }
+  }, {
+    key: "clone",
+    value: function clone() {
+      return new URI(this._scheme, this._user, this._host, this._port, JSON.parse(JSON.stringify(this._parameters)), JSON.parse(JSON.stringify(this._headers)));
+    }
+  }, {
+    key: "toString",
+    value: function toString() {
+      var headers = [];
+      var uri = "".concat(this._scheme, ":");
+
+      if (this._user) {
+        uri += "".concat(Utils.escapeUser(this._user), "@");
+      }
+
+      uri += this._host;
+
+      if (this._port || this._port === 0) {
+        uri += ":".concat(this._port);
+      }
+
+      for (var parameter in this._parameters) {
+        if (Object.prototype.hasOwnProperty.call(this._parameters, parameter)) {
+          uri += ";".concat(parameter);
+
+          if (this._parameters[parameter] !== null) {
+            uri += "=".concat(this._parameters[parameter]);
+          }
+        }
+      }
+
+      for (var header in this._headers) {
+        if (Object.prototype.hasOwnProperty.call(this._headers, header)) {
+          var _iterator = _createForOfIteratorHelper(this._headers[header]),
+              _step;
+
+          try {
+            for (_iterator.s(); !(_step = _iterator.n()).done;) {
+              var item = _step.value;
+              headers.push("".concat(header, "=").concat(item));
+            }
+          } catch (err) {
+            _iterator.e(err);
+          } finally {
+            _iterator.f();
+          }
+        }
+      }
+
+      if (headers.length > 0) {
+        uri += "?".concat(headers.join('&'));
+      }
+
+      return uri;
+    }
+  }, {
+    key: "toAor",
+    value: function toAor(show_port) {
+      var aor = "".concat(this._scheme, ":");
+
+      if (this._user) {
+        aor += "".concat(Utils.escapeUser(this._user), "@");
+      }
+
+      aor += this._host;
+
+      if (show_port && (this._port || this._port === 0)) {
+        aor += ":".concat(this._port);
+      }
+
+      return aor;
+    }
+  }, {
+    key: "scheme",
+    get: function get() {
+      return this._scheme;
+    },
+    set: function set(value) {
+      this._scheme = value.toLowerCase();
+    }
+  }, {
+    key: "user",
+    get: function get() {
+      return this._user;
+    },
+    set: function set(value) {
+      this._user = value;
+    }
+  }, {
+    key: "host",
+    get: function get() {
+      return this._host;
+    },
+    set: function set(value) {
+      this._host = value.toLowerCase();
+    }
+  }, {
+    key: "port",
+    get: function get() {
+      return this._port;
+    },
+    set: function set(value) {
+      this._port = value === 0 ? value : parseInt(value, 10) || null;
+    }
+  }]);
+
+  return URI;
+}();
+},{"./Constants":2,"./Grammar":7,"./Utils":28}],28:[function(require,module,exports){
+"use strict";
+
+function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }
+
+function _createForOfIteratorHelper(o, allowArrayLike) { var it; if (typeof Symbol === "undefined" || o[Symbol.iterator] == null) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = o[Symbol.iterator](); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it["return"] != null) it["return"](); } finally { if (didErr) throw err; } } }; }
+
+function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
+
+function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; }
+
+var JsSIP_C = require('./Constants');
+
+var URI = require('./URI');
+
+var Grammar = require('./Grammar');
+
+exports.str_utf8_length = function (string) {
+  return unescape(encodeURIComponent(string)).length;
+}; // Used by 'hasMethods'.
+
+
+var isFunction = exports.isFunction = function (fn) {
+  if (fn !== undefined) {
+    return Object.prototype.toString.call(fn) === '[object Function]' ? true : false;
+  } else {
+    return false;
+  }
+};
+
+exports.isString = function (str) {
+  if (str !== undefined) {
+    return Object.prototype.toString.call(str) === '[object String]' ? true : false;
+  } else {
+    return false;
+  }
+};
+
+exports.isDecimal = function (num) {
+  return !isNaN(num) && parseFloat(num) === parseInt(num, 10);
+};
+
+exports.isEmpty = function (value) {
+  return value === null || value === '' || value === undefined || Array.isArray(value) && value.length === 0 || typeof value === 'number' && isNaN(value);
+};
+
+exports.hasMethods = function (obj) {
+  for (var _len = arguments.length, methodNames = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
+    methodNames[_key - 1] = arguments[_key];
+  }
+
+  for (var _i = 0, _methodNames = methodNames; _i < _methodNames.length; _i++) {
+    var methodName = _methodNames[_i];
+
+    if (isFunction(obj[methodName])) {
+      return false;
+    }
+  }
+
+  return true;
+}; // Used by 'newTag'.
+
+
+var createRandomToken = exports.createRandomToken = function (size) {
+  var base = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 32;
+  var i,
+      r,
+      token = '';
+
+  for (i = 0; i < size; i++) {
+    r = Math.random() * base | 0;
+    token += r.toString(base);
+  }
+
+  return token;
+};
+
+exports.newTag = function () {
+  return createRandomToken(10);
+}; // https://stackoverflow.com/users/109538/broofa.
+
+
+exports.newUUID = function () {
+  var UUID = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
+    var r = Math.random() * 16 | 0,
+        v = c === 'x' ? r : r & 0x3 | 0x8;
+    return v.toString(16);
+  });
+  return UUID;
+};
+
+exports.hostType = function (host) {
+  if (!host) {
+    return;
+  } else {
+    host = Grammar.parse(host, 'host');
+
+    if (host !== -1) {
+      return host.host_type;
+    }
+  }
+};
+/**
+* Hex-escape a SIP URI user.
+* Don't hex-escape ':' (%3A), '+' (%2B), '?' (%3F"), '/' (%2F).
+*
+* Used by 'normalizeTarget'.
+*/
+
+
+var escapeUser = exports.escapeUser = function (user) {
+  return encodeURIComponent(decodeURIComponent(user)).replace(/%3A/ig, ':').replace(/%2B/ig, '+').replace(/%3F/ig, '?').replace(/%2F/ig, '/');
+};
+/**
+* Normalize SIP URI.
+* NOTE: It does not allow a SIP URI without username.
+* Accepts 'sip', 'sips' and 'tel' URIs and convert them into 'sip'.
+* Detects the domain part (if given) and properly hex-escapes the user portion.
+* If the user portion has only 'tel' number symbols the user portion is clean of 'tel' visual separators.
+*/
+
+
+exports.normalizeTarget = function (target, domain) {
+  // If no target is given then raise an error.
+  if (!target) {
+    return; // If a URI instance is given then return it.
+  } else if (target instanceof URI) {
+    return target; // If a string is given split it by '@':
+    // - Last fragment is the desired domain.
+    // - Otherwise append the given domain argument.
+  } else if (typeof target === 'string') {
+    var target_array = target.split('@');
+    var target_user;
+    var target_domain;
+
+    switch (target_array.length) {
+      case 1:
+        if (!domain) {
+          return;
+        }
+
+        target_user = target;
+        target_domain = domain;
+        break;
+
+      case 2:
+        target_user = target_array[0];
+        target_domain = target_array[1];
+        break;
+
+      default:
+        target_user = target_array.slice(0, target_array.length - 1).join('@');
+        target_domain = target_array[target_array.length - 1];
+    } // Remove the URI scheme (if present).
+
+
+    target_user = target_user.replace(/^(sips?|tel):/i, ''); // Remove 'tel' visual separators if the user portion just contains 'tel' number symbols.
+
+    if (/^[-.()]*\+?[0-9\-.()]+$/.test(target_user)) {
+      target_user = target_user.replace(/[-.()]/g, '');
+    } // Build the complete SIP URI.
+
+
+    target = "".concat(JsSIP_C.SIP, ":").concat(escapeUser(target_user), "@").concat(target_domain); // Finally parse the resulting URI.
+
+    var uri;
+
+    if (uri = URI.parse(target)) {
+      return uri;
+    } else {
+      return;
+    }
+  } else {
+    return;
+  }
+};
+
+exports.headerize = function (string) {
+  var exceptions = {
+    'Call-Id': 'Call-ID',
+    'Cseq': 'CSeq',
+    'Www-Authenticate': 'WWW-Authenticate'
+  };
+  var name = string.toLowerCase().replace(/_/g, '-').split('-');
+  var hname = '';
+  var parts = name.length;
+  var part;
+
+  for (part = 0; part < parts; part++) {
+    if (part !== 0) {
+      hname += '-';
+    }
+
+    hname += name[part].charAt(0).toUpperCase() + name[part].substring(1);
+  }
+
+  if (exceptions[hname]) {
+    hname = exceptions[hname];
+  }
+
+  return hname;
+};
+
+exports.sipErrorCause = function (status_code) {
+  for (var cause in JsSIP_C.SIP_ERROR_CAUSES) {
+    if (JsSIP_C.SIP_ERROR_CAUSES[cause].indexOf(status_code) !== -1) {
+      return JsSIP_C.causes[cause];
+    }
+  }
+
+  return JsSIP_C.causes.SIP_FAILURE_CODE;
+};
+/**
+* Generate a random Test-Net IP (https://tools.ietf.org/html/rfc5735)
+*/
+
+
+exports.getRandomTestNetIP = function () {
+  function getOctet(from, to) {
+    return Math.floor(Math.random() * (to - from + 1) + from);
+  }
+
+  return "192.0.2.".concat(getOctet(1, 254));
+}; // MD5 (Message-Digest Algorithm) https://www.webtoolkit.info.
+
+
+exports.calculateMD5 = function (string) {
+  function rotateLeft(lValue, iShiftBits) {
+    return lValue << iShiftBits | lValue >>> 32 - iShiftBits;
+  }
+
+  function addUnsigned(lX, lY) {
+    var lX8 = lX & 0x80000000;
+    var lY8 = lY & 0x80000000;
+    var lX4 = lX & 0x40000000;
+    var lY4 = lY & 0x40000000;
+    var lResult = (lX & 0x3FFFFFFF) + (lY & 0x3FFFFFFF);
+
+    if (lX4 & lY4) {
+      return lResult ^ 0x80000000 ^ lX8 ^ lY8;
+    }
+
+    if (lX4 | lY4) {
+      if (lResult & 0x40000000) {
+        return lResult ^ 0xC0000000 ^ lX8 ^ lY8;
+      } else {
+        return lResult ^ 0x40000000 ^ lX8 ^ lY8;
+      }
+    } else {
+      return lResult ^ lX8 ^ lY8;
+    }
+  }
+
+  function doF(x, y, z) {
+    return x & y | ~x & z;
+  }
+
+  function doG(x, y, z) {
+    return x & z | y & ~z;
+  }
+
+  function doH(x, y, z) {
+    return x ^ y ^ z;
+  }
+
+  function doI(x, y, z) {
+    return y ^ (x | ~z);
+  }
+
+  function doFF(a, b, c, d, x, s, ac) {
+    a = addUnsigned(a, addUnsigned(addUnsigned(doF(b, c, d), x), ac));
+    return addUnsigned(rotateLeft(a, s), b);
+  }
+
+  function doGG(a, b, c, d, x, s, ac) {
+    a = addUnsigned(a, addUnsigned(addUnsigned(doG(b, c, d), x), ac));
+    return addUnsigned(rotateLeft(a, s), b);
+  }
+
+  function doHH(a, b, c, d, x, s, ac) {
+    a = addUnsigned(a, addUnsigned(addUnsigned(doH(b, c, d), x), ac));
+    return addUnsigned(rotateLeft(a, s), b);
+  }
+
+  function doII(a, b, c, d, x, s, ac) {
+    a = addUnsigned(a, addUnsigned(addUnsigned(doI(b, c, d), x), ac));
+    return addUnsigned(rotateLeft(a, s), b);
+  }
+
+  function convertToWordArray(str) {
+    var lWordCount;
+    var lMessageLength = str.length;
+    var lNumberOfWords_temp1 = lMessageLength + 8;
+    var lNumberOfWords_temp2 = (lNumberOfWords_temp1 - lNumberOfWords_temp1 % 64) / 64;
+    var lNumberOfWords = (lNumberOfWords_temp2 + 1) * 16;
+    var lWordArray = new Array(lNumberOfWords - 1);
+    var lBytePosition = 0;
+    var lByteCount = 0;
+
+    while (lByteCount < lMessageLength) {
+      lWordCount = (lByteCount - lByteCount % 4) / 4;
+      lBytePosition = lByteCount % 4 * 8;
+      lWordArray[lWordCount] = lWordArray[lWordCount] | str.charCodeAt(lByteCount) << lBytePosition;
+      lByteCount++;
+    }
+
+    lWordCount = (lByteCount - lByteCount % 4) / 4;
+    lBytePosition = lByteCount % 4 * 8;
+    lWordArray[lWordCount] = lWordArray[lWordCount] | 0x80 << lBytePosition;
+    lWordArray[lNumberOfWords - 2] = lMessageLength << 3;
+    lWordArray[lNumberOfWords - 1] = lMessageLength >>> 29;
+    return lWordArray;
+  }
+
+  function wordToHex(lValue) {
+    var wordToHexValue = '',
+        wordToHexValue_temp = '',
+        lByte,
+        lCount;
+
+    for (lCount = 0; lCount <= 3; lCount++) {
+      lByte = lValue >>> lCount * 8 & 255;
+      wordToHexValue_temp = "0".concat(lByte.toString(16));
+      wordToHexValue = wordToHexValue + wordToHexValue_temp.substr(wordToHexValue_temp.length - 2, 2);
+    }
+
+    return wordToHexValue;
+  }
+
+  function utf8Encode(str) {
+    var utftext = '';
+
+    for (var n = 0; n < str.length; n++) {
+      var _c = str.charCodeAt(n);
+
+      if (_c < 128) {
+        utftext += String.fromCharCode(_c);
+      } else if (_c > 127 && _c < 2048) {
+        utftext += String.fromCharCode(_c >> 6 | 192);
+        utftext += String.fromCharCode(_c & 63 | 128);
+      } else {
+        utftext += String.fromCharCode(_c >> 12 | 224);
+        utftext += String.fromCharCode(_c >> 6 & 63 | 128);
+        utftext += String.fromCharCode(_c & 63 | 128);
+      }
+    }
+
+    return utftext;
+  }
+
+  var x = [];
+  var k, AA, BB, CC, DD, a, b, c, d;
+  var S11 = 7,
+      S12 = 12,
+      S13 = 17,
+      S14 = 22;
+  var S21 = 5,
+      S22 = 9,
+      S23 = 14,
+      S24 = 20;
+  var S31 = 4,
+      S32 = 11,
+      S33 = 16,
+      S34 = 23;
+  var S41 = 6,
+      S42 = 10,
+      S43 = 15,
+      S44 = 21;
+  string = utf8Encode(string);
+  x = convertToWordArray(string);
+  a = 0x67452301;
+  b = 0xEFCDAB89;
+  c = 0x98BADCFE;
+  d = 0x10325476;
+
+  for (k = 0; k < x.length; k += 16) {
+    AA = a;
+    BB = b;
+    CC = c;
+    DD = d;
+    a = doFF(a, b, c, d, x[k + 0], S11, 0xD76AA478);
+    d = doFF(d, a, b, c, x[k + 1], S12, 0xE8C7B756);
+    c = doFF(c, d, a, b, x[k + 2], S13, 0x242070DB);
+    b = doFF(b, c, d, a, x[k + 3], S14, 0xC1BDCEEE);
+    a = doFF(a, b, c, d, x[k + 4], S11, 0xF57C0FAF);
+    d = doFF(d, a, b, c, x[k + 5], S12, 0x4787C62A);
+    c = doFF(c, d, a, b, x[k + 6], S13, 0xA8304613);
+    b = doFF(b, c, d, a, x[k + 7], S14, 0xFD469501);
+    a = doFF(a, b, c, d, x[k + 8], S11, 0x698098D8);
+    d = doFF(d, a, b, c, x[k + 9], S12, 0x8B44F7AF);
+    c = doFF(c, d, a, b, x[k + 10], S13, 0xFFFF5BB1);
+    b = doFF(b, c, d, a, x[k + 11], S14, 0x895CD7BE);
+    a = doFF(a, b, c, d, x[k + 12], S11, 0x6B901122);
+    d = doFF(d, a, b, c, x[k + 13], S12, 0xFD987193);
+    c = doFF(c, d, a, b, x[k + 14], S13, 0xA679438E);
+    b = doFF(b, c, d, a, x[k + 15], S14, 0x49B40821);
+    a = doGG(a, b, c, d, x[k + 1], S21, 0xF61E2562);
+    d = doGG(d, a, b, c, x[k + 6], S22, 0xC040B340);
+    c = doGG(c, d, a, b, x[k + 11], S23, 0x265E5A51);
+    b = doGG(b, c, d, a, x[k + 0], S24, 0xE9B6C7AA);
+    a = doGG(a, b, c, d, x[k + 5], S21, 0xD62F105D);
+    d = doGG(d, a, b, c, x[k + 10], S22, 0x2441453);
+    c = doGG(c, d, a, b, x[k + 15], S23, 0xD8A1E681);
+    b = doGG(b, c, d, a, x[k + 4], S24, 0xE7D3FBC8);
+    a = doGG(a, b, c, d, x[k + 9], S21, 0x21E1CDE6);
+    d = doGG(d, a, b, c, x[k + 14], S22, 0xC33707D6);
+    c = doGG(c, d, a, b, x[k + 3], S23, 0xF4D50D87);
+    b = doGG(b, c, d, a, x[k + 8], S24, 0x455A14ED);
+    a = doGG(a, b, c, d, x[k + 13], S21, 0xA9E3E905);
+    d = doGG(d, a, b, c, x[k + 2], S22, 0xFCEFA3F8);
+    c = doGG(c, d, a, b, x[k + 7], S23, 0x676F02D9);
+    b = doGG(b, c, d, a, x[k + 12], S24, 0x8D2A4C8A);
+    a = doHH(a, b, c, d, x[k + 5], S31, 0xFFFA3942);
+    d = doHH(d, a, b, c, x[k + 8], S32, 0x8771F681);
+    c = doHH(c, d, a, b, x[k + 11], S33, 0x6D9D6122);
+    b = doHH(b, c, d, a, x[k + 14], S34, 0xFDE5380C);
+    a = doHH(a, b, c, d, x[k + 1], S31, 0xA4BEEA44);
+    d = doHH(d, a, b, c, x[k + 4], S32, 0x4BDECFA9);
+    c = doHH(c, d, a, b, x[k + 7], S33, 0xF6BB4B60);
+    b = doHH(b, c, d, a, x[k + 10], S34, 0xBEBFBC70);
+    a = doHH(a, b, c, d, x[k + 13], S31, 0x289B7EC6);
+    d = doHH(d, a, b, c, x[k + 0], S32, 0xEAA127FA);
+    c = doHH(c, d, a, b, x[k + 3], S33, 0xD4EF3085);
+    b = doHH(b, c, d, a, x[k + 6], S34, 0x4881D05);
+    a = doHH(a, b, c, d, x[k + 9], S31, 0xD9D4D039);
+    d = doHH(d, a, b, c, x[k + 12], S32, 0xE6DB99E5);
+    c = doHH(c, d, a, b, x[k + 15], S33, 0x1FA27CF8);
+    b = doHH(b, c, d, a, x[k + 2], S34, 0xC4AC5665);
+    a = doII(a, b, c, d, x[k + 0], S41, 0xF4292244);
+    d = doII(d, a, b, c, x[k + 7], S42, 0x432AFF97);
+    c = doII(c, d, a, b, x[k + 14], S43, 0xAB9423A7);
+    b = doII(b, c, d, a, x[k + 5], S44, 0xFC93A039);
+    a = doII(a, b, c, d, x[k + 12], S41, 0x655B59C3);
+    d = doII(d, a, b, c, x[k + 3], S42, 0x8F0CCC92);
+    c = doII(c, d, a, b, x[k + 10], S43, 0xFFEFF47D);
+    b = doII(b, c, d, a, x[k + 1], S44, 0x85845DD1);
+    a = doII(a, b, c, d, x[k + 8], S41, 0x6FA87E4F);
+    d = doII(d, a, b, c, x[k + 15], S42, 0xFE2CE6E0);
+    c = doII(c, d, a, b, x[k + 6], S43, 0xA3014314);
+    b = doII(b, c, d, a, x[k + 13], S44, 0x4E0811A1);
+    a = doII(a, b, c, d, x[k + 4], S41, 0xF7537E82);
+    d = doII(d, a, b, c, x[k + 11], S42, 0xBD3AF235);
+    c = doII(c, d, a, b, x[k + 2], S43, 0x2AD7D2BB);
+    b = doII(b, c, d, a, x[k + 9], S44, 0xEB86D391);
+    a = addUnsigned(a, AA);
+    b = addUnsigned(b, BB);
+    c = addUnsigned(c, CC);
+    d = addUnsigned(d, DD);
+  }
+
+  var temp = wordToHex(a) + wordToHex(b) + wordToHex(c) + wordToHex(d);
+  return temp.toLowerCase();
+};
+
+exports.closeMediaStream = function (stream) {
+  if (!stream) {
+    return;
+  } // Latest spec states that MediaStream has no stop() method and instead must
+  // call stop() on every MediaStreamTrack.
+
+
+  try {
+    var tracks;
+
+    if (stream.getTracks) {
+      tracks = stream.getTracks();
+
+      var _iterator = _createForOfIteratorHelper(tracks),
+          _step;
+
+      try {
+        for (_iterator.s(); !(_step = _iterator.n()).done;) {
+          var track = _step.value;
+          track.stop();
+        }
+      } catch (err) {
+        _iterator.e(err);
+      } finally {
+        _iterator.f();
+      }
+    } else {
+      tracks = stream.getAudioTracks();
+
+      var _iterator2 = _createForOfIteratorHelper(tracks),
+          _step2;
+
+      try {
+        for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
+          var _track = _step2.value;
+
+          _track.stop();
+        }
+      } catch (err) {
+        _iterator2.e(err);
+      } finally {
+        _iterator2.f();
+      }
+
+      tracks = stream.getVideoTracks();
+
+      var _iterator3 = _createForOfIteratorHelper(tracks),
+          _step3;
+
+      try {
+        for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
+          var _track2 = _step3.value;
+
+          _track2.stop();
+        }
+      } catch (err) {
+        _iterator3.e(err);
+      } finally {
+        _iterator3.f();
+      }
+    }
+  } catch (error) {
+    // Deprecated by the spec, but still in use.
+    // NOTE: In Temasys IE plugin stream.stop is a callable 'object'.
+    if (typeof stream.stop === 'function' || _typeof(stream.stop) === 'object') {
+      stream.stop();
+    }
+  }
+};
+
+exports.cloneArray = function (array) {
+  return array && array.slice() || [];
+};
+
+exports.cloneObject = function (obj) {
+  var fallback = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
+  return obj && Object.assign({}, obj) || fallback;
+};
+},{"./Constants":2,"./Grammar":7,"./URI":27}],29:[function(require,module,exports){
+"use strict";
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
+
+function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
+
+var Logger = require('./Logger');
+
+var Grammar = require('./Grammar');
+
+var logger = new Logger('WebSocketInterface');
+
+module.exports = /*#__PURE__*/function () {
+  function WebSocketInterface(url) {
+    _classCallCheck(this, WebSocketInterface);
+
+    logger.debug('new() [url:"%s"]', url);
+    this._url = url;
+    this._sip_uri = null;
+    this._via_transport = null;
+    this._ws = null;
+    var parsed_url = Grammar.parse(url, 'absoluteURI');
+
+    if (parsed_url === -1) {
+      logger.warn("invalid WebSocket URI: ".concat(url));
+      throw new TypeError("Invalid argument: ".concat(url));
+    } else if (parsed_url.scheme !== 'wss' && parsed_url.scheme !== 'ws') {
+      logger.warn("invalid WebSocket URI scheme: ".concat(parsed_url.scheme));
+      throw new TypeError("Invalid argument: ".concat(url));
+    } else {
+      this._sip_uri = "sip:".concat(parsed_url.host).concat(parsed_url.port ? ":".concat(parsed_url.port) : '', ";transport=ws");
+      this._via_transport = parsed_url.scheme.toUpperCase();
+    }
+  }
+
+  _createClass(WebSocketInterface, [{
+    key: "connect",
+    value: function connect() {
+      logger.debug('connect()');
+
+      if (this.isConnected()) {
+        logger.debug("WebSocket ".concat(this._url, " is already connected"));
+        return;
+      } else if (this.isConnecting()) {
+        logger.debug("WebSocket ".concat(this._url, " is connecting"));
+        return;
+      }
+
+      if (this._ws) {
+        this.disconnect();
+      }
+
+      logger.debug("connecting to WebSocket ".concat(this._url));
+
+      try {
+        this._ws = new WebSocket(this._url, 'sip');
+        this._ws.binaryType = 'arraybuffer';
+        this._ws.onopen = this._onOpen.bind(this);
+        this._ws.onclose = this._onClose.bind(this);
+        this._ws.onmessage = this._onMessage.bind(this);
+        this._ws.onerror = this._onError.bind(this);
+      } catch (e) {
+        this._onError(e);
+      }
+    }
+  }, {
+    key: "disconnect",
+    value: function disconnect() {
+      logger.debug('disconnect()');
+
+      if (this._ws) {
+        // Unbind websocket event callbacks.
+        this._ws.onopen = function () {};
+
+        this._ws.onclose = function () {};
+
+        this._ws.onmessage = function () {};
+
+        this._ws.onerror = function () {};
+
+        this._ws.close();
+
+        this._ws = null;
+      }
+    }
+  }, {
+    key: "send",
+    value: function send(message) {
+      logger.debug('send()');
+
+      if (this.isConnected()) {
+        this._ws.send(message);
+
+        return true;
+      } else {
+        logger.warn('unable to send message, WebSocket is not open');
+        return false;
+      }
+    }
+  }, {
+    key: "isConnected",
+    value: function isConnected() {
+      return this._ws && this._ws.readyState === this._ws.OPEN;
+    }
+  }, {
+    key: "isConnecting",
+    value: function isConnecting() {
+      return this._ws && this._ws.readyState === this._ws.CONNECTING;
+    }
+    /**
+     * WebSocket Event Handlers
+     */
+
+  }, {
+    key: "_onOpen",
+    value: function _onOpen() {
+      logger.debug("WebSocket ".concat(this._url, " connected"));
+      this.onconnect();
+    }
+  }, {
+    key: "_onClose",
+    value: function _onClose(_ref) {
+      var wasClean = _ref.wasClean,
+          code = _ref.code,
+          reason = _ref.reason;
+      logger.debug("WebSocket ".concat(this._url, " closed"));
+
+      if (wasClean === false) {
+        logger.debug('WebSocket abrupt disconnection');
+      }
+
+      this.ondisconnect(!wasClean, code, reason);
+    }
+  }, {
+    key: "_onMessage",
+    value: function _onMessage(_ref2) {
+      var data = _ref2.data;
+      logger.debug('received WebSocket message');
+      this.ondata(data);
+    }
+  }, {
+    key: "_onError",
+    value: function _onError(e) {
+      logger.warn("WebSocket ".concat(this._url, " error: "), e);
+    }
+  }, {
+    key: "via_transport",
+    get: function get() {
+      return this._via_transport;
+    },
+    set: function set(value) {
+      this._via_transport = value.toUpperCase();
+    }
+  }, {
+    key: "sip_uri",
+    get: function get() {
+      return this._sip_uri;
+    }
+  }, {
+    key: "url",
+    get: function get() {
+      return this._url;
+    }
+  }]);
+
+  return WebSocketInterface;
+}();
+},{"./Grammar":7,"./Logger":9}],30:[function(require,module,exports){
+"use strict";
+
+function _createForOfIteratorHelper(o, allowArrayLike) { var it; if (typeof Symbol === "undefined" || o[Symbol.iterator] == null) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = o[Symbol.iterator](); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it["return"] != null) it["return"](); } finally { if (didErr) throw err; } } }; }
+
+function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
+
+function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; }
+
+var Logger = require('./Logger');
+
+var JsSIP_C = require('./Constants');
+
+var SIPMessage = require('./SIPMessage');
+
+var Utils = require('./Utils');
+
+var logger = new Logger('sanityCheck'); // Checks for requests and responses.
+
+var all = [minimumHeaders]; // Checks for requests.
+
+var requests = [rfc3261_8_2_2_1, rfc3261_16_3_4, rfc3261_18_3_request, rfc3261_8_2_2_2]; // Checks for responses.
+
+var responses = [rfc3261_8_1_3_3, rfc3261_18_3_response]; // local variables.
+
+var message;
+var ua;
+var transport;
+
+module.exports = function (m, u, t) {
+  message = m;
+  ua = u;
+  transport = t;
+
+  var _iterator = _createForOfIteratorHelper(all),
+      _step;
+
+  try {
+    for (_iterator.s(); !(_step = _iterator.n()).done;) {
+      var _check2 = _step.value;
+
+      if (_check2() === false) {
+        return false;
+      }
+    }
+  } catch (err) {
+    _iterator.e(err);
+  } finally {
+    _iterator.f();
+  }
+
+  if (message instanceof SIPMessage.IncomingRequest) {
+    var _iterator2 = _createForOfIteratorHelper(requests),
+        _step2;
+
+    try {
+      for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
+        var check = _step2.value;
+
+        if (check() === false) {
+          return false;
+        }
+      }
+    } catch (err) {
+      _iterator2.e(err);
+    } finally {
+      _iterator2.f();
+    }
+  } else if (message instanceof SIPMessage.IncomingResponse) {
+    var _iterator3 = _createForOfIteratorHelper(responses),
+        _step3;
+
+    try {
+      for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
+        var _check = _step3.value;
+
+        if (_check() === false) {
+          return false;
+        }
+      }
+    } catch (err) {
+      _iterator3.e(err);
+    } finally {
+      _iterator3.f();
+    }
+  } // Everything is OK.
+
+
+  return true;
+};
+/*
+ * Sanity Check for incoming Messages
+ *
+ * Requests:
+ *  - _rfc3261_8_2_2_1_ Receive a Request with a non supported URI scheme
+ *  - _rfc3261_16_3_4_ Receive a Request already sent by us
+ *   Does not look at via sent-by but at jssip_id, which is inserted as
+ *   a prefix in all initial requests generated by the ua
+ *  - _rfc3261_18_3_request_ Body Content-Length
+ *  - _rfc3261_8_2_2_2_ Merged Requests
+ *
+ * Responses:
+ *  - _rfc3261_8_1_3_3_ Multiple Via headers
+ *  - _rfc3261_18_3_response_ Body Content-Length
+ *
+ * All:
+ *  - Minimum headers in a SIP message
+ */
+// Sanity Check functions for requests.
+
+
+function rfc3261_8_2_2_1() {
+  if (message.s('to').uri.scheme !== 'sip') {
+    reply(416);
+    return false;
+  }
+}
+
+function rfc3261_16_3_4() {
+  if (!message.to_tag) {
+    if (message.call_id.substr(0, 5) === ua.configuration.jssip_id) {
+      reply(482);
+      return false;
+    }
+  }
+}
+
+function rfc3261_18_3_request() {
+  var len = Utils.str_utf8_length(message.body);
+  var contentLength = message.getHeader('content-length');
+
+  if (len < contentLength) {
+    reply(400);
+    return false;
+  }
+}
+
+function rfc3261_8_2_2_2() {
+  var fromTag = message.from_tag;
+  var call_id = message.call_id;
+  var cseq = message.cseq;
+  var tr; // Accept any in-dialog request.
+
+  if (message.to_tag) {
+    return;
+  } // INVITE request.
+
+
+  if (message.method === JsSIP_C.INVITE) {
+    // If the branch matches the key of any IST then assume it is a retransmission
+    // and ignore the INVITE.
+    // TODO: we should reply the last response.
+    if (ua._transactions.ist[message.via_branch]) {
+      return false;
+    } // Otherwise check whether it is a merged request.
+    else {
+        for (var transaction in ua._transactions.ist) {
+          if (Object.prototype.hasOwnProperty.call(ua._transactions.ist, transaction)) {
+            tr = ua._transactions.ist[transaction];
+
+            if (tr.request.from_tag === fromTag && tr.request.call_id === call_id && tr.request.cseq === cseq) {
+              reply(482);
+              return false;
+            }
+          }
+        }
+      }
+  } // Non INVITE request.
+  // If the branch matches the key of any NIST then assume it is a retransmission
+  // and ignore the request.
+  // TODO: we should reply the last response.
+  else if (ua._transactions.nist[message.via_branch]) {
+      return false;
+    } // Otherwise check whether it is a merged request.
+    else {
+        for (var _transaction in ua._transactions.nist) {
+          if (Object.prototype.hasOwnProperty.call(ua._transactions.nist, _transaction)) {
+            tr = ua._transactions.nist[_transaction];
+
+            if (tr.request.from_tag === fromTag && tr.request.call_id === call_id && tr.request.cseq === cseq) {
+              reply(482);
+              return false;
+            }
+          }
+        }
+      }
+} // Sanity Check functions for responses.
+
+
+function rfc3261_8_1_3_3() {
+  if (message.getHeaders('via').length > 1) {
+    logger.debug('more than one Via header field present in the response, dropping the response');
+    return false;
+  }
+}
+
+function rfc3261_18_3_response() {
+  var len = Utils.str_utf8_length(message.body),
+      contentLength = message.getHeader('content-length');
+
+  if (len < contentLength) {
+    logger.debug('message body length is lower than the value in Content-Length header field, dropping the response');
+    return false;
+  }
+} // Sanity Check functions for requests and responses.
+
+
+function minimumHeaders() {
+  var mandatoryHeaders = ['from', 'to', 'call_id', 'cseq', 'via'];
+
+  for (var _i = 0, _mandatoryHeaders = mandatoryHeaders; _i < _mandatoryHeaders.length; _i++) {
+    var header = _mandatoryHeaders[_i];
+
+    if (!message.hasHeader(header)) {
+      logger.debug("missing mandatory header field : ".concat(header, ", dropping the response"));
+      return false;
+    }
+  }
+} // Reply.
+
+
+function reply(status_code) {
+  var vias = message.getHeaders('via');
+  var to;
+  var response = "SIP/2.0 ".concat(status_code, " ").concat(JsSIP_C.REASON_PHRASE[status_code], "\r\n");
+
+  var _iterator4 = _createForOfIteratorHelper(vias),
+      _step4;
+
+  try {
+    for (_iterator4.s(); !(_step4 = _iterator4.n()).done;) {
+      var via = _step4.value;
+      response += "Via: ".concat(via, "\r\n");
+    }
+  } catch (err) {
+    _iterator4.e(err);
+  } finally {
+    _iterator4.f();
+  }
+
+  to = message.getHeader('To');
+
+  if (!message.to_tag) {
+    to += ";tag=".concat(Utils.newTag());
+  }
+
+  response += "To: ".concat(to, "\r\n");
+  response += "From: ".concat(message.getHeader('From'), "\r\n");
+  response += "Call-ID: ".concat(message.call_id, "\r\n");
+  response += "CSeq: ".concat(message.cseq, " ").concat(message.method, "\r\n");
+  response += '\r\n';
+  transport.send(response);
+}
+},{"./Constants":2,"./Logger":9,"./SIPMessage":21,"./Utils":28}],31:[function(require,module,exports){
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+var objectCreate = Object.create || objectCreatePolyfill
+var objectKeys = Object.keys || objectKeysPolyfill
+var bind = Function.prototype.bind || functionBindPolyfill
+
+function EventEmitter() {
+  if (!this._events || !Object.prototype.hasOwnProperty.call(this, '_events')) {
+    this._events = objectCreate(null);
+    this._eventsCount = 0;
+  }
+
+  this._maxListeners = this._maxListeners || undefined;
+}
+module.exports = EventEmitter;
+
+// Backwards-compat with node 0.10.x
+EventEmitter.EventEmitter = EventEmitter;
+
+EventEmitter.prototype._events = undefined;
+EventEmitter.prototype._maxListeners = undefined;
+
+// By default EventEmitters will print a warning if more than 10 listeners are
+// added to it. This is a useful default which helps finding memory leaks.
+var defaultMaxListeners = 10;
+
+var hasDefineProperty;
+try {
+  var o = {};
+  if (Object.defineProperty) Object.defineProperty(o, 'x', { value: 0 });
+  hasDefineProperty = o.x === 0;
+} catch (err) { hasDefineProperty = false }
+if (hasDefineProperty) {
+  Object.defineProperty(EventEmitter, 'defaultMaxListeners', {
+    enumerable: true,
+    get: function() {
+      return defaultMaxListeners;
+    },
+    set: function(arg) {
+      // check whether the input is a positive number (whose value is zero or
+      // greater and not a NaN).
+      if (typeof arg !== 'number' || arg < 0 || arg !== arg)
+        throw new TypeError('"defaultMaxListeners" must be a positive number');
+      defaultMaxListeners = arg;
+    }
+  });
+} else {
+  EventEmitter.defaultMaxListeners = defaultMaxListeners;
+}
+
+// Obviously not all Emitters should be limited to 10. This function allows
+// that to be increased. Set to zero for unlimited.
+EventEmitter.prototype.setMaxListeners = function setMaxListeners(n) {
+  if (typeof n !== 'number' || n < 0 || isNaN(n))
+    throw new TypeError('"n" argument must be a positive number');
+  this._maxListeners = n;
+  return this;
+};
+
+function $getMaxListeners(that) {
+  if (that._maxListeners === undefined)
+    return EventEmitter.defaultMaxListeners;
+  return that._maxListeners;
+}
+
+EventEmitter.prototype.getMaxListeners = function getMaxListeners() {
+  return $getMaxListeners(this);
+};
+
+// These standalone emit* functions are used to optimize calling of event
+// handlers for fast cases because emit() itself often has a variable number of
+// arguments and can be deoptimized because of that. These functions always have
+// the same number of arguments and thus do not get deoptimized, so the code
+// inside them can execute faster.
+function emitNone(handler, isFn, self) {
+  if (isFn)
+    handler.call(self);
+  else {
+    var len = handler.length;
+    var listeners = arrayClone(handler, len);
+    for (var i = 0; i < len; ++i)
+      listeners[i].call(self);
+  }
+}
+function emitOne(handler, isFn, self, arg1) {
+  if (isFn)
+    handler.call(self, arg1);
+  else {
+    var len = handler.length;
+    var listeners = arrayClone(handler, len);
+    for (var i = 0; i < len; ++i)
+      listeners[i].call(self, arg1);
+  }
+}
+function emitTwo(handler, isFn, self, arg1, arg2) {
+  if (isFn)
+    handler.call(self, arg1, arg2);
+  else {
+    var len = handler.length;
+    var listeners = arrayClone(handler, len);
+    for (var i = 0; i < len; ++i)
+      listeners[i].call(self, arg1, arg2);
+  }
+}
+function emitThree(handler, isFn, self, arg1, arg2, arg3) {
+  if (isFn)
+    handler.call(self, arg1, arg2, arg3);
+  else {
+    var len = handler.length;
+    var listeners = arrayClone(handler, len);
+    for (var i = 0; i < len; ++i)
+      listeners[i].call(self, arg1, arg2, arg3);
+  }
+}
+
+function emitMany(handler, isFn, self, args) {
+  if (isFn)
+    handler.apply(self, args);
+  else {
+    var len = handler.length;
+    var listeners = arrayClone(handler, len);
+    for (var i = 0; i < len; ++i)
+      listeners[i].apply(self, args);
+  }
+}
+
+EventEmitter.prototype.emit = function emit(type) {
+  var er, handler, len, args, i, events;
+  var doError = (type === 'error');
+
+  events = this._events;
+  if (events)
+    doError = (doError && events.error == null);
+  else if (!doError)
+    return false;
+
+  // If there is no 'error' event listener then throw.
+  if (doError) {
+    if (arguments.length > 1)
+      er = arguments[1];
+    if (er instanceof Error) {
+      throw er; // Unhandled 'error' event
+    } else {
+      // At least give some kind of context to the user
+      var err = new Error('Unhandled "error" event. (' + er + ')');
+      err.context = er;
+      throw err;
+    }
+    return false;
+  }
+
+  handler = events[type];
+
+  if (!handler)
+    return false;
+
+  var isFn = typeof handler === 'function';
+  len = arguments.length;
+  switch (len) {
+      // fast cases
+    case 1:
+      emitNone(handler, isFn, this);
+      break;
+    case 2:
+      emitOne(handler, isFn, this, arguments[1]);
+      break;
+    case 3:
+      emitTwo(handler, isFn, this, arguments[1], arguments[2]);
+      break;
+    case 4:
+      emitThree(handler, isFn, this, arguments[1], arguments[2], arguments[3]);
+      break;
+      // slower
+    default:
+      args = new Array(len - 1);
+      for (i = 1; i < len; i++)
+        args[i - 1] = arguments[i];
+      emitMany(handler, isFn, this, args);
+  }
+
+  return true;
+};
+
+function _addListener(target, type, listener, prepend) {
+  var m;
+  var events;
+  var existing;
+
+  if (typeof listener !== 'function')
+    throw new TypeError('"listener" argument must be a function');
+
+  events = target._events;
+  if (!events) {
+    events = target._events = objectCreate(null);
+    target._eventsCount = 0;
+  } else {
+    // To avoid recursion in the case that type === "newListener"! Before
+    // adding it to the listeners, first emit "newListener".
+    if (events.newListener) {
+      target.emit('newListener', type,
+          listener.listener ? listener.listener : listener);
+
+      // Re-assign `events` because a newListener handler could have caused the
+      // this._events to be assigned to a new object
+      events = target._events;
+    }
+    existing = events[type];
+  }
+
+  if (!existing) {
+    // Optimize the case of one listener. Don't need the extra array object.
+    existing = events[type] = listener;
+    ++target._eventsCount;
+  } else {
+    if (typeof existing === 'function') {
+      // Adding the second element, need to change to array.
+      existing = events[type] =
+          prepend ? [listener, existing] : [existing, listener];
+    } else {
+      // If we've already got an array, just append.
+      if (prepend) {
+        existing.unshift(listener);
+      } else {
+        existing.push(listener);
+      }
+    }
+
+    // Check for listener leak
+    if (!existing.warned) {
+      m = $getMaxListeners(target);
+      if (m && m > 0 && existing.length > m) {
+        existing.warned = true;
+        var w = new Error('Possible EventEmitter memory leak detected. ' +
+            existing.length + ' "' + String(type) + '" listeners ' +
+            'added. Use emitter.setMaxListeners() to ' +
+            'increase limit.');
+        w.name = 'MaxListenersExceededWarning';
+        w.emitter = target;
+        w.type = type;
+        w.count = existing.length;
+        if (typeof console === 'object' && console.warn) {
+          console.warn('%s: %s', w.name, w.message);
+        }
+      }
+    }
+  }
+
+  return target;
+}
+
+EventEmitter.prototype.addListener = function addListener(type, listener) {
+  return _addListener(this, type, listener, false);
+};
+
+EventEmitter.prototype.on = EventEmitter.prototype.addListener;
+
+EventEmitter.prototype.prependListener =
+    function prependListener(type, listener) {
+      return _addListener(this, type, listener, true);
+    };
+
+function onceWrapper() {
+  if (!this.fired) {
+    this.target.removeListener(this.type, this.wrapFn);
+    this.fired = true;
+    switch (arguments.length) {
+      case 0:
+        return this.listener.call(this.target);
+      case 1:
+        return this.listener.call(this.target, arguments[0]);
+      case 2:
+        return this.listener.call(this.target, arguments[0], arguments[1]);
+      case 3:
+        return this.listener.call(this.target, arguments[0], arguments[1],
+            arguments[2]);
+      default:
+        var args = new Array(arguments.length);
+        for (var i = 0; i < args.length; ++i)
+          args[i] = arguments[i];
+        this.listener.apply(this.target, args);
+    }
+  }
+}
+
+function _onceWrap(target, type, listener) {
+  var state = { fired: false, wrapFn: undefined, target: target, type: type, listener: listener };
+  var wrapped = bind.call(onceWrapper, state);
+  wrapped.listener = listener;
+  state.wrapFn = wrapped;
+  return wrapped;
+}
+
+EventEmitter.prototype.once = function once(type, listener) {
+  if (typeof listener !== 'function')
+    throw new TypeError('"listener" argument must be a function');
+  this.on(type, _onceWrap(this, type, listener));
+  return this;
+};
+
+EventEmitter.prototype.prependOnceListener =
+    function prependOnceListener(type, listener) {
+      if (typeof listener !== 'function')
+        throw new TypeError('"listener" argument must be a function');
+      this.prependListener(type, _onceWrap(this, type, listener));
+      return this;
+    };
+
+// Emits a 'removeListener' event if and only if the listener was removed.
+EventEmitter.prototype.removeListener =
+    function removeListener(type, listener) {
+      var list, events, position, i, originalListener;
+
+      if (typeof listener !== 'function')
+        throw new TypeError('"listener" argument must be a function');
+
+      events = this._events;
+      if (!events)
+        return this;
+
+      list = events[type];
+      if (!list)
+        return this;
+
+      if (list === listener || list.listener === listener) {
+        if (--this._eventsCount === 0)
+          this._events = objectCreate(null);
+        else {
+          delete events[type];
+          if (events.removeListener)
+            this.emit('removeListener', type, list.listener || listener);
+        }
+      } else if (typeof list !== 'function') {
+        position = -1;
+
+        for (i = list.length - 1; i >= 0; i--) {
+          if (list[i] === listener || list[i].listener === listener) {
+            originalListener = list[i].listener;
+            position = i;
+            break;
+          }
+        }
+
+        if (position < 0)
+          return this;
+
+        if (position === 0)
+          list.shift();
+        else
+          spliceOne(list, position);
+
+        if (list.length === 1)
+          events[type] = list[0];
+
+        if (events.removeListener)
+          this.emit('removeListener', type, originalListener || listener);
+      }
+
+      return this;
+    };
+
+EventEmitter.prototype.removeAllListeners =
+    function removeAllListeners(type) {
+      var listeners, events, i;
+
+      events = this._events;
+      if (!events)
+        return this;
+
+      // not listening for removeListener, no need to emit
+      if (!events.removeListener) {
+        if (arguments.length === 0) {
+          this._events = objectCreate(null);
+          this._eventsCount = 0;
+        } else if (events[type]) {
+          if (--this._eventsCount === 0)
+            this._events = objectCreate(null);
+          else
+            delete events[type];
+        }
+        return this;
+      }
+
+      // emit removeListener for all listeners on all events
+      if (arguments.length === 0) {
+        var keys = objectKeys(events);
+        var key;
+        for (i = 0; i < keys.length; ++i) {
+          key = keys[i];
+          if (key === 'removeListener') continue;
+          this.removeAllListeners(key);
+        }
+        this.removeAllListeners('removeListener');
+        this._events = objectCreate(null);
+        this._eventsCount = 0;
+        return this;
+      }
+
+      listeners = events[type];
+
+      if (typeof listeners === 'function') {
+        this.removeListener(type, listeners);
+      } else if (listeners) {
+        // LIFO order
+        for (i = listeners.length - 1; i >= 0; i--) {
+          this.removeListener(type, listeners[i]);
+        }
+      }
+
+      return this;
+    };
+
+function _listeners(target, type, unwrap) {
+  var events = target._events;
+
+  if (!events)
+    return [];
+
+  var evlistener = events[type];
+  if (!evlistener)
+    return [];
+
+  if (typeof evlistener === 'function')
+    return unwrap ? [evlistener.listener || evlistener] : [evlistener];
+
+  return unwrap ? unwrapListeners(evlistener) : arrayClone(evlistener, evlistener.length);
+}
+
+EventEmitter.prototype.listeners = function listeners(type) {
+  return _listeners(this, type, true);
+};
+
+EventEmitter.prototype.rawListeners = function rawListeners(type) {
+  return _listeners(this, type, false);
+};
+
+EventEmitter.listenerCount = function(emitter, type) {
+  if (typeof emitter.listenerCount === 'function') {
+    return emitter.listenerCount(type);
+  } else {
+    return listenerCount.call(emitter, type);
+  }
+};
+
+EventEmitter.prototype.listenerCount = listenerCount;
+function listenerCount(type) {
+  var events = this._events;
+
+  if (events) {
+    var evlistener = events[type];
+
+    if (typeof evlistener === 'function') {
+      return 1;
+    } else if (evlistener) {
+      return evlistener.length;
+    }
+  }
+
+  return 0;
+}
+
+EventEmitter.prototype.eventNames = function eventNames() {
+  return this._eventsCount > 0 ? Reflect.ownKeys(this._events) : [];
+};
+
+// About 1.5x faster than the two-arg version of Array#splice().
+function spliceOne(list, index) {
+  for (var i = index, k = i + 1, n = list.length; k < n; i += 1, k += 1)
+    list[i] = list[k];
+  list.pop();
+}
+
+function arrayClone(arr, n) {
+  var copy = new Array(n);
+  for (var i = 0; i < n; ++i)
+    copy[i] = arr[i];
+  return copy;
+}
+
+function unwrapListeners(arr) {
+  var ret = new Array(arr.length);
+  for (var i = 0; i < ret.length; ++i) {
+    ret[i] = arr[i].listener || arr[i];
+  }
+  return ret;
+}
+
+function objectCreatePolyfill(proto) {
+  var F = function() {};
+  F.prototype = proto;
+  return new F;
+}
+function objectKeysPolyfill(obj) {
+  var keys = [];
+  for (var k in obj) if (Object.prototype.hasOwnProperty.call(obj, k)) {
+    keys.push(k);
+  }
+  return k;
+}
+function functionBindPolyfill(context) {
+  var fn = this;
+  return function () {
+    return fn.apply(context, arguments);
+  };
+}
+
+},{}],32:[function(require,module,exports){
+(function (process){
+/* eslint-env browser */
+
+/**
+ * This is the web browser implementation of `debug()`.
+ */
+
+exports.log = log;
+exports.formatArgs = formatArgs;
+exports.save = save;
+exports.load = load;
+exports.useColors = useColors;
+exports.storage = localstorage();
+
+/**
+ * Colors.
+ */
+
+exports.colors = [
+	'#0000CC',
+	'#0000FF',
+	'#0033CC',
+	'#0033FF',
+	'#0066CC',
+	'#0066FF',
+	'#0099CC',
+	'#0099FF',
+	'#00CC00',
+	'#00CC33',
+	'#00CC66',
+	'#00CC99',
+	'#00CCCC',
+	'#00CCFF',
+	'#3300CC',
+	'#3300FF',
+	'#3333CC',
+	'#3333FF',
+	'#3366CC',
+	'#3366FF',
+	'#3399CC',
+	'#3399FF',
+	'#33CC00',
+	'#33CC33',
+	'#33CC66',
+	'#33CC99',
+	'#33CCCC',
+	'#33CCFF',
+	'#6600CC',
+	'#6600FF',
+	'#6633CC',
+	'#6633FF',
+	'#66CC00',
+	'#66CC33',
+	'#9900CC',
+	'#9900FF',
+	'#9933CC',
+	'#9933FF',
+	'#99CC00',
+	'#99CC33',
+	'#CC0000',
+	'#CC0033',
+	'#CC0066',
+	'#CC0099',
+	'#CC00CC',
+	'#CC00FF',
+	'#CC3300',
+	'#CC3333',
+	'#CC3366',
+	'#CC3399',
+	'#CC33CC',
+	'#CC33FF',
+	'#CC6600',
+	'#CC6633',
+	'#CC9900',
+	'#CC9933',
+	'#CCCC00',
+	'#CCCC33',
+	'#FF0000',
+	'#FF0033',
+	'#FF0066',
+	'#FF0099',
+	'#FF00CC',
+	'#FF00FF',
+	'#FF3300',
+	'#FF3333',
+	'#FF3366',
+	'#FF3399',
+	'#FF33CC',
+	'#FF33FF',
+	'#FF6600',
+	'#FF6633',
+	'#FF9900',
+	'#FF9933',
+	'#FFCC00',
+	'#FFCC33'
+];
+
+/**
+ * Currently only WebKit-based Web Inspectors, Firefox >= v31,
+ * and the Firebug extension (any Firefox version) are known
+ * to support "%c" CSS customizations.
+ *
+ * TODO: add a `localStorage` variable to explicitly enable/disable colors
+ */
+
+// eslint-disable-next-line complexity
+function useColors() {
+	// NB: In an Electron preload script, document will be defined but not fully
+	// initialized. Since we know we're in Chrome, we'll just detect this case
+	// explicitly
+	if (typeof window !== 'undefined' && window.process && (window.process.type === 'renderer' || window.process.__nwjs)) {
+		return true;
+	}
+
+	// Internet Explorer and Edge do not support colors.
+	if (typeof navigator !== 'undefined' && navigator.userAgent && navigator.userAgent.toLowerCase().match(/(edge|trident)\/(\d+)/)) {
+		return false;
+	}
+
+	// Is webkit? http://stackoverflow.com/a/16459606/376773
+	// document is undefined in react-native: https://github.com/facebook/react-native/pull/1632
+	return (typeof document !== 'undefined' && document.documentElement && document.documentElement.style && document.documentElement.style.WebkitAppearance) ||
+		// Is firebug? http://stackoverflow.com/a/398120/376773
+		(typeof window !== 'undefined' && window.console && (window.console.firebug || (window.console.exception && window.console.table))) ||
+		// Is firefox >= v31?
+		// https://developer.mozilla.org/en-US/docs/Tools/Web_Console#Styling_messages
+		(typeof navigator !== 'undefined' && navigator.userAgent && navigator.userAgent.toLowerCase().match(/firefox\/(\d+)/) && parseInt(RegExp.$1, 10) >= 31) ||
+		// Double check webkit in userAgent just in case we are in a worker
+		(typeof navigator !== 'undefined' && navigator.userAgent && navigator.userAgent.toLowerCase().match(/applewebkit\/(\d+)/));
+}
+
+/**
+ * Colorize log arguments if enabled.
+ *
+ * @api public
+ */
+
+function formatArgs(args) {
+	args[0] = (this.useColors ? '%c' : '') +
+		this.namespace +
+		(this.useColors ? ' %c' : ' ') +
+		args[0] +
+		(this.useColors ? '%c ' : ' ') +
+		'+' + module.exports.humanize(this.diff);
+
+	if (!this.useColors) {
+		return;
+	}
+
+	const c = 'color: ' + this.color;
+	args.splice(1, 0, c, 'color: inherit');
+
+	// The final "%c" is somewhat tricky, because there could be other
+	// arguments passed either before or after the %c, so we need to
+	// figure out the correct index to insert the CSS into
+	let index = 0;
+	let lastC = 0;
+	args[0].replace(/%[a-zA-Z%]/g, match => {
+		if (match === '%%') {
+			return;
+		}
+		index++;
+		if (match === '%c') {
+			// We only are interested in the *last* %c
+			// (the user may have provided their own)
+			lastC = index;
+		}
+	});
+
+	args.splice(lastC, 0, c);
+}
+
+/**
+ * Invokes `console.log()` when available.
+ * No-op when `console.log` is not a "function".
+ *
+ * @api public
+ */
+function log(...args) {
+	// This hackery is required for IE8/9, where
+	// the `console.log` function doesn't have 'apply'
+	return typeof console === 'object' &&
+		console.log &&
+		console.log(...args);
+}
+
+/**
+ * Save `namespaces`.
+ *
+ * @param {String} namespaces
+ * @api private
+ */
+function save(namespaces) {
+	try {
+		if (namespaces) {
+			exports.storage.setItem('debug', namespaces);
+		} else {
+			exports.storage.removeItem('debug');
+		}
+	} catch (error) {
+		// Swallow
+		// XXX (@Qix-) should we be logging these?
+	}
+}
+
+/**
+ * Load `namespaces`.
+ *
+ * @return {String} returns the previously persisted debug modes
+ * @api private
+ */
+function load() {
+	let r;
+	try {
+		r = exports.storage.getItem('debug');
+	} catch (error) {
+		// Swallow
+		// XXX (@Qix-) should we be logging these?
+	}
+
+	// If debug isn't set in LS, and we're in Electron, try to load $DEBUG
+	if (!r && typeof process !== 'undefined' && 'env' in process) {
+		r = process.env.DEBUG;
+	}
+
+	return r;
+}
+
+/**
+ * Localstorage attempts to return the localstorage.
+ *
+ * This is necessary because safari throws
+ * when a user disables cookies/localstorage
+ * and you attempt to access it.
+ *
+ * @return {LocalStorage}
+ * @api private
+ */
+
+function localstorage() {
+	try {
+		// TVMLKit (Apple TV JS Runtime) does not have a window object, just localStorage in the global context
+		// The Browser also has localStorage in the global context.
+		return localStorage;
+	} catch (error) {
+		// Swallow
+		// XXX (@Qix-) should we be logging these?
+	}
+}
+
+module.exports = require('./common')(exports);
+
+const {formatters} = module.exports;
+
+/**
+ * Map %j to `JSON.stringify()`, since no Web Inspectors do that by default.
+ */
+
+formatters.j = function (v) {
+	try {
+		return JSON.stringify(v);
+	} catch (error) {
+		return '[UnexpectedJSONParseError]: ' + error.message;
+	}
+};
+
+}).call(this,require('_process'))
+},{"./common":33,"_process":35}],33:[function(require,module,exports){
+
+/**
+ * This is the common logic for both the Node.js and web browser
+ * implementations of `debug()`.
+ */
+
+function setup(env) {
+	createDebug.debug = createDebug;
+	createDebug.default = createDebug;
+	createDebug.coerce = coerce;
+	createDebug.disable = disable;
+	createDebug.enable = enable;
+	createDebug.enabled = enabled;
+	createDebug.humanize = require('ms');
+
+	Object.keys(env).forEach(key => {
+		createDebug[key] = env[key];
+	});
+
+	/**
+	* Active `debug` instances.
+	*/
+	createDebug.instances = [];
+
+	/**
+	* The currently active debug mode names, and names to skip.
+	*/
+
+	createDebug.names = [];
+	createDebug.skips = [];
+
+	/**
+	* Map of special "%n" handling functions, for the debug "format" argument.
+	*
+	* Valid key names are a single, lower or upper-case letter, i.e. "n" and "N".
+	*/
+	createDebug.formatters = {};
+
+	/**
+	* Selects a color for a debug namespace
+	* @param {String} namespace The namespace string for the for the debug instance to be colored
+	* @return {Number|String} An ANSI color code for the given namespace
+	* @api private
+	*/
+	function selectColor(namespace) {
+		let hash = 0;
+
+		for (let i = 0; i < namespace.length; i++) {
+			hash = ((hash << 5) - hash) + namespace.charCodeAt(i);
+			hash |= 0; // Convert to 32bit integer
+		}
+
+		return createDebug.colors[Math.abs(hash) % createDebug.colors.length];
+	}
+	createDebug.selectColor = selectColor;
+
+	/**
+	* Create a debugger with the given `namespace`.
+	*
+	* @param {String} namespace
+	* @return {Function}
+	* @api public
+	*/
+	function createDebug(namespace) {
+		let prevTime;
+
+		function debug(...args) {
+			// Disabled?
+			if (!debug.enabled) {
+				return;
+			}
+
+			const self = debug;
+
+			// Set `diff` timestamp
+			const curr = Number(new Date());
+			const ms = curr - (prevTime || curr);
+			self.diff = ms;
+			self.prev = prevTime;
+			self.curr = curr;
+			prevTime = curr;
+
+			args[0] = createDebug.coerce(args[0]);
+
+			if (typeof args[0] !== 'string') {
+				// Anything else let's inspect with %O
+				args.unshift('%O');
+			}
+
+			// Apply any `formatters` transformations
+			let index = 0;
+			args[0] = args[0].replace(/%([a-zA-Z%])/g, (match, format) => {
+				// If we encounter an escaped % then don't increase the array index
+				if (match === '%%') {
+					return match;
+				}
+				index++;
+				const formatter = createDebug.formatters[format];
+				if (typeof formatter === 'function') {
+					const val = args[index];
+					match = formatter.call(self, val);
+
+					// Now we need to remove `args[index]` since it's inlined in the `format`
+					args.splice(index, 1);
+					index--;
+				}
+				return match;
+			});
+
+			// Apply env-specific formatting (colors, etc.)
+			createDebug.formatArgs.call(self, args);
+
+			const logFn = self.log || createDebug.log;
+			logFn.apply(self, args);
+		}
+
+		debug.namespace = namespace;
+		debug.enabled = createDebug.enabled(namespace);
+		debug.useColors = createDebug.useColors();
+		debug.color = selectColor(namespace);
+		debug.destroy = destroy;
+		debug.extend = extend;
+		// Debug.formatArgs = formatArgs;
+		// debug.rawLog = rawLog;
+
+		// env-specific initialization logic for debug instances
+		if (typeof createDebug.init === 'function') {
+			createDebug.init(debug);
+		}
+
+		createDebug.instances.push(debug);
+
+		return debug;
+	}
+
+	function destroy() {
+		const index = createDebug.instances.indexOf(this);
+		if (index !== -1) {
+			createDebug.instances.splice(index, 1);
+			return true;
+		}
+		return false;
+	}
+
+	function extend(namespace, delimiter) {
+		const newDebug = createDebug(this.namespace + (typeof delimiter === 'undefined' ? ':' : delimiter) + namespace);
+		newDebug.log = this.log;
+		return newDebug;
+	}
+
+	/**
+	* Enables a debug mode by namespaces. This can include modes
+	* separated by a colon and wildcards.
+	*
+	* @param {String} namespaces
+	* @api public
+	*/
+	function enable(namespaces) {
+		createDebug.save(namespaces);
+
+		createDebug.names = [];
+		createDebug.skips = [];
+
+		let i;
+		const split = (typeof namespaces === 'string' ? namespaces : '').split(/[\s,]+/);
+		const len = split.length;
+
+		for (i = 0; i < len; i++) {
+			if (!split[i]) {
+				// ignore empty strings
+				continue;
+			}
+
+			namespaces = split[i].replace(/\*/g, '.*?');
+
+			if (namespaces[0] === '-') {
+				createDebug.skips.push(new RegExp('^' + namespaces.substr(1) + '$'));
+			} else {
+				createDebug.names.push(new RegExp('^' + namespaces + '$'));
+			}
+		}
+
+		for (i = 0; i < createDebug.instances.length; i++) {
+			const instance = createDebug.instances[i];
+			instance.enabled = createDebug.enabled(instance.namespace);
+		}
+	}
+
+	/**
+	* Disable debug output.
+	*
+	* @return {String} namespaces
+	* @api public
+	*/
+	function disable() {
+		const namespaces = [
+			...createDebug.names.map(toNamespace),
+			...createDebug.skips.map(toNamespace).map(namespace => '-' + namespace)
+		].join(',');
+		createDebug.enable('');
+		return namespaces;
+	}
+
+	/**
+	* Returns true if the given mode name is enabled, false otherwise.
+	*
+	* @param {String} name
+	* @return {Boolean}
+	* @api public
+	*/
+	function enabled(name) {
+		if (name[name.length - 1] === '*') {
+			return true;
+		}
+
+		let i;
+		let len;
+
+		for (i = 0, len = createDebug.skips.length; i < len; i++) {
+			if (createDebug.skips[i].test(name)) {
+				return false;
+			}
+		}
+
+		for (i = 0, len = createDebug.names.length; i < len; i++) {
+			if (createDebug.names[i].test(name)) {
+				return true;
+			}
+		}
+
+		return false;
+	}
+
+	/**
+	* Convert regexp to namespace
+	*
+	* @param {RegExp} regxep
+	* @return {String} namespace
+	* @api private
+	*/
+	function toNamespace(regexp) {
+		return regexp.toString()
+			.substring(2, regexp.toString().length - 2)
+			.replace(/\.\*\?$/, '*');
+	}
+
+	/**
+	* Coerce `val`.
+	*
+	* @param {Mixed} val
+	* @return {Mixed}
+	* @api private
+	*/
+	function coerce(val) {
+		if (val instanceof Error) {
+			return val.stack || val.message;
+		}
+		return val;
+	}
+
+	createDebug.enable(createDebug.load());
+
+	return createDebug;
+}
+
+module.exports = setup;
+
+},{"ms":34}],34:[function(require,module,exports){
+/**
+ * Helpers.
+ */
+
+var s = 1000;
+var m = s * 60;
+var h = m * 60;
+var d = h * 24;
+var w = d * 7;
+var y = d * 365.25;
+
+/**
+ * Parse or format the given `val`.
+ *
+ * Options:
+ *
+ *  - `long` verbose formatting [false]
+ *
+ * @param {String|Number} val
+ * @param {Object} [options]
+ * @throws {Error} throw an error if val is not a non-empty string or a number
+ * @return {String|Number}
+ * @api public
+ */
+
+module.exports = function(val, options) {
+  options = options || {};
+  var type = typeof val;
+  if (type === 'string' && val.length > 0) {
+    return parse(val);
+  } else if (type === 'number' && isFinite(val)) {
+    return options.long ? fmtLong(val) : fmtShort(val);
+  }
+  throw new Error(
+    'val is not a non-empty string or a valid number. val=' +
+      JSON.stringify(val)
+  );
+};
+
+/**
+ * Parse the given `str` and return milliseconds.
+ *
+ * @param {String} str
+ * @return {Number}
+ * @api private
+ */
+
+function parse(str) {
+  str = String(str);
+  if (str.length > 100) {
+    return;
+  }
+  var match = /^(-?(?:\d+)?\.?\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|weeks?|w|years?|yrs?|y)?$/i.exec(
+    str
+  );
+  if (!match) {
+    return;
+  }
+  var n = parseFloat(match[1]);
+  var type = (match[2] || 'ms').toLowerCase();
+  switch (type) {
+    case 'years':
+    case 'year':
+    case 'yrs':
+    case 'yr':
+    case 'y':
+      return n * y;
+    case 'weeks':
+    case 'week':
+    case 'w':
+      return n * w;
+    case 'days':
+    case 'day':
+    case 'd':
+      return n * d;
+    case 'hours':
+    case 'hour':
+    case 'hrs':
+    case 'hr':
+    case 'h':
+      return n * h;
+    case 'minutes':
+    case 'minute':
+    case 'mins':
+    case 'min':
+    case 'm':
+      return n * m;
+    case 'seconds':
+    case 'second':
+    case 'secs':
+    case 'sec':
+    case 's':
+      return n * s;
+    case 'milliseconds':
+    case 'millisecond':
+    case 'msecs':
+    case 'msec':
+    case 'ms':
+      return n;
+    default:
+      return undefined;
+  }
+}
+
+/**
+ * Short format for `ms`.
+ *
+ * @param {Number} ms
+ * @return {String}
+ * @api private
+ */
+
+function fmtShort(ms) {
+  var msAbs = Math.abs(ms);
+  if (msAbs >= d) {
+    return Math.round(ms / d) + 'd';
+  }
+  if (msAbs >= h) {
+    return Math.round(ms / h) + 'h';
+  }
+  if (msAbs >= m) {
+    return Math.round(ms / m) + 'm';
+  }
+  if (msAbs >= s) {
+    return Math.round(ms / s) + 's';
+  }
+  return ms + 'ms';
+}
+
+/**
+ * Long format for `ms`.
+ *
+ * @param {Number} ms
+ * @return {String}
+ * @api private
+ */
+
+function fmtLong(ms) {
+  var msAbs = Math.abs(ms);
+  if (msAbs >= d) {
+    return plural(ms, msAbs, d, 'day');
+  }
+  if (msAbs >= h) {
+    return plural(ms, msAbs, h, 'hour');
+  }
+  if (msAbs >= m) {
+    return plural(ms, msAbs, m, 'minute');
+  }
+  if (msAbs >= s) {
+    return plural(ms, msAbs, s, 'second');
+  }
+  return ms + ' ms';
+}
+
+/**
+ * Pluralization helper.
+ */
+
+function plural(ms, msAbs, n, name) {
+  var isPlural = msAbs >= n * 1.5;
+  return Math.round(ms / n) + ' ' + name + (isPlural ? 's' : '');
+}
+
+},{}],35:[function(require,module,exports){
+// shim for using process in browser
+var process = module.exports = {};
+
+// cached from whatever global is present so that test runners that stub it
+// don't break things.  But we need to wrap it in a try catch in case it is
+// wrapped in strict mode code which doesn't define any globals.  It's inside a
+// function because try/catches deoptimize in certain engines.
+
+var cachedSetTimeout;
+var cachedClearTimeout;
+
+function defaultSetTimout() {
+    throw new Error('setTimeout has not been defined');
+}
+function defaultClearTimeout () {
+    throw new Error('clearTimeout has not been defined');
+}
+(function () {
+    try {
+        if (typeof setTimeout === 'function') {
+            cachedSetTimeout = setTimeout;
+        } else {
+            cachedSetTimeout = defaultSetTimout;
+        }
+    } catch (e) {
+        cachedSetTimeout = defaultSetTimout;
+    }
+    try {
+        if (typeof clearTimeout === 'function') {
+            cachedClearTimeout = clearTimeout;
+        } else {
+            cachedClearTimeout = defaultClearTimeout;
+        }
+    } catch (e) {
+        cachedClearTimeout = defaultClearTimeout;
+    }
+} ())
+function runTimeout(fun) {
+    if (cachedSetTimeout === setTimeout) {
+        //normal enviroments in sane situations
+        return setTimeout(fun, 0);
+    }
+    // if setTimeout wasn't available but was latter defined
+    if ((cachedSetTimeout === defaultSetTimout || !cachedSetTimeout) && setTimeout) {
+        cachedSetTimeout = setTimeout;
+        return setTimeout(fun, 0);
+    }
+    try {
+        // when when somebody has screwed with setTimeout but no I.E. maddness
+        return cachedSetTimeout(fun, 0);
+    } catch(e){
+        try {
+            // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally
+            return cachedSetTimeout.call(null, fun, 0);
+        } catch(e){
+            // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error
+            return cachedSetTimeout.call(this, fun, 0);
+        }
+    }
+
+
+}
+function runClearTimeout(marker) {
+    if (cachedClearTimeout === clearTimeout) {
+        //normal enviroments in sane situations
+        return clearTimeout(marker);
+    }
+    // if clearTimeout wasn't available but was latter defined
+    if ((cachedClearTimeout === defaultClearTimeout || !cachedClearTimeout) && clearTimeout) {
+        cachedClearTimeout = clearTimeout;
+        return clearTimeout(marker);
+    }
+    try {
+        // when when somebody has screwed with setTimeout but no I.E. maddness
+        return cachedClearTimeout(marker);
+    } catch (e){
+        try {
+            // When we are in I.E. but the script has been evaled so I.E. doesn't  trust the global object when called normally
+            return cachedClearTimeout.call(null, marker);
+        } catch (e){
+            // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error.
+            // Some versions of I.E. have different rules for clearTimeout vs setTimeout
+            return cachedClearTimeout.call(this, marker);
+        }
+    }
+
+
+
+}
+var queue = [];
+var draining = false;
+var currentQueue;
+var queueIndex = -1;
+
+function cleanUpNextTick() {
+    if (!draining || !currentQueue) {
+        return;
+    }
+    draining = false;
+    if (currentQueue.length) {
+        queue = currentQueue.concat(queue);
+    } else {
+        queueIndex = -1;
+    }
+    if (queue.length) {
+        drainQueue();
+    }
+}
+
+function drainQueue() {
+    if (draining) {
+        return;
+    }
+    var timeout = runTimeout(cleanUpNextTick);
+    draining = true;
+
+    var len = queue.length;
+    while(len) {
+        currentQueue = queue;
+        queue = [];
+        while (++queueIndex < len) {
+            if (currentQueue) {
+                currentQueue[queueIndex].run();
+            }
+        }
+        queueIndex = -1;
+        len = queue.length;
+    }
+    currentQueue = null;
+    draining = false;
+    runClearTimeout(timeout);
+}
+
+process.nextTick = function (fun) {
+    var args = new Array(arguments.length - 1);
+    if (arguments.length > 1) {
+        for (var i = 1; i < arguments.length; i++) {
+            args[i - 1] = arguments[i];
+        }
+    }
+    queue.push(new Item(fun, args));
+    if (queue.length === 1 && !draining) {
+        runTimeout(drainQueue);
+    }
+};
+
+// v8 likes predictible objects
+function Item(fun, array) {
+    this.fun = fun;
+    this.array = array;
+}
+Item.prototype.run = function () {
+    this.fun.apply(null, this.array);
+};
+process.title = 'browser';
+process.browser = true;
+process.env = {};
+process.argv = [];
+process.version = ''; // empty string to avoid regexp issues
+process.versions = {};
+
+function noop() {}
+
+process.on = noop;
+process.addListener = noop;
+process.once = noop;
+process.off = noop;
+process.removeListener = noop;
+process.removeAllListeners = noop;
+process.emit = noop;
+process.prependListener = noop;
+process.prependOnceListener = noop;
+
+process.listeners = function (name) { return [] }
+
+process.binding = function (name) {
+    throw new Error('process.binding is not supported');
+};
+
+process.cwd = function () { return '/' };
+process.chdir = function (dir) {
+    throw new Error('process.chdir is not supported');
+};
+process.umask = function() { return 0; };
+
+},{}],36:[function(require,module,exports){
+var grammar = module.exports = {
+  v: [{
+    name: 'version',
+    reg: /^(\d*)$/
+  }],
+  o: [{
+    // o=- 20518 0 IN IP4 203.0.113.1
+    // NB: sessionId will be a String in most cases because it is huge
+    name: 'origin',
+    reg: /^(\S*) (\d*) (\d*) (\S*) IP(\d) (\S*)/,
+    names: ['username', 'sessionId', 'sessionVersion', 'netType', 'ipVer', 'address'],
+    format: '%s %s %d %s IP%d %s'
+  }],
+  // default parsing of these only (though some of these feel outdated)
+  s: [{ name: 'name' }],
+  i: [{ name: 'description' }],
+  u: [{ name: 'uri' }],
+  e: [{ name: 'email' }],
+  p: [{ name: 'phone' }],
+  z: [{ name: 'timezones' }], // TODO: this one can actually be parsed properly...
+  r: [{ name: 'repeats' }],   // TODO: this one can also be parsed properly
+  // k: [{}], // outdated thing ignored
+  t: [{
+    // t=0 0
+    name: 'timing',
+    reg: /^(\d*) (\d*)/,
+    names: ['start', 'stop'],
+    format: '%d %d'
+  }],
+  c: [{
+    // c=IN IP4 10.47.197.26
+    name: 'connection',
+    reg: /^IN IP(\d) (\S*)/,
+    names: ['version', 'ip'],
+    format: 'IN IP%d %s'
+  }],
+  b: [{
+    // b=AS:4000
+    push: 'bandwidth',
+    reg: /^(TIAS|AS|CT|RR|RS):(\d*)/,
+    names: ['type', 'limit'],
+    format: '%s:%s'
+  }],
+  m: [{
+    // m=video 51744 RTP/AVP 126 97 98 34 31
+    // NB: special - pushes to session
+    // TODO: rtp/fmtp should be filtered by the payloads found here?
+    reg: /^(\w*) (\d*) ([\w/]*)(?: (.*))?/,
+    names: ['type', 'port', 'protocol', 'payloads'],
+    format: '%s %d %s %s'
+  }],
+  a: [
+    {
+      // a=rtpmap:110 opus/48000/2
+      push: 'rtp',
+      reg: /^rtpmap:(\d*) ([\w\-.]*)(?:\s*\/(\d*)(?:\s*\/(\S*))?)?/,
+      names: ['payload', 'codec', 'rate', 'encoding'],
+      format: function (o) {
+        return (o.encoding)
+          ? 'rtpmap:%d %s/%s/%s'
+          : o.rate
+            ? 'rtpmap:%d %s/%s'
+            : 'rtpmap:%d %s';
+      }
+    },
+    {
+      // a=fmtp:108 profile-level-id=24;object=23;bitrate=64000
+      // a=fmtp:111 minptime=10; useinbandfec=1
+      push: 'fmtp',
+      reg: /^fmtp:(\d*) ([\S| ]*)/,
+      names: ['payload', 'config'],
+      format: 'fmtp:%d %s'
+    },
+    {
+      // a=control:streamid=0
+      name: 'control',
+      reg: /^control:(.*)/,
+      format: 'control:%s'
+    },
+    {
+      // a=rtcp:65179 IN IP4 193.84.77.194
+      name: 'rtcp',
+      reg: /^rtcp:(\d*)(?: (\S*) IP(\d) (\S*))?/,
+      names: ['port', 'netType', 'ipVer', 'address'],
+      format: function (o) {
+        return (o.address != null)
+          ? 'rtcp:%d %s IP%d %s'
+          : 'rtcp:%d';
+      }
+    },
+    {
+      // a=rtcp-fb:98 trr-int 100
+      push: 'rtcpFbTrrInt',
+      reg: /^rtcp-fb:(\*|\d*) trr-int (\d*)/,
+      names: ['payload', 'value'],
+      format: 'rtcp-fb:%d trr-int %d'
+    },
+    {
+      // a=rtcp-fb:98 nack rpsi
+      push: 'rtcpFb',
+      reg: /^rtcp-fb:(\*|\d*) ([\w-_]*)(?: ([\w-_]*))?/,
+      names: ['payload', 'type', 'subtype'],
+      format: function (o) {
+        return (o.subtype != null)
+          ? 'rtcp-fb:%s %s %s'
+          : 'rtcp-fb:%s %s';
+      }
+    },
+    {
+      // a=extmap:2 urn:ietf:params:rtp-hdrext:toffset
+      // a=extmap:1/recvonly URI-gps-string
+      // a=extmap:3 urn:ietf:params:rtp-hdrext:encrypt urn:ietf:params:rtp-hdrext:smpte-tc 25@600/24
+      push: 'ext',
+      reg: /^extmap:(\d+)(?:\/(\w+))?(?: (urn:ietf:params:rtp-hdrext:encrypt))? (\S*)(?: (\S*))?/,
+      names: ['value', 'direction', 'encrypt-uri', 'uri', 'config'],
+      format: function (o) {
+        return (
+          'extmap:%d' +
+          (o.direction ? '/%s' : '%v') +
+          (o['encrypt-uri'] ? ' %s' : '%v') +
+          ' %s' +
+          (o.config ? ' %s' : '')
+        );
+      }
+    },
+    {
+      // a=extmap-allow-mixed
+      name: 'extmapAllowMixed',
+      reg: /^(extmap-allow-mixed)/
+    },
+    {
+      // a=crypto:1 AES_CM_128_HMAC_SHA1_80 inline:PS1uQCVeeCFCanVmcjkpPywjNWhcYD0mXXtxaVBR|2^20|1:32
+      push: 'crypto',
+      reg: /^crypto:(\d*) ([\w_]*) (\S*)(?: (\S*))?/,
+      names: ['id', 'suite', 'config', 'sessionConfig'],
+      format: function (o) {
+        return (o.sessionConfig != null)
+          ? 'crypto:%d %s %s %s'
+          : 'crypto:%d %s %s';
+      }
+    },
+    {
+      // a=setup:actpass
+      name: 'setup',
+      reg: /^setup:(\w*)/,
+      format: 'setup:%s'
+    },
+    {
+      // a=connection:new
+      name: 'connectionType',
+      reg: /^connection:(new|existing)/,
+      format: 'connection:%s'
+    },
+    {
+      // a=mid:1
+      name: 'mid',
+      reg: /^mid:([^\s]*)/,
+      format: 'mid:%s'
+    },
+    {
+      // a=msid:0c8b064d-d807-43b4-b434-f92a889d8587 98178685-d409-46e0-8e16-7ef0db0db64a
+      name: 'msid',
+      reg: /^msid:(.*)/,
+      format: 'msid:%s'
+    },
+    {
+      // a=ptime:20
+      name: 'ptime',
+      reg: /^ptime:(\d*(?:\.\d*)*)/,
+      format: 'ptime:%d'
+    },
+    {
+      // a=maxptime:60
+      name: 'maxptime',
+      reg: /^maxptime:(\d*(?:\.\d*)*)/,
+      format: 'maxptime:%d'
+    },
+    {
+      // a=sendrecv
+      name: 'direction',
+      reg: /^(sendrecv|recvonly|sendonly|inactive)/
+    },
+    {
+      // a=ice-lite
+      name: 'icelite',
+      reg: /^(ice-lite)/
+    },
+    {
+      // a=ice-ufrag:F7gI
+      name: 'iceUfrag',
+      reg: /^ice-ufrag:(\S*)/,
+      format: 'ice-ufrag:%s'
+    },
+    {
+      // a=ice-pwd:x9cml/YzichV2+XlhiMu8g
+      name: 'icePwd',
+      reg: /^ice-pwd:(\S*)/,
+      format: 'ice-pwd:%s'
+    },
+    {
+      // a=fingerprint:SHA-1 00:11:22:33:44:55:66:77:88:99:AA:BB:CC:DD:EE:FF:00:11:22:33
+      name: 'fingerprint',
+      reg: /^fingerprint:(\S*) (\S*)/,
+      names: ['type', 'hash'],
+      format: 'fingerprint:%s %s'
+    },
+    {
+      // a=candidate:0 1 UDP 2113667327 203.0.113.1 54400 typ host
+      // a=candidate:1162875081 1 udp 2113937151 192.168.34.75 60017 typ host generation 0 network-id 3 network-cost 10
+      // a=candidate:3289912957 2 udp 1845501695 193.84.77.194 60017 typ srflx raddr 192.168.34.75 rport 60017 generation 0 network-id 3 network-cost 10
+      // a=candidate:229815620 1 tcp 1518280447 192.168.150.19 60017 typ host tcptype active generation 0 network-id 3 network-cost 10
+      // a=candidate:3289912957 2 tcp 1845501695 193.84.77.194 60017 typ srflx raddr 192.168.34.75 rport 60017 tcptype passive generation 0 network-id 3 network-cost 10
+      push:'candidates',
+      reg: /^candidate:(\S*) (\d*) (\S*) (\d*) (\S*) (\d*) typ (\S*)(?: raddr (\S*) rport (\d*))?(?: tcptype (\S*))?(?: generation (\d*))?(?: network-id (\d*))?(?: network-cost (\d*))?/,
+      names: ['foundation', 'component', 'transport', 'priority', 'ip', 'port', 'type', 'raddr', 'rport', 'tcptype', 'generation', 'network-id', 'network-cost'],
+      format: function (o) {
+        var str = 'candidate:%s %d %s %d %s %d typ %s';
+
+        str += (o.raddr != null) ? ' raddr %s rport %d' : '%v%v';
+
+        // NB: candidate has three optional chunks, so %void middles one if it's missing
+        str += (o.tcptype != null) ? ' tcptype %s' : '%v';
+
+        if (o.generation != null) {
+          str += ' generation %d';
+        }
+
+        str += (o['network-id'] != null) ? ' network-id %d' : '%v';
+        str += (o['network-cost'] != null) ? ' network-cost %d' : '%v';
+        return str;
+      }
+    },
+    {
+      // a=end-of-candidates (keep after the candidates line for readability)
+      name: 'endOfCandidates',
+      reg: /^(end-of-candidates)/
+    },
+    {
+      // a=remote-candidates:1 203.0.113.1 54400 2 203.0.113.1 54401 ...
+      name: 'remoteCandidates',
+      reg: /^remote-candidates:(.*)/,
+      format: 'remote-candidates:%s'
+    },
+    {
+      // a=ice-options:google-ice
+      name: 'iceOptions',
+      reg: /^ice-options:(\S*)/,
+      format: 'ice-options:%s'
+    },
+    {
+      // a=ssrc:2566107569 cname:t9YU8M1UxTF8Y1A1
+      push: 'ssrcs',
+      reg: /^ssrc:(\d*) ([\w_-]*)(?::(.*))?/,
+      names: ['id', 'attribute', 'value'],
+      format: function (o) {
+        var str = 'ssrc:%d';
+        if (o.attribute != null) {
+          str += ' %s';
+          if (o.value != null) {
+            str += ':%s';
+          }
+        }
+        return str;
+      }
+    },
+    {
+      // a=ssrc-group:FEC 1 2
+      // a=ssrc-group:FEC-FR 3004364195 1080772241
+      push: 'ssrcGroups',
+      // token-char = %x21 / %x23-27 / %x2A-2B / %x2D-2E / %x30-39 / %x41-5A / %x5E-7E
+      reg: /^ssrc-group:([\x21\x23\x24\x25\x26\x27\x2A\x2B\x2D\x2E\w]*) (.*)/,
+      names: ['semantics', 'ssrcs'],
+      format: 'ssrc-group:%s %s'
+    },
+    {
+      // a=msid-semantic: WMS Jvlam5X3SX1OP6pn20zWogvaKJz5Hjf9OnlV
+      name: 'msidSemantic',
+      reg: /^msid-semantic:\s?(\w*) (\S*)/,
+      names: ['semantic', 'token'],
+      format: 'msid-semantic: %s %s' // space after ':' is not accidental
+    },
+    {
+      // a=group:BUNDLE audio video
+      push: 'groups',
+      reg: /^group:(\w*) (.*)/,
+      names: ['type', 'mids'],
+      format: 'group:%s %s'
+    },
+    {
+      // a=rtcp-mux
+      name: 'rtcpMux',
+      reg: /^(rtcp-mux)/
+    },
+    {
+      // a=rtcp-rsize
+      name: 'rtcpRsize',
+      reg: /^(rtcp-rsize)/
+    },
+    {
+      // a=sctpmap:5000 webrtc-datachannel 1024
+      name: 'sctpmap',
+      reg: /^sctpmap:([\w_/]*) (\S*)(?: (\S*))?/,
+      names: ['sctpmapNumber', 'app', 'maxMessageSize'],
+      format: function (o) {
+        return (o.maxMessageSize != null)
+          ? 'sctpmap:%s %s %s'
+          : 'sctpmap:%s %s';
+      }
+    },
+    {
+      // a=x-google-flag:conference
+      name: 'xGoogleFlag',
+      reg: /^x-google-flag:([^\s]*)/,
+      format: 'x-google-flag:%s'
+    },
+    {
+      // a=rid:1 send max-width=1280;max-height=720;max-fps=30;depend=0
+      push: 'rids',
+      reg: /^rid:([\d\w]+) (\w+)(?: ([\S| ]*))?/,
+      names: ['id', 'direction', 'params'],
+      format: function (o) {
+        return (o.params) ? 'rid:%s %s %s' : 'rid:%s %s';
+      }
+    },
+    {
+      // a=imageattr:97 send [x=800,y=640,sar=1.1,q=0.6] [x=480,y=320] recv [x=330,y=250]
+      // a=imageattr:* send [x=800,y=640] recv *
+      // a=imageattr:100 recv [x=320,y=240]
+      push: 'imageattrs',
+      reg: new RegExp(
+        // a=imageattr:97
+        '^imageattr:(\\d+|\\*)' +
+        // send [x=800,y=640,sar=1.1,q=0.6] [x=480,y=320]
+        '[\\s\\t]+(send|recv)[\\s\\t]+(\\*|\\[\\S+\\](?:[\\s\\t]+\\[\\S+\\])*)' +
+        // recv [x=330,y=250]
+        '(?:[\\s\\t]+(recv|send)[\\s\\t]+(\\*|\\[\\S+\\](?:[\\s\\t]+\\[\\S+\\])*))?'
+      ),
+      names: ['pt', 'dir1', 'attrs1', 'dir2', 'attrs2'],
+      format: function (o) {
+        return 'imageattr:%s %s %s' + (o.dir2 ? ' %s %s' : '');
+      }
+    },
+    {
+      // a=simulcast:send 1,2,3;~4,~5 recv 6;~7,~8
+      // a=simulcast:recv 1;4,5 send 6;7
+      name: 'simulcast',
+      reg: new RegExp(
+        // a=simulcast:
+        '^simulcast:' +
+        // send 1,2,3;~4,~5
+        '(send|recv) ([a-zA-Z0-9\\-_~;,]+)' +
+        // space + recv 6;~7,~8
+        '(?:\\s?(send|recv) ([a-zA-Z0-9\\-_~;,]+))?' +
+        // end
+        '$'
+      ),
+      names: ['dir1', 'list1', 'dir2', 'list2'],
+      format: function (o) {
+        return 'simulcast:%s %s' + (o.dir2 ? ' %s %s' : '');
+      }
+    },
+    {
+      // old simulcast draft 03 (implemented by Firefox)
+      //   https://tools.ietf.org/html/draft-ietf-mmusic-sdp-simulcast-03
+      // a=simulcast: recv pt=97;98 send pt=97
+      // a=simulcast: send rid=5;6;7 paused=6,7
+      name: 'simulcast_03',
+      reg: /^simulcast:[\s\t]+([\S+\s\t]+)$/,
+      names: ['value'],
+      format: 'simulcast: %s'
+    },
+    {
+      // a=framerate:25
+      // a=framerate:29.97
+      name: 'framerate',
+      reg: /^framerate:(\d+(?:$|\.\d+))/,
+      format: 'framerate:%s'
+    },
+    {
+      // RFC4570
+      // a=source-filter: incl IN IP4 239.5.2.31 10.1.15.5
+      name: 'sourceFilter',
+      reg: /^source-filter: *(excl|incl) (\S*) (IP4|IP6|\*) (\S*) (.*)/,
+      names: ['filterMode', 'netType', 'addressTypes', 'destAddress', 'srcList'],
+      format: 'source-filter: %s %s %s %s %s'
+    },
+    {
+      // a=bundle-only
+      name: 'bundleOnly',
+      reg: /^(bundle-only)/
+    },
+    {
+      // a=label:1
+      name: 'label',
+      reg: /^label:(.+)/,
+      format: 'label:%s'
+    },
+    {
+      // RFC version 26 for SCTP over DTLS
+      // https://tools.ietf.org/html/draft-ietf-mmusic-sctp-sdp-26#section-5
+      name: 'sctpPort',
+      reg: /^sctp-port:(\d+)$/,
+      format: 'sctp-port:%s'
+    },
+    {
+      // RFC version 26 for SCTP over DTLS
+      // https://tools.ietf.org/html/draft-ietf-mmusic-sctp-sdp-26#section-6
+      name: 'maxMessageSize',
+      reg: /^max-message-size:(\d+)$/,
+      format: 'max-message-size:%s'
+    },
+    {
+      // RFC7273
+      // a=ts-refclk:ptp=IEEE1588-2008:39-A7-94-FF-FE-07-CB-D0:37
+      push:'tsRefClocks',
+      reg: /^ts-refclk:([^\s=]*)(?:=(\S*))?/,
+      names: ['clksrc', 'clksrcExt'],
+      format: function (o) {
+        return 'ts-refclk:%s' + (o.clksrcExt != null ? '=%s' : '');
+      }
+    },
+    {
+      // RFC7273
+      // a=mediaclk:direct=963214424
+      name:'mediaClk',
+      reg: /^mediaclk:(?:id=(\S*))? *([^\s=]*)(?:=(\S*))?(?: *rate=(\d+)\/(\d+))?/,
+      names: ['id', 'mediaClockName', 'mediaClockValue', 'rateNumerator', 'rateDenominator'],
+      format: function (o) {
+        var str = 'mediaclk:';
+        str += (o.id != null ? 'id=%s %s' : '%v%s');
+        str += (o.mediaClockValue != null ? '=%s' : '');
+        str += (o.rateNumerator != null ? ' rate=%s' : '');
+        str += (o.rateDenominator != null ? '/%s' : '');
+        return str;
+      }
+    },
+    {
+      // a=keywds:keywords
+      name: 'keywords',
+      reg: /^keywds:(.+)$/,
+      format: 'keywds:%s'
+    },
+    {
+      // a=content:main
+      name: 'content',
+      reg: /^content:(.+)/,
+      format: 'content:%s'
+    },
+    // BFCP https://tools.ietf.org/html/rfc4583
+    {
+      // a=floorctrl:c-s
+      name: 'bfcpFloorCtrl',
+      reg: /^floorctrl:(c-only|s-only|c-s)/,
+      format: 'floorctrl:%s'
+    },
+    {
+      // a=confid:1
+      name: 'bfcpConfId',
+      reg: /^confid:(\d+)/,
+      format: 'confid:%s'
+    },
+    {
+      // a=userid:1
+      name: 'bfcpUserId',
+      reg: /^userid:(\d+)/,
+      format: 'userid:%s'
+    },
+    {
+      // a=floorid:1
+      name: 'bfcpFloorId',
+      reg: /^floorid:(.+) (?:m-stream|mstrm):(.+)/,
+      names: ['id', 'mStream'],
+      format: 'floorid:%s mstrm:%s'
+    },
+    {
+      // any a= that we don't understand is kept verbatim on media.invalid
+      push: 'invalid',
+      names: ['value']
+    }
+  ]
+};
+
+// set sensible defaults to avoid polluting the grammar with boring details
+Object.keys(grammar).forEach(function (key) {
+  var objs = grammar[key];
+  objs.forEach(function (obj) {
+    if (!obj.reg) {
+      obj.reg = /(.*)/;
+    }
+    if (!obj.format) {
+      obj.format = '%s';
+    }
+  });
+});
+
+},{}],37:[function(require,module,exports){
+var parser = require('./parser');
+var writer = require('./writer');
+
+exports.write = writer;
+exports.parse = parser.parse;
+exports.parseParams = parser.parseParams;
+exports.parseFmtpConfig = parser.parseFmtpConfig; // Alias of parseParams().
+exports.parsePayloads = parser.parsePayloads;
+exports.parseRemoteCandidates = parser.parseRemoteCandidates;
+exports.parseImageAttributes = parser.parseImageAttributes;
+exports.parseSimulcastStreamList = parser.parseSimulcastStreamList;
+
+},{"./parser":38,"./writer":39}],38:[function(require,module,exports){
+var toIntIfInt = function (v) {
+  return String(Number(v)) === v ? Number(v) : v;
+};
+
+var attachProperties = function (match, location, names, rawName) {
+  if (rawName && !names) {
+    location[rawName] = toIntIfInt(match[1]);
+  }
+  else {
+    for (var i = 0; i < names.length; i += 1) {
+      if (match[i+1] != null) {
+        location[names[i]] = toIntIfInt(match[i+1]);
+      }
+    }
+  }
+};
+
+var parseReg = function (obj, location, content) {
+  var needsBlank = obj.name && obj.names;
+  if (obj.push && !location[obj.push]) {
+    location[obj.push] = [];
+  }
+  else if (needsBlank && !location[obj.name]) {
+    location[obj.name] = {};
+  }
+  var keyLocation = obj.push ?
+    {} :  // blank object that will be pushed
+    needsBlank ? location[obj.name] : location; // otherwise, named location or root
+
+  attachProperties(content.match(obj.reg), keyLocation, obj.names, obj.name);
+
+  if (obj.push) {
+    location[obj.push].push(keyLocation);
+  }
+};
+
+var grammar = require('./grammar');
+var validLine = RegExp.prototype.test.bind(/^([a-z])=(.*)/);
+
+exports.parse = function (sdp) {
+  var session = {}
+    , media = []
+    , location = session; // points at where properties go under (one of the above)
+
+  // parse lines we understand
+  sdp.split(/(\r\n|\r|\n)/).filter(validLine).forEach(function (l) {
+    var type = l[0];
+    var content = l.slice(2);
+    if (type === 'm') {
+      media.push({rtp: [], fmtp: []});
+      location = media[media.length-1]; // point at latest media line
+    }
+
+    for (var j = 0; j < (grammar[type] || []).length; j += 1) {
+      var obj = grammar[type][j];
+      if (obj.reg.test(content)) {
+        return parseReg(obj, location, content);
+      }
+    }
+  });
+
+  session.media = media; // link it up
+  return session;
+};
+
+var paramReducer = function (acc, expr) {
+  var s = expr.split(/=(.+)/, 2);
+  if (s.length === 2) {
+    acc[s[0]] = toIntIfInt(s[1]);
+  } else if (s.length === 1 && expr.length > 1) {
+    acc[s[0]] = undefined;
+  }
+  return acc;
+};
+
+exports.parseParams = function (str) {
+  return str.split(/;\s?/).reduce(paramReducer, {});
+};
+
+// For backward compatibility - alias will be removed in 3.0.0
+exports.parseFmtpConfig = exports.parseParams;
+
+exports.parsePayloads = function (str) {
+  return str.toString().split(' ').map(Number);
+};
+
+exports.parseRemoteCandidates = function (str) {
+  var candidates = [];
+  var parts = str.split(' ').map(toIntIfInt);
+  for (var i = 0; i < parts.length; i += 3) {
+    candidates.push({
+      component: parts[i],
+      ip: parts[i + 1],
+      port: parts[i + 2]
+    });
+  }
+  return candidates;
+};
+
+exports.parseImageAttributes = function (str) {
+  return str.split(' ').map(function (item) {
+    return item.substring(1, item.length-1).split(',').reduce(paramReducer, {});
+  });
+};
+
+exports.parseSimulcastStreamList = function (str) {
+  return str.split(';').map(function (stream) {
+    return stream.split(',').map(function (format) {
+      var scid, paused = false;
+
+      if (format[0] !== '~') {
+        scid = toIntIfInt(format);
+      } else {
+        scid = toIntIfInt(format.substring(1, format.length));
+        paused = true;
+      }
+
+      return {
+        scid: scid,
+        paused: paused
+      };
+    });
+  });
+};
+
+},{"./grammar":36}],39:[function(require,module,exports){
+var grammar = require('./grammar');
+
+// customized util.format - discards excess arguments and can void middle ones
+var formatRegExp = /%[sdv%]/g;
+var format = function (formatStr) {
+  var i = 1;
+  var args = arguments;
+  var len = args.length;
+  return formatStr.replace(formatRegExp, function (x) {
+    if (i >= len) {
+      return x; // missing argument
+    }
+    var arg = args[i];
+    i += 1;
+    switch (x) {
+    case '%%':
+      return '%';
+    case '%s':
+      return String(arg);
+    case '%d':
+      return Number(arg);
+    case '%v':
+      return '';
+    }
+  });
+  // NB: we discard excess arguments - they are typically undefined from makeLine
+};
+
+var makeLine = function (type, obj, location) {
+  var str = obj.format instanceof Function ?
+    (obj.format(obj.push ? location : location[obj.name])) :
+    obj.format;
+
+  var args = [type + '=' + str];
+  if (obj.names) {
+    for (var i = 0; i < obj.names.length; i += 1) {
+      var n = obj.names[i];
+      if (obj.name) {
+        args.push(location[obj.name][n]);
+      }
+      else { // for mLine and push attributes
+        args.push(location[obj.names[i]]);
+      }
+    }
+  }
+  else {
+    args.push(location[obj.name]);
+  }
+  return format.apply(null, args);
+};
+
+// RFC specified order
+// TODO: extend this with all the rest
+var defaultOuterOrder = [
+  'v', 'o', 's', 'i',
+  'u', 'e', 'p', 'c',
+  'b', 't', 'r', 'z', 'a'
+];
+var defaultInnerOrder = ['i', 'c', 'b', 'a'];
+
+
+module.exports = function (session, opts) {
+  opts = opts || {};
+  // ensure certain properties exist
+  if (session.version == null) {
+    session.version = 0; // 'v=0' must be there (only defined version atm)
+  }
+  if (session.name == null) {
+    session.name = ' '; // 's= ' must be there if no meaningful name set
+  }
+  session.media.forEach(function (mLine) {
+    if (mLine.payloads == null) {
+      mLine.payloads = '';
+    }
+  });
+
+  var outerOrder = opts.outerOrder || defaultOuterOrder;
+  var innerOrder = opts.innerOrder || defaultInnerOrder;
+  var sdp = [];
+
+  // loop through outerOrder for matching properties on session
+  outerOrder.forEach(function (type) {
+    grammar[type].forEach(function (obj) {
+      if (obj.name in session && session[obj.name] != null) {
+        sdp.push(makeLine(type, obj, session));
+      }
+      else if (obj.push in session && session[obj.push] != null) {
+        session[obj.push].forEach(function (el) {
+          sdp.push(makeLine(type, obj, el));
+        });
+      }
+    });
+  });
+
+  // then for each media line, follow the innerOrder
+  session.media.forEach(function (mLine) {
+    sdp.push(makeLine('m', grammar.m[0], mLine));
+
+    innerOrder.forEach(function (type) {
+      grammar[type].forEach(function (obj) {
+        if (obj.name in mLine && mLine[obj.name] != null) {
+          sdp.push(makeLine(type, obj, mLine));
+        }
+        else if (obj.push in mLine && mLine[obj.push] != null) {
+          mLine[obj.push].forEach(function (el) {
+            sdp.push(makeLine(type, obj, el));
+          });
+        }
+      });
+    });
+  });
+
+  return sdp.join('\r\n') + '\r\n';
+};
+
+},{"./grammar":36}],40:[function(require,module,exports){
+module.exports={
+  "name": "jssip",
+  "title": "JsSIP",
+  "description": "the Javascript SIP library",
+  "version": "3.10.0",
+  "homepage": "https://jssip.net",
+  "contributors": [
+    "Jos茅 Luis Mill谩n <jmillan@aliax.net> (https://github.com/jmillan)",
+    "I帽aki Baz Castillo <ibc@aliax.net> (https://inakibaz.me)"
+  ],
+  "types": "lib/JsSIP.d.ts",
+  "main": "lib-es5/JsSIP.js",
+  "keywords": [
+    "sip",
+    "websocket",
+    "webrtc",
+    "node",
+    "browser",
+    "library"
+  ],
+  "license": "MIT",
+  "repository": {
+    "type": "git",
+    "url": "https://github.com/versatica/JsSIP.git"
+  },
+  "bugs": {
+    "url": "https://github.com/versatica/JsSIP/issues"
+  },
+  "dependencies": {
+    "@types/events": "^3.0.0",
+    "@types/debug": "^4.1.7",
+    "debug": "^4.3.1",
+    "events": "^3.3.0",
+    "sdp-transform": "^2.14.1"
+  },
+  "devDependencies": {
+    "@babel/core": "^7.19.6",
+    "@babel/preset-env": "^7.19.4",
+    "ansi-colors": "^3.2.4",
+    "browserify": "^16.5.1",
+    "eslint": "^5.16.0",
+    "fancy-log": "^1.3.3",
+    "gulp": "^4.0.2",
+    "gulp-babel": "^8.0.0",
+    "gulp-eslint": "^5.0.0",
+    "gulp-expect-file": "^1.0.2",
+    "gulp-header": "^2.0.9",
+    "gulp-nodeunit-runner": "^0.2.2",
+    "gulp-plumber": "^1.2.1",
+    "gulp-rename": "^1.4.0",
+    "gulp-uglify-es": "^1.0.4",
+    "pegjs": "^0.7.0",
+    "vinyl-buffer": "^1.0.1",
+    "vinyl-source-stream": "^2.0.0"
+  },
+  "scripts": {
+    "lint": "node npm-scripts.js lint",
+    "test": "node npm-scripts.js test",
+    "prepublish": "node npm-scripts.js prepublish",
+    "release": "node npm-scripts.js release"
+  }
+}
+
+},{}]},{},[8])(8)
+});
diff --git a/sltd.zip b/sltd.zip
new file mode 100644
index 0000000..37ef9e2
--- /dev/null
+++ b/sltd.zip
Binary files differ
diff --git a/src/App.vue b/src/App.vue
index 30d9a8f..83f295c 100644
--- a/src/App.vue
+++ b/src/App.vue
@@ -3,6 +3,13 @@
     <router-view />
     <theme-picker />
     <!-- <Assistant v-if="routertf" /> -->
+    <Assistant
+      v-if="Assvite"
+      :initial-position="{ x: 50, y: 200 }"
+      :auto-hide="false"
+      :hide-delay="3000"
+      primary-color="#1890ff"
+    />
   </div>
 </template>
 
@@ -13,17 +20,29 @@
   name: "App",
   components: {
     ThemePicker,
-    Assistant: () => import("./components/Assistant"), //寮傛缁勪欢鍔犺浇鏂瑰紡
+    Assistant: () => import("./components/Assistant"),
   },
   data() {
     return {
-      routers: window.location.href,
-      routertf: true,
+      Assvite: true,
     };
   },
   created() {
-    var startIndex = this.routers.indexOf("param5=") + "param5=".length; // 鎵惧埌绗竴涓瓧绗︾殑浣嶇疆
-    this.routertf = JSON.parse(this.routers.substring(startIndex)); // 鎴彇浠� 'param5=' 涔嬪悗鐨勫唴瀹�
+    // 鍒濆鍖栧垽鏂�
+    this.checkAndUpdateAssvite();
+  },
+  watch: {
+    // 鐩戝惉璺敱鍙樺寲
+    '$route'(to, from) {
+      this.checkAndUpdateAssvite();
+    }
+  },
+  methods: {
+    checkAndUpdateAssvite() {
+      const isLoginPage = window.location.pathname.includes("/login");
+      this.Assvite = !isLoginPage;
+      console.log('褰撳墠璺敱:', this.$route.path, '鏄惁鐧诲綍椤�:', isLoginPage, '鏄剧ず鎮诞鐞�:', this.Assvite);
+    }
   },
   metaInfo() {
     return {
diff --git a/src/api/AiCentre/EChartsdata.js b/src/api/AiCentre/EChartsdata.js
index d6ebdb0..6a193bd 100644
--- a/src/api/AiCentre/EChartsdata.js
+++ b/src/api/AiCentre/EChartsdata.js
@@ -1,6 +1,5 @@
 import request from "@/utils/request";
 
-
 // 鏌ヨ闂ㄨ瘖鐪嬬梾浜烘鍜屼汉鏁�
 export function getEChartsPatMedOuthospCount(data) {
   return request({
@@ -65,6 +64,7 @@
   return request({
     url: "/smartor/organization/list",
     method: "get",
+    params: data,
   });
 }
 // 鍙戦�佺煭淇�
@@ -72,6 +72,14 @@
   return request({
     url: "/sms/send",
     method: "post",
-    data: data
+    data: data,
+  });
+}
+// 鍙戦�佺煭淇�
+export function getCurrentUserServiceSubtaskCount(data) {
+  return request({
+    url: "/smartor/serviceSubtask/getCurrentUserServiceSubtaskCount",
+    method: "post",
+    data: data,
   });
 }
diff --git a/src/api/AiCentre/Followup.js b/src/api/AiCentre/Followup.js
index b20b35a..991dd04 100644
--- a/src/api/AiCentre/Followup.js
+++ b/src/api/AiCentre/Followup.js
@@ -45,7 +45,13 @@
     // data: data,
   });
 }
-
+export function getTaskFollowupList(data) {
+  return request({
+    url: "/smartor/ivrTaskTemplate/list",
+    method: "post",
+    data: data,
+  });
+}
 // 鏂板闅忚妯℃澘鍒嗙被鏍�
 export function addFollowupclassify(data) {
   return request({
diff --git a/src/api/AiCentre/Qtemplate.js b/src/api/AiCentre/Qtemplate.js
index 5853929..c619033 100644
--- a/src/api/AiCentre/Qtemplate.js
+++ b/src/api/AiCentre/Qtemplate.js
@@ -9,6 +9,14 @@
     data: data,
   });
 }
+// 鏌ヨ闂嵎妯℃澘鍒楄〃
+export function taskgetQtemplateobj(data) {
+  return request({
+    url: "smartor/svytemplateTask/selectInfoByCondition",
+    method: "post",
+    data: data,
+  });
+}
 // 闂嵎妯℃澘鍒楄〃
 export function getQtemplatelist(data) {
   return request({
@@ -224,3 +232,11 @@
     data: data,
   });
 }
+// 鍖绘姢淇濆瓨鏁版嵁
+export function savequestiondetail(data) {
+  return request({
+    url: "/smartor/subtaskAnswer/savequestiondetail",
+    method: "post",
+    data: data,
+  });
+}
diff --git a/src/api/AiCentre/SingleTask.js b/src/api/AiCentre/SingleTask.js
index c94501b..379812f 100644
--- a/src/api/AiCentre/SingleTask.js
+++ b/src/api/AiCentre/SingleTask.js
@@ -104,6 +104,14 @@
     data: data,
   });
 }
+// 璇婃柇鏌ヨ鍘嗗彶鏈嶅姟鍒楄〃
+export function historservelist(data) {
+  return request({
+    url: "/smartor/serviceSubtask/getSubtaskByDiagname",
+    method: "post",
+    data: data,
+  });
+}
 // 蹇嵎鏌ヨ浠诲姟鍒楄〃
 export function buidegetTasklist(data) {
   return request({
@@ -128,6 +136,14 @@
     method: "get",
   });
 }
+// 鑾峰彇璇煶浠诲姟妯℃澘璇︽儏
+export function selectInfoByCondition(data) {
+  return request({
+     url: "/smartor/ivrTaskTemplate/selectInfoByCondition",
+    method: "post",
+    data: data,
+  });
+}
 // 浠诲姟妯℃澘鏂板淇敼
 export function TaskTemplatecomit(data) {
   return request({
diff --git a/src/api/AiCentre/phoneCall.js b/src/api/AiCentre/phoneCall.js
index f2f5124..a542402 100644
--- a/src/api/AiCentre/phoneCall.js
+++ b/src/api/AiCentre/phoneCall.js
@@ -10,7 +10,7 @@
     },
   });
 }
-// 鏌ヨ澶栭儴鎮h�呰〃
+// 鏇存柊鍒嗙骇鍙�
 export function CallsetState(data) {
   return request({
     url: "/smartor/ServiceTelInfo/setState",
diff --git a/src/api/AiCentre/questionnaire.js b/src/api/AiCentre/questionnaire.js
index 63efa1b..7776e75 100644
--- a/src/api/AiCentre/questionnaire.js
+++ b/src/api/AiCentre/questionnaire.js
@@ -30,7 +30,14 @@
       data: data,
     });
   }
-
+// 鏌ヨ闂缁熻
+export function compileissuestatistics(data) {
+    return request({
+      url: "/smartor/svytemplatescript/countPatByScript",
+      method: "post",
+      data: data,
+    });
+  }
 
   // 鏂板闂嵎闂鍒嗙被
   export function addissueclassify(data) {
diff --git a/src/api/login.js b/src/api/login.js
index 9c838af..77dc52e 100644
--- a/src/api/login.js
+++ b/src/api/login.js
@@ -1,12 +1,13 @@
 import request from "@/utils/request";
 
 // 鐧诲綍鏂规硶
-export function login(username, password, code, orgid) {
+export function login(username, password, code, orgid,campusid) {
   const data = {
     username,
     password,
     code,
     orgid,
+    campusid,
   };
   return request({
     url: "/login",
diff --git a/src/api/smartor/patouthosp.js b/src/api/smartor/patouthosp.js
index ebe3d70..353c440 100644
--- a/src/api/smartor/patouthosp.js
+++ b/src/api/smartor/patouthosp.js
@@ -8,6 +8,14 @@
     data: query
   })
 }
+// 鏌ヨ寰呭叆闄㈣褰曞垪琛�
+export function listPatMedInhosp(query) {
+  return request({
+    url: '/smartor/patinhosp/selectPatMedInhospList',
+    method: 'post',
+    data: query
+  })
+}
 
 // 鏌ヨ鎮h�呴棬璇婅褰曡缁�
 export function getPatouthosp(id) {
diff --git a/src/api/system/user.js b/src/api/system/user.js
index 79ab356..53e4168 100644
--- a/src/api/system/user.js
+++ b/src/api/system/user.js
@@ -94,17 +94,18 @@
     data: data,
   });
 }
-// 婊℃剰搴︽槑缁嗘煡璇�
-export function getSfStatisticsJoydetails(data) {
+// 婊℃剰搴︾粺璁�
+export function getSfStatisticsJoy(data) {
   return request({
-    url: "/smartor/serviceSubtask/getSfStatisticsJoydetails",
+    url: "/smartor/serviceSubtask/getSfStatisticsCount",
     method: "post",
     data: data,
   });
-}// 婊℃剰搴︾粺璁�
-export function getSfStatisticsJoy(data) {
+}
+// 婊℃剰搴︾粺璁¤鎯�
+export function getSfStatisticsJoyInfo(data) {
   return request({
-    url: "/smartor/serviceSubtask/getSfStatisticsJoy",
+    url: "/smartor/serviceSubtask/getSfStatisticsCountDetails",
     method: "post",
     data: data,
   });
@@ -119,7 +120,7 @@
 }
 
 // 浠诲姟闅忚鐜囩粺璁¤〃鐨勪笅閽绘槑缁�
-// sendstate = 2 寰呴殢璁� 5 寰呴殢璁垮け璐�    
+// sendstate = 2 寰呴殢璁� 5 寰呴殢璁垮け璐�
 // preachform = 浠诲姟褰㈠紡(1,浜哄伐 2,绾歌川  3,鐢佃瘽  4,鐭俊  5.寰俊鍏紬鍙� 6.寰俊灏忕▼搴� 7.鏀粯瀹濆皬绋嬪簭  8.鏅鸿兘鏈哄櫒浜�  9.閽夐拤)
 export function querySubtaskList(data) {
   return request({
@@ -195,3 +196,19 @@
     data: data,
   });
 }
+// 鐪佺珛鍚屽痉婊℃剰搴︾粺璁¢〉棰樼洰鏄庣粏
+export function statistics(data) {
+  return request({
+    url: "/smartor/satisfaction/statistics",
+    method: "post",
+    data: data,
+  });
+}
+// 鐪佺珛鍚屽痉婊℃剰搴︾粺璁¢〉棰樼洰鏄庣粏
+export function satisfactionGraph(data) {
+  return request({
+    url: "/smartor/satisfaction/satisfactionGraph",
+    method: "post",
+    data: data,
+  });
+}
diff --git a/src/components/AskRegular/index.vue b/src/components/AskRegular/index.vue
index 8e135a3..7073c23 100644
--- a/src/components/AskRegular/index.vue
+++ b/src/components/AskRegular/index.vue
@@ -14,10 +14,18 @@
         ></el-col>
         <el-col :span="12"
           ><el-form-item label="寮傚父鎻愰啋">
-            <el-radio-group v-model="radio">
-              <el-radio :label="3">鏄�</el-radio>
-              <el-radio :label="6">鍚�</el-radio>
-            </el-radio-group>
+            <el-select v-model="item.isabnormal" placeholder="璇烽�夋嫨鐘舵��">
+              <el-option :value="0" label="姝e父" :style="{ color: '#67C23A' }">
+                <span style="color: #67c23a">鈼� 姝e父</span>
+              </el-option>
+
+              <el-option :value="2" label="璀﹀憡" :style="{ color: '#FFBA00' }">
+                <span style="color: #ffba00">鈼� 璀﹀憡</span>
+              </el-option>
+              <el-option :value="1" label="寮傚父" :style="{ color: '#f75c5c' }">
+                <span style="color: #f75c5c">鈼� 寮傚父</span>
+              </el-option>
+            </el-select>
           </el-form-item></el-col
         >
         <el-col :span="12" v-if="intent"
diff --git a/src/components/Assistant/index.vue b/src/components/Assistant/index.vue
index 356ef75..2ee2946 100644
--- a/src/components/Assistant/index.vue
+++ b/src/components/Assistant/index.vue
@@ -1,479 +1,809 @@
 <template>
   <div
-    ref="floatDrag"
-    class="float-position"
-    id="float-box"
-    :style="{
-      left: left + 'px',
-      top: top + 'px',
-      right: right + 'px !important',
-      zIndex: zIndex,
+    ref="floatBall"
+    class="float-ball"
+    :class="{
+      'float-ball-hidden': isHidden && !isHovering,
+      'float-ball-expanded': isExpanded,
     }"
-    @touchmove.prevent
-    @mousemove.prevent
-    @mousedown="mouseDown"
-    @mouseup="mouseUp"
+    :style="{
+      left: position.x + 'px',
+      top: position.y + 'px',
+      '--primary-color': primaryColor,
+      '--hover-color': hoverColor,
+    }"
+    @mouseenter="handleMouseEnter"
+    @mouseleave="handleMouseLeave"
   >
-    <div class="drag">
-      <svg
-        t="1682058484158"
-        class="icon"
-        viewBox="0 0 1024 1024"
-        version="1.1"
-        xmlns="http://www.w3.org/2000/svg"
-        p-id="2023"
-        width="32"
-        height="32"
-      >
-        <path
-          d="M556.297 172.715a42.407 42.407 0 0 1 42.426 42.398l0.837 267.69c-0.118 1.703 0.63 2.737 1.408 2.737 0.63 0 1.29-0.699 1.506-2.284l37.74-208.953c3.732-20.672 21.844-36.166 42.162-36.166a40.074 40.074 0 0 1 7.136 0.64c23.064 4.164 38.391 27.562 34.217 50.587l-33.656 244.529c0 2.559 0.483 4.478 1.32 4.478 0.58 0 1.328-0.935 2.175-3.218l50.144-134.063c6.27-17.65 23.034-29.403 40.793-29.403A39.798 39.798 0 0 1 797.892 374c22.08 7.875 33.626 33.41 25.78 55.47l-87.904 287.191c-0.453 1.585-0.984 3.16-1.437 4.725l-0.187 0.591v0.128a187.031 187.031 0 0 1-177.847 129.1c-53.156 0-108.42-18.752-150.472-51-45.419-27.336-190.968-183.783-190.968-183.783-22.09-22.07-18.792-55.882 3.297-77.962 11.537-11.537 25.919-17.6 40.173-17.6 13.033 0 25.967 5.05 36.51 15.592l63.138 63.157c8.603 8.594 18.132 12.699 26.922 12.699a26.952 26.952 0 0 0 20.88-9.893c7.658-9.037 4.635-36.914 2.49-54.594l-31.668-260.259c-2.825-23.26 13.781-45.724 37.003-48.549a40.497 40.497 0 0 1 4.853-0.295c21.282 0 39.749 16.98 42.387 38.597l34.926 204.425c0.905 2.54 2.342 4.036 3.602 4.036s2.353-1.496 2.58-4.922l11.88-265.741a42.417 42.417 0 0 1 42.467-42.398m0-70.875a113.36 113.36 0 0 0-104.344 69.153c-0.246 0.57-0.482 1.152-0.718 1.732a111.234 111.234 0 0 0-90.022 10.976 113.597 113.597 0 0 0-32.415 29.207 115.23 115.23 0 0 0-19.067 38.489 113.843 113.843 0 0 0-3.465 44.68l21.36 175.77a120.842 120.842 0 0 0-69.3-21.863c-33.468 0-65.549 13.614-90.286 38.332-23.212 23.202-36.993 53.363-38.863 84.952a120.92 120.92 0 0 0 34.502 92.216c5.532 5.906 39.64 42.407 79.203 82.412 74.586 75.422 105.328 99.648 122.702 110.771 53.973 40.36 123.254 63.414 190.674 63.414A257.906 257.906 0 0 0 801.14 745.1c0.247-0.709 0.483-1.417 0.7-2.136l0.117-0.374a178.56 178.56 0 0 0 1.723-5.64l87.413-285.578a113.203 113.203 0 0 0 5.729-42.86 115.585 115.585 0 0 0-35.772-77.135 111.431 111.431 0 0 0-67.45-30.19l0.148-0.985a113.676 113.676 0 0 0-1.201-43.155 115.408 115.408 0 0 0-16.872-39.523 113.774 113.774 0 0 0-30.703-30.968 111.077 111.077 0 0 0-84.981-17.06 113.203 113.203 0 0 0-103.694-67.656z"
-          fill="#ffffff"
-          p-id="2024"
-        ></path>
-      </svg>
-    </div>
-    <div class="content" id="content" @click="handelFlex">
-      <!-- <img src="../../../../assets/image/alarm.png" alt="" /> -->
-      <div class="label">
-        <div v-if="flag">灞曞紑</div>
-        <div v-else>鏀惰捣</div>
-      </div>
-      <div class="item-container">
-        <div
-          v-for="(item, index) in powerList"
-          :key="index"
-          @click.stop="activeHandle(index,item.url)"
+    <!-- 涓荤悆浣� -->
+    <div
+      class="ball-main"
+      :class="{ 'ball-main-expanded': isExpanded }"
+      @click="toggleExpand"
+      @mousedown="startDrag"
+      @touchstart="startDrag"
+    >
+      <!-- 鎶樺彔鐘舵�佸浘鏍� -->
+      <div v-if="!isExpanded" class="ball-icon">
+        <svg
+          class="fold-icon"
+          viewBox="0 0 24 24"
+          fill="none"
+          stroke="currentColor"
+          stroke-width="2"
         >
+          <path d="M4 6h16M4 12h16M4 18h16" />
+        </svg>
+      </div>
+
+      <!-- 灞曞紑鐘舵�佸叧闂寜閽� -->
+      <div v-else class="close-btn" @click.stop="toggleExpand">
+        <svg
+          class="close-icon"
+          viewBox="0 0 24 24"
+          fill="none"
+          stroke="currentColor"
+          stroke-width="2"
+        >
+          <path d="M6 18L18 6M6 6l12 12" />
+        </svg>
+      </div>
+
+      <!-- 瑙掓爣鎻愮ず锛堟湁鏈鏁版椂鏄剧ず锛� -->
+      <div v-if="totalUnread > 0" class="ball-badge">
+        {{ totalUnread > 99 ? "99+" : totalUnread }}
+      </div>
+    </div>
+
+    <!-- 灞曞紑鐨勫唴瀹归潰鏉� -->
+    <transition name="ball-expand">
+      <div v-if="isExpanded" class="ball-content">
+        <div class="content-header">
+          <h3>闅忚宸ヤ綔鍙�</h3>
+          <div class="update-time">鏇存柊浜� {{ updateTime }}</div>
+        </div>
+
+        <div class="stats-grid">
           <div
-            :class="activeIndex == index ? 'active power-item' : 'power-item'"
+            v-for="(item, index) in statsItems"
+            :key="index"
+            class="stat-item"
+            :class="{ 'stat-item-highlight': item.highlight }"
+            @click="handleItemClick(item)"
           >
-            <img :src="item.path" alt="" style="width: 26px" />
+            <div class="stat-icon">
+              <svg
+                v-if="item.icon === 'IconUsers'"
+                viewBox="0 0 24 24"
+                fill="none"
+                stroke="currentColor"
+                stroke-width="2"
+              >
+                <path
+                  d="M12 4.354a4 4 0 110 5.292M15 21H3v-1a6 6 0 0112 0v1zm0 0h6v-1a6 6 0 00-9-5.197m13-7.157a4 4 0 11-8 0 4 4 0 018 0z"
+                />
+              </svg>
+              <svg
+                v-else-if="item.icon === 'IconAlertCircle'"
+                viewBox="0 0 24 24"
+                fill="none"
+                stroke="currentColor"
+                stroke-width="2"
+              >
+                <path d="M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
+              </svg>
+              <svg
+                v-else-if="item.icon === 'IconTask'"
+                viewBox="0 0 24 24"
+                fill="none"
+                stroke="currentColor"
+                stroke-width="2"
+              >
+                <path
+                  d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"
+                />
+              </svg>
+            </div>
+            <div class="stat-info">
+              <div class="stat-label">{{ item.label }}</div>
+              <div class="stat-value">{{ item.value }}</div>
+              <div
+                v-if="item.trend"
+                class="stat-trend"
+                :class="'trend-' + item.trend.type"
+              >
+                <span class="trend-arrow">{{ item.trend.arrow }}</span>
+                <span class="trend-value">{{ item.trend.value }}</span>
+              </div>
+            </div>
+            <div v-if="item.unread > 0" class="stat-badge">
+              {{ item.unread > 99 ? "99+" : item.unread }}
+            </div>
           </div>
-          <div :class="activeIndex == index ? 'active-des des' : 'des'">
-            {{ item.label }}
+        </div>
+
+        <div class="quick-actions">
+          <div
+            v-for="(action, index) in quickActions"
+            :key="index"
+            class="action-item"
+            @click="handleActionClick(action)"
+          >
+            <div class="action-icon">
+              <svg
+                v-if="action.icon === 'IconMessageCircle'"
+                viewBox="0 0 24 24"
+                fill="none"
+                stroke="currentColor"
+                stroke-width="2"
+              >
+                <path
+                  d="M8 12h.01M12 12h.01M16 12h.01M21 12c0 4.418-4.03 8-9 8a9.863 9.863 0 01-4.255-.949L3 20l1.395-3.72C3.512 15.042 3 13.574 3 12c0-4.418 4.03-8 9-8s9 3.582 9 8z"
+                />
+              </svg>
+              <svg
+                v-else-if="action.icon === 'IconPhone'"
+                viewBox="0 0 24 24"
+                fill="none"
+                stroke="currentColor"
+                stroke-width="2"
+              >
+                <path
+                  d="M3 5a2 2 0 012-2h3.28a1 1 0 01.948.684l1.498 4.493a1 1 0 01-.502 1.21l-2.257 1.13a11.042 11.042 0 005.516 5.516l1.13-2.257a1 1 0 011.21-.502l4.493 1.498a1 1 0 01.684.949V19a2 2 0 01-2 2h-1C9.716 21 3 14.284 3 6V5z"
+                />
+              </svg>
+            </div>
+            <div class="action-label">{{ action.label }}</div>
           </div>
         </div>
       </div>
-    </div>
+    </transition>
   </div>
 </template>
 
 <script>
+import { getCurrentUserServiceSubtaskCount } from "@/api/AiCentre/index";
 export default {
-  name: "DragBall",
+  name: "FloatBall",
+
   props: {
-    distanceRight: {
-      type: Number,
-      default: 36,
+    // 鍒濆浣嶇疆
+    initialPosition: {
+      type: Object,
+      default: () => ({ x: 20, y: 100 }),
     },
-    distanceBottom: {
-      type: Number,
-      default: 600,
-    },
-    isScrollHidden: {
-      type: Boolean,
-      default: false,
-    },
-    isCanDraggable: {
+    // 鏄惁鑷姩闅愯棌
+    autoHide: {
       type: Boolean,
       default: true,
     },
-    zIndex: {
+    // 闅愯棌寤惰繜锛堟绉掞級
+    hideDelay: {
       type: Number,
-      default: 50,
+      default: 2000,
     },
-    value: {
+    // 涓婚棰滆壊
+    primaryColor: {
       type: String,
-      default: "鎮诞鐞冿紒",
+      default: "#4f46e5",
+    },
+    // 鎮仠棰滆壊
+    hoverColor: {
+      type: String,
+      default: "#4338ca",
+    },
+    // 鏁版嵁婧愶紙鍙粠澶栭儴浼犲叆锛�
+    statsData: {
+      type: Object,
+      default: null,
     },
   },
+
   data() {
     return {
-      clientWidth: null,
-      clientHeight: null,
-      left: null,
-      top: null,
-      right: null,
-      timer: null,
-      currentTop: 0,
-      mousedownX: 0,
-      mousedownY: 0,
+      isExpanded: false,
+      isHovering: false,
+      isHidden: false,
+      isDragging: false,
+      position: { ...this.initialPosition },
+      dragStart: { x: 0, y: 0 },
+      hideTimer: null,
+      updateTime: "",
+      roles: null,
+      // 缁熻鏁版嵁
+      statsItems: [
+        {
+          id: "pending",
+          label: "寰呴殢璁�",
+          value: "0",
+          unread: 0,
+          urltype: 2,
+          icon: "IconUsers",
+          url: "/followvisit/discharge",
+          trend: { type: "up", arrow: "", value: "" },
+          highlight: true,
+        },
+        {
+          id: "failed",
+          label: "闅忚澶辫触",
+          value: "0",
+          unread: 0,
+          urltype: 3,
+          icon: "IconAlertCircle",
+          url: "/followvisit/discharge",
+          trend: { type: "down", arrow: "", value: "" },
+        },
+        {
+          id: "abnormal",
+          label: "浠诲姟寮傚父",
+          value: "0",
+          unread: 0,
+          urltype: 4,
+          icon: "IconAlertCircle",
+          url: "/followvisit/discharge",
+          trend: { type: "up", arrow: "", value: "" },
+        },
+        {
+          id: "myTasks",
+          label: "鎴戠殑浠诲姟",
+          value: "0",
+          unread: 0,
+          urltype: 5,
+          icon: "IconTask",
+          url: "/followvisit/discharge",
+          trend: { type: "stable", arrow: "", value: "" },
+        },
+      ],
 
-      flag: true, // 鎺у埗鎮诞妗嗘槸鍚﹀睍寮�
-      box: "", // 鎮诞鐞冪殑dom
-      activeIndex: 0, //楂樹寒鏄剧ず
-      powerList: [
+      // 蹇嵎鎿嶄綔
+      quickActions: [
         {
-          path: require("@/assets/images/huanzheliebiao.png"),
-          url:'/patient/patient/',
-          label: "鎮h��",
+          id: "sms",
+          label: "鍒涘缓闂嵎浠诲姟",
+          icon: "IconMessageCircle",
+          url: "/followvisit/QuestionnaireTask?type=2&serviceType=2",
         },
         {
-          path: require("@/assets/images/fwwu.png"),
-          url:'/followvisit/tasklist/',
-          label: "浠诲姟",
+          id: "call",
+          label: "鍒涘缓璇煶浠诲姟",
+          icon: "IconPhone",
+          url: "/followvisit/particty?type=1&serviceType=2",
         },
-        {
-          path: require("@/assets/images/duanxinjilu.png"),
-          url:'',
-          label: "鐭俊",
-        },
-        {
-          path: require("@/assets/images/dianhua.png"),
-          url:'',
-          label: "鐢佃瘽",
-        },
-        {
-          path: require("@/assets/images/zxlt.png"),
-          url:'',
-          label: "鍦ㄧ嚎鑱婂ぉ",
-        },
+        // {
+        //   id: 'chat',
+        //   label: '鍦ㄧ嚎鑱婂ぉ',
+        //   icon: 'IconMessageCircle',
+        //   url: '/chat'
+        // }
       ],
     };
   },
-  created() {
-    this.clientWidth = document.documentElement.clientWidth;
-    this.clientHeight = document.documentElement.clientHeight;
+
+  computed: {
+    totalUnread() {
+      return this.statsItems.reduce((sum, item) => sum + item.unread, 0);
+    },
   },
+
   mounted() {
-    this.isCanDraggable &&
-      this.$nextTick(() => {
-        this.floatDrag = this.$refs.floatDrag;
-        // 鑾峰彇鍏冪礌浣嶇疆灞炴��
-        this.floatDragDom = this.floatDrag.getBoundingClientRect();
-        // 璁剧疆鍒濆浣嶇疆
-        this.left = this.clientWidth - this.floatDragDom.width - this.distanceRight;
-        // this.right = 0;
-        this.top =
-          this.clientHeight - this.floatDragDom.height - this.distanceBottom;
-        this.initDraggable();
-      });
-    // this.isScrollHidden && window.addEventListener('scroll', this.handleScroll);
+    this.roles = this.$store.state.user.roles;
+    this.loadPosition();
+
+    if (this.autoHide) {
+      this.startAutoHide();
+    }
+
+    // 鐐瑰嚮澶栭儴鍏抽棴
+    document.addEventListener("click", this.handleClickOutside);
+
+    // 绐楀彛澶у皬鍙樺寲鏃堕噸鏂板畾浣�
     window.addEventListener("resize", this.handleResize);
-
-    this.box = document.getElementById("float-box");
   },
-  beforeUnmount() {
-    window.removeEventListener("scroll", this.handleScroll);
+
+  beforeDestroy() {
+    document.removeEventListener("click", this.handleClickOutside);
     window.removeEventListener("resize", this.handleResize);
+    clearTimeout(this.hideTimer);
   },
-  methods: {
-    // 浼哥缉鎮诞鐞�
-    handelFlex() {
-      if (this.flag) {
-        this.buffer(this.box, "height", 600);
-      } else {
-        this.buffer(this.box, "height", 70);
-      }
-      this.flag = !this.flag;
-      console.log("鏄惁灞曞紑", this.flag);
-    },
-    // 鐐瑰嚮鍝釜power
-    activeHandle(index,url) {
-      //鎶婃垜浠嚜瀹氫箟鐨勪笅鏍囪祴鍊�
-      this.activeIndex = index;
-      this.$router.push({
-        path: url,
-      })
-      console.log("HHHH", index);
-    },
-    // 鑾峰彇瑕佹敼鍙樺緱鏍峰紡灞炴��
-    getStyleAttr(obj, attr) {
-      if (obj.currentStyle) {
-        // IE 鍜� opera
-        return obj.currentStyle[attr];
-      } else {
-        return window.getComputedStyle(obj, null)[attr];
-      }
-    },
-    // 鍔ㄧ敾鍑芥暟
-    buffer(eleObj, attr, target) {
-      // setInterval鏂瑰紡寮�鍚姩鐢�
-      //鍏堟竻鍚庤
-      // clearInterval(eleObj.timer);
-      // let speed = 0
-      // let begin = 0
-      // //璁剧疆瀹氭椂鍣�
-      // eleObj.timer = setInterval(() => {
-      //     //鑾峰彇鍔ㄧ敾灞炴�х殑鍒濆鍊�
-      //     begin = parseInt(this.getStyleAttr(eleObj, attr));
-      //     speed = (target - begin) * 0.2;
-      //     speed = target > begin ? Math.ceil(speed) : Math.floor(speed);
-      //     eleObj.style[attr] = begin + speed + "px";
-      //     if (begin === target) {
-      //         clearInterval(eleObj.timer);
-      //     }
-      // }, 20);
-      // cancelAnimationFrame寮�鍚姩鐢�
-      // 鍏堟竻鍚庤
-      cancelAnimationFrame(eleObj.timer);
-      let speed = 0;
-      let begin = 0;
-      let _this = this;
-      eleObj.timer = requestAnimationFrame(function fn() {
-        begin = parseInt(_this.getStyleAttr(eleObj, attr));
-        // 鍔ㄧ敾閫熷害
-        speed = (target - begin) * 0.9;
-        speed = target > begin ? Math.ceil(speed) : Math.floor(speed);
-        eleObj.style[attr] = begin + speed + "px";
-        eleObj.timer = requestAnimationFrame(fn);
-        if (begin === target) {
-          cancelAnimationFrame(eleObj.timer);
-        }
-      });
-    },
-    /**
-     * 绐楀彛resize鐩戝惉
-     */
-    handleResize() {
-      // this.clientWidth = document.documentElement.clientWidth;
-      // this.clientHeight = document.documentElement.clientHeight;
-      // console.log(window.innerWidth);
-      // console.log(document.documentElement.clientWidth);
 
-      this.checkDraggablePosition();
-    },
-    /**
-     * 鍒濆鍖杁raggable
-     */
-    initDraggable() {
-      this.floatDrag.addEventListener("touchstart", this.toucheStart);
-      this.floatDrag.addEventListener("touchmove", (e) => this.touchMove(e));
-      this.floatDrag.addEventListener("touchend", this.touchEnd);
-    },
-    mouseDown(e) {
-      const event = e || window.event;
-      this.mousedownX = event.screenX;
-      this.mousedownY = event.screenY;
-      const that = this;
-      let floatDragWidth = this.floatDragDom.width / 2;
-      let floatDragHeight = this.floatDragDom.height / 2;
-      if (event.preventDefault) {
-        event.preventDefault();
+  methods: {
+    toggleExpand() {
+      this.isExpanded = !this.isExpanded;
+      if (this.isExpanded) {
+        this.isHidden = false;
+        clearTimeout(this.hideTimer);
+        this.updateStats();
       }
-      this.canClick = false;
-      this.floatDrag.style.transition = "none";
-      document.onmousemove = function (e) {
-        var event = e || window.event;
-        that.left = event.clientX - floatDragWidth;
-        that.top = event.clientY - floatDragHeight;
-        if (that.left < 0) that.left = 0;
-        if (that.top < 0) that.top = 0;
-        // 榧犳爣绉诲嚭鍙鍖哄煙鍚庣粰鎸夐挳杩樺師
-        if (
-          event.clientY < 0 ||
-          event.clientY > Number(this.clientHeight) ||
-          event.clientX > Number(this.clientWidth) ||
-          event.clientX < 0
-        ) {
-          this.right = 0;
-          this.top =
-            this.clientHeight - this.floatDragDom.height - this.distanceBottom;
-          document.onmousemove = null;
-          this.floatDrag.style.transition = "all 0.3s";
-          return;
+    },
+
+    handleMouseEnter() {
+      this.isHovering = true;
+      if (this.autoHide) {
+        clearTimeout(this.hideTimer);
+        this.isHidden = false;
+      }
+    },
+
+    handleMouseLeave() {
+      this.isHovering = false;
+      if (this.autoHide && !this.isExpanded) {
+        this.startAutoHide();
+      }
+    },
+
+    startAutoHide() {
+      this.hideTimer = setTimeout(() => {
+        if (!this.isExpanded && !this.isHovering) {
+          this.isHidden = true;
         }
-        if (
-          that.left >=
-          document.documentElement.clientWidth - floatDragWidth * 2
-        ) {
-          that.left = document.documentElement.clientWidth - floatDragWidth * 2;
+      }, this.hideDelay);
+    },
+
+    startDrag(e) {
+      e.preventDefault();
+      e.stopPropagation();
+      this.isDragging = true;
+
+      const clientX = e.type.includes("touch")
+        ? e.touches[0].clientX
+        : e.clientX;
+      const clientY = e.type.includes("touch")
+        ? e.touches[0].clientY
+        : e.clientY;
+
+      this.dragStart = {
+        x: clientX - this.position.x,
+        y: clientY - this.position.y,
+      };
+
+      const onMove = (moveEvent) => {
+        if (!this.isDragging) return;
+
+        const moveX = moveEvent.type.includes("touch")
+          ? moveEvent.touches[0].clientX
+          : moveEvent.clientX;
+        const moveY = moveEvent.type.includes("touch")
+          ? moveEvent.touches[0].clientY
+          : moveEvent.clientY;
+
+        const newX = moveX - this.dragStart.x;
+        const newY = moveY - this.dragStart.y;
+
+        // 杈圭晫妫�鏌�
+        const maxX = window.innerWidth - 60;
+        const maxY = window.innerHeight - 60;
+
+        this.position.x = Math.max(0, Math.min(newX, maxX));
+        this.position.y = Math.max(0, Math.min(newY, maxY));
+      };
+
+      const onEnd = () => {
+        this.isDragging = false;
+        document.removeEventListener("mousemove", onMove);
+        document.removeEventListener("mouseup", onEnd);
+        document.removeEventListener("touchmove", onMove);
+        document.removeEventListener("touchend", onEnd);
+
+        // 濡傛灉闈犺繎杈圭紭锛岃嚜鍔ㄥ惛闄�
+        if (this.position.x < 20) {
+          this.position.x = 0;
+        } else if (this.position.x > window.innerWidth - 80) {
+          this.position.x = window.innerWidth - 60;
         }
-        if (that.top >= that.clientHeight - floatDragHeight * 2) {
-          that.top = that.clientHeight - floatDragHeight * 2;
+
+        // 淇濆瓨浣嶇疆鍒版湰鍦板瓨鍌�
+        try {
+          localStorage.setItem(
+            "floatBallPosition",
+            JSON.stringify(this.position)
+          );
+        } catch (e) {
+          console.error("淇濆瓨浣嶇疆澶辫触:", e);
         }
       };
+
+      document.addEventListener("mousemove", onMove);
+      document.addEventListener("mouseup", onEnd);
+      document.addEventListener("touchmove", onMove, { passive: false });
+      document.addEventListener("touchend", onEnd);
     },
-    mouseUp(e) {
-      const event = e || window.event;
-      //鍒ゆ柇鍙槸鍗曠函鐨勭偣鍑伙紝娌℃湁鎷栨嫿
+
+    handleItemClick(item) {
+      if (item.url) {
+        console.log(item.url, "item.url");
+
+        // this.$router.push(item.url);
+        this.$router.replace({
+          path: item.url,
+          query: {
+            errtype: item.urltype,
+          },
+        });
+        this.toggleExpand();
+      }
+    },
+
+    handleActionClick(action) {
+      console.log(this.roles, "this.roles");
       if (
-        this.mousedownY == event.screenY &&
-        this.mousedownX == event.screenX
+        action.url &&
+        (this.roles.includes("admin") || this.roles.includes("sysadmin"))
       ) {
-        this.$emit("handlepaly");
-      }
-      document.onmousemove = null;
-      this.checkDraggablePosition();
-      this.floatDrag.style.transition = "all 0.3s";
-    },
-    toucheStart() {
-      this.canClick = false;
-      this.floatDrag.style.transition = "none";
-    },
-    touchMove(e) {
-      this.canClick = true;
-      if (e.targetTouches.length === 1) {
-        // 鍗曟寚鎷栧姩
-        let touch = event.targetTouches[0];
-        this.left = touch.clientX - this.floatDragDom.width / 2;
-        this.top = touch.clientY - this.floatDragDom.height / 2;
-      }
-    },
-    touchEnd() {
-      if (!this.canClick) return; // 瑙e喅鐐瑰嚮浜嬩欢鍜宼ouch浜嬩欢鍐茬獊鐨勯棶棰�
-      this.floatDrag.style.transition = "all 0.3s";
-      this.checkDraggablePosition();
-    },
-    /**
-     * 鍒ゆ柇鍏冪礌鏄剧ず浣嶇疆
-     * 鍦ㄧ獥鍙f敼鍙樺拰move end鏃惰皟鐢�
-     */
-    checkDraggablePosition() {
-      this.clientWidth = document.documentElement.clientWidth;
-      this.clientHeight = document.documentElement.clientHeight;
-      if (this.left + this.floatDragDom.width / 2 >= this.clientWidth / 2) {
-        // 鍒ゆ柇浣嶇疆鏄線宸﹀線鍙虫粦鍔�
-        this.left = this.clientWidth - this.floatDragDom.width;
+        this.$router.replace(action.url);
+        this.toggleExpand();
       } else {
-        this.left = 0;
+        this.$modal.msgError("闈炵鐞嗗憳鐢ㄦ埛鏆傛棤鍒涘缓浠诲姟鏉冮檺");
       }
-      if (this.top < 0) {
-        // 鍒ゆ柇鏄惁瓒呭嚭灞忓箷涓婃部
-        this.top = 0;
+    },
+
+    async updateStats() {
+      try {
+        // 杩欓噷鍙互鏇挎崲涓哄疄闄呯殑 API 璋冪敤
+        // const response = await this.$api.getFollowupStats()
+        // this.statsItems = response.data
+
+        // 妯℃嫙鏁版嵁鏇存柊
+        const mockData = {
+          pending: {
+            value: "128",
+            unread: null,
+            trend: { type: "up", arrow: "鈫�", value: "5" },
+          },
+          failed: {
+            value: "24",
+            unread: null,
+            trend: { type: "down", arrow: "鈫�", value: "2" },
+          },
+          abnormal: {
+            value: "8",
+            unread: null,
+            trend: { type: "up", arrow: "鈫�", value: "3" },
+          },
+          myTasks: {
+            value: "156",
+            unread: null,
+            trend: { type: "stable", arrow: "鈫�", value: "0" },
+          },
+        };
+        const response = await getCurrentUserServiceSubtaskCount();
+        mockData.pending.value = response.pendingVisitCount;
+        mockData.failed.value = response.failedVisitCount;
+        mockData.abnormal.value = response.abnormalVisitCount;
+        mockData.myTasks.value = response.allVisitCount;
+        this.statsItems = this.statsItems.map((item) => {
+          const data = mockData[item.id] || {};
+          return {
+            ...item,
+            value: data.value || item.value,
+            unread: data.unread || item.unread,
+            trend: data.trend || item.trend,
+          };
+        });
+
+        // 鏇存柊鏃堕棿
+        const now = new Date();
+        this.updateTime = `${now.getHours().toString().padStart(2, "0")}:${now
+          .getMinutes()
+          .toString()
+          .padStart(2, "0")}`;
+      } catch (error) {
+        console.error("鏇存柊缁熻鏁版嵁澶辫触:", error);
       }
-      if (this.top + this.floatDragDom.height >= this.clientHeight) {
-        // 鍒ゆ柇鏄惁瓒呭嚭灞忓箷涓嬫部
-        this.top = this.clientHeight - this.floatDragDom.height;
+    },
+
+    loadPosition() {
+      try {
+        const savedPosition = localStorage.getItem("floatBallPosition");
+        if (savedPosition) {
+          const parsed = JSON.parse(savedPosition);
+          this.position = parsed;
+        }
+      } catch (e) {
+        console.error("鍔犺浇浣嶇疆澶辫触:", e);
       }
+    },
+
+    handleClickOutside(e) {
+      if (
+        this.isExpanded &&
+        this.$refs.floatBall &&
+        !this.$refs.floatBall.contains(e.target)
+      ) {
+        this.toggleExpand();
+      }
+    },
+
+    handleResize() {
+      const maxX = window.innerWidth - 60;
+      const maxY = window.innerHeight - 60;
+
+      this.position.x = Math.min(this.position.x, maxX);
+      this.position.y = Math.min(this.position.y, maxY);
     },
   },
 };
 </script>
-<style>
-html,
-body {
-  overflow: hidden;
-}
-</style>
-<style scoped lang="scss">
-.float-position {
+
+<style scoped>
+.float-ball {
   position: fixed;
-  z-index: 10003 !important;
-  left: 0;
-  top: 20%;
-  width: 70px;
-  height: 70px;
-  border-radius: 32px;
+  z-index: 9999;
+  transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
+  pointer-events: auto;
+}
+
+.float-ball-hidden {
+  opacity: 0.3;
+  transform: translateX(10px);
+}
+
+.float-ball-hidden:hover {
+  opacity: 1;
+  transform: translateX(0);
+}
+
+.ball-main {
+  width: 60px;
+  height: 60px;
+  border-radius: 50%;
+  background: linear-gradient(135deg, var(--primary-color), #7c3aed);
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  cursor: move;
+  box-shadow: 0 4px 20px rgba(79, 70, 229, 0.3);
+  transition: all 0.3s ease;
+  position: relative;
+  z-index: 10000;
+}
+
+.ball-main:hover {
+  background: linear-gradient(135deg, var(--hover-color), #6d28d9);
+  box-shadow: 0 6px 25px rgba(79, 70, 229, 0.4);
+  transform: scale(1.05);
+}
+
+.ball-main-expanded {
+  background: linear-gradient(135deg, #6366f1, #8b5cf6);
+}
+
+.ball-icon {
+  width: 24px;
+  height: 24px;
+  color: white;
+}
+
+.fold-icon {
+  width: 100%;
+  height: 100%;
+}
+
+.close-btn {
+  width: 24px;
+  height: 24px;
+  display: flex;
+  align-items: center;
+  justify-content: center;
   cursor: pointer;
-  overflow: hidden;
-  user-select: none;
+  color: white;
+  transition: transform 0.2s ease;
+}
 
-  display: block;
-  background: black;
-  background: -webkit-radial-gradient(100px 100px, circle, #5788FE, #292929);
-  //   background: -moz-radial-gradient(100px 100px, circle, #35a1a1, #000);Firefox 娴忚鍣ㄧ殑瀹炵幇
-  //   background: radial-gradient(100px 100px, circle, #35a1a1, #000);鏍囧噯 HTML5 灞炴��
-  margin: 0;
-  .drag {
-    width: 70px;
-    height: 35px;
-    // background: #f2e96a;
-    text-align: center;
-    line-height: 35px;
-    border-bottom: 1px solid #fff;
+.close-btn:hover {
+  transform: rotate(90deg);
+}
+
+.close-icon {
+  width: 20px;
+  height: 20px;
+}
+
+.ball-badge {
+  position: absolute;
+  top: -5px;
+  right: -5px;
+  min-width: 20px;
+  height: 20px;
+  padding: 0 6px;
+  background: #ef4444;
+  color: white;
+  font-size: 12px;
+  font-weight: 600;
+  border-radius: 10px;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  border: 2px solid white;
+  animation: pulse 2s infinite;
+}
+
+@keyframes pulse {
+  0%,
+  100% {
+    transform: scale(1);
   }
-  .content {
-    width: 70px;
-    height: 35px;
-    // background: #716af2;
-    .label {
-      width: 70px;
-      height: 35px;
-      text-align: center;
-      line-height: 35px;
-      color: white;
-    }
-    .label:hover {
-      color: rgb(19, 217, 243);
-      transition: all 0.5;
-    }
-
-    .item-container {
-      margin-top: 10px;
-      width: 70px;
-      height: 500px;
-      display: flex;
-      justify-content: space-between;
-      align-items: center;
-      flex-direction: column;
-
-      .power-item {
-        width: 40px;
-        height: 40px;
-        border-radius: 50%;
-        background-color: #f1f7ff;
-        display: flex;
-        justify-content: center;
-        align-items: center;
-        flex-direction: column;
-      }
-      .des {
-        width: 40px;
-        text-align: center;
-        margin-bottom: 5px;
-        font-size: 10px;
-        color: #fff;
-      }
-    }
-  }
-
-  .close {
-    width: 20px;
-    height: 20px;
-    border-radius: 50%;
-    display: flex;
-    align-items: center;
-    justify-content: center;
-    color: #fff;
-    background: rgba(0, 0, 0, 0.6);
-    position: absolute;
-    right: -10px;
-    top: -12px;
-    cursor: pointer;
+  50% {
+    transform: scale(1.1);
   }
 }
 
-.cart {
-  border-radius: 50%;
-  width: 5em;
-  height: 5em;
+.ball-content {
+  position: absolute;
+  top: 70px;
+  left: 0;
+  width: 320px;
+  background: white;
+  border-radius: 16px;
+  box-shadow: 0 10px 40px rgba(0, 0, 0, 0.1);
+  overflow: hidden;
+  z-index: 9999;
+}
+
+.ball-expand-enter-active,
+.ball-expand-leave-active {
+  transition: all 0.3s ease;
+}
+
+.ball-expand-enter,
+.ball-expand-leave-to {
+  opacity: 0;
+  transform: translateY(-10px);
+}
+
+.content-header {
+  padding: 20px 20px 16px;
+  background: linear-gradient(135deg, var(--primary-color), #7c3aed);
+  color: white;
+}
+
+.content-header h3 {
+  margin: 0 0 8px 0;
+  font-size: 18px;
+  font-weight: 600;
+}
+
+.update-time {
+  font-size: 12px;
+  opacity: 0.9;
+}
+
+.stats-grid {
+  padding: 16px;
+  display: grid;
+  grid-template-columns: 1fr 1fr;
+  gap: 12px;
+}
+
+.stat-item {
+  padding: 16px;
+  background: #f8fafc;
+  border-radius: 12px;
+  cursor: pointer;
+  transition: all 0.2s ease;
+  position: relative;
+  border: 2px solid transparent;
+}
+
+.stat-item:hover {
+  background: #f1f5f9;
+  border-color: #e2e8f0;
+  transform: translateY(-2px);
+}
+
+.stat-item-highlight {
+  border-color: var(--primary-color);
+  background: linear-gradient(to bottom right, #f0f9ff, #f8fafc);
+}
+
+.stat-icon {
+  width: 32px;
+  height: 32px;
+  background: white;
+  border-radius: 8px;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  margin-bottom: 12px;
+  color: var(--primary-color);
+  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
+}
+
+.stat-icon svg {
+  width: 18px;
+  height: 18px;
+}
+
+.stat-label {
+  font-size: 12px;
+  color: #64748b;
+  margin-bottom: 4px;
+}
+
+.stat-value {
+  font-size: 20px;
+  font-weight: 700;
+  color: #1e293b;
+  margin-bottom: 4px;
+}
+
+.stat-trend {
+  font-size: 11px;
+  display: flex;
+  align-items: center;
+  gap: 2px;
+}
+
+.trend-up {
+  color: #10b981;
+}
+
+.trend-down {
+  color: #ef4444;
+}
+
+.trend-stable {
+  color: #64748b;
+}
+
+.trend-arrow {
+  font-size: 10px;
+}
+
+.stat-badge {
+  position: absolute;
+  top: 12px;
+  right: 12px;
+  min-width: 18px;
+  height: 18px;
+  padding: 0 4px;
+  background: #ef4444;
+  color: white;
+  font-size: 10px;
+  font-weight: 600;
+  border-radius: 9px;
   display: flex;
   align-items: center;
   justify-content: center;
 }
 
-.header-notice {
-  display: inline-block;
-  transition: all 0.3s;
-
-  span {
-    vertical-align: initial;
-  }
-
-  .notice-badge {
-    color: inherit;
-
-    .header-notice-icon {
-      font-size: 16px;
-      padding: 4px;
-    }
-  }
+.quick-actions {
+  padding: 12px 20px 20px;
+  border-top: 1px solid #f1f5f9;
+  display: flex;
+  gap: 12px;
+  justify-content: center;
 }
 
-.drag-ball .drag-content {
-  overflow-wrap: break-word;
-  font-size: 14px;
-  color: #fff;
-  letter-spacing: 2px;
+.action-item {
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  gap: 8px;
+  cursor: pointer;
+  padding: 12px;
+  border-radius: 8px;
+  transition: all 0.2s ease;
+  flex: 1;
 }
 
-.active {
-  background-color: #f9f1db !important;
+.action-item:hover {
+  background: #f8fafc;
 }
-.active-des {
-  color: #71dcfa !important;
-  font-size: 20px !important;
-  font-weight: 500 !important;
+
+.action-icon {
+  width: 24px;
+  height: 24px;
+  color: var(--primary-color);
+}
+
+.action-icon svg {
+  width: 20px;
+  height: 20px;
+}
+
+.action-label {
+  font-size: 12px;
+  color: #475569;
+  font-weight: 500;
 }
 </style>
diff --git a/src/components/CallButton/index.vue b/src/components/CallButton/index.vue
index c839632..8e45ab5 100644
--- a/src/components/CallButton/index.vue
+++ b/src/components/CallButton/index.vue
@@ -11,10 +11,17 @@
 
     <!-- 鍛煎彨鎸夐挳 -->
     <button
-      :class="['call-btn', { calling: isCalling }]"
+      :class="[
+        'call-btn',
+        {
+          calling: isCalling,
+          registering: isRegistering,
+        },
+      ]"
       @click="startCall"
-      :disabled="isCalling || sipStatus !== '宸叉敞鍐�'"
+      :disabled="isButtonDisabled"
     >
+      <i v-if="isRegistering" class="el-icon-loading"></i>
       {{ callButtonText }}
     </button>
 
@@ -41,15 +48,18 @@
     const randomNum = Math.floor(Math.random() * 20) + 1000; // 瀹氫箟闅忔満鍒嗘満鍙�
     return {
       isCalling: false,
+      isRegistering: true, // 鍒濆涓烘敞鍐屼腑鐘舵��
       randomNum: randomNum,
       randomID: null,
       callStatus: "idle", // idle, calling, connected, ended
       sipStatus: "鏈繛鎺�",
       sipStatusClass: "status-disconnected",
       sipConfig: {
-        wsUrl: "wss://192.168.10.124:7443",
+        // 绉婚櫎纭紪鐮佺殑wsUrl鍜宒omain
+        wsUrl: "",
         sipUri: "",
-        password: "Smartor@2023",
+        password: "Smartor@2023",//涓芥按
+        // password: "heskj@1234",//甯備竴
         displayName: "Web 灏忛緳",
         // realm: "9.208.5.18:8090",
       },
@@ -74,11 +84,17 @@
       }
       return "";
     },
-    callStatusClass() {
-      return `status-${this.callStatus}`;
+    isButtonDisabled() {
+      return (
+        this.isCalling || this.sipStatus !== "宸叉敞鍐�" || this.isRegistering
+      );
     },
     callButtonText() {
+      if (this.isRegistering) return "娉ㄥ唽涓�...";
       return this.isCalling ? "閫氳瘽涓�..." : "涓�閿懠鍙�";
+    },
+    callStatusClass() {
+      return `status-${this.callStatus}`;
     },
   },
   created() {
@@ -86,16 +102,29 @@
   },
 
   async mounted() {
+    const orgName = localStorage.getItem("orgname");
+    if (orgName == "鏅畞鐣叉棌鑷不鍘夸汉姘戝尰闄�") {
+      return;
+    }
     await this.CallgetList();
+    this.isRegistering = true; // 寮�濮嬫敞鍐�
     sipService.init(this.sipConfig);
     // 璁剧疆鐘舵�佸洖璋�
     sipService.onStatusChange = (status) => {
       this.sipStatus = status.text;
       this.sipStatusClass = `status-${status.type}`;
-
+      // 娉ㄥ唽鎴愬姛鎴栧け璐ユ椂鍙栨秷鍔犺浇鐘舵��
+      if (status.type === "registered" || status.type === "failed") {
+        this.isRegistering = false;
+      }
+      // 娉ㄥ唽鎴愬姛
+      if (status.type === "registered") {
+        this.startCallsetState();
+      }
       // 澶勭悊娉ㄥ唽澶辫触鍜屾柇寮�杩炴帴鎯呭喌
       if (status.type === "failed" || status.type === "disconnected") {
         this.overCallsetState(); // 閲婃斁鍒嗘満鍙�
+        this.isRegistering = false;
       }
     };
 
@@ -107,6 +136,13 @@
       // 閫氱煡鐖剁粍浠堕�氳瘽鐘舵�佸彉鍖�
       this.$emit("call-status-change", status);
     };
+    // 娣诲姞娉ㄥ唽瓒呮椂澶勭悊
+    setTimeout(() => {
+      if (this.isRegistering && this.sipStatus !== "宸叉敞鍐�") {
+        this.isRegistering = false;
+        this.$message.warning("SIP娉ㄥ唽瓒呮椂锛岃妫�鏌ョ綉缁滆繛鎺�");
+      }
+    }, 10000); // 10绉掕秴鏃�
   },
   methods: {
     async startCall() {
@@ -158,9 +194,15 @@
         const res = await CallgetList();
         this.randomNum = res.data[0].tel;
         this.randomID = res.data[0].id;
-        // 姝g‘璁剧疆 sipUri
-        this.sipConfig.sipUri = `${this.randomNum}@192.168.10.124`;
-        this.startCallsetState();
+        // 鍔ㄦ�佽缃畇ipUri锛屽煙鍚嶉儴鍒嗕細鍦╯ipService涓姩鎬佸鐞�
+        const orgName = localStorage.getItem("orgname");
+        if (orgName == "涓芥按甯備腑鍖婚櫌") {
+          this.sipConfig.sipUri = `${this.randomNum}@192.168.10.124`;
+        } else if (orgName == "榫欐硥甯備汉姘戝尰闄�") {
+          this.sipConfig.sipUri = `${this.randomNum}@10.10.0.220`;
+        } else if (orgName == "绗竴浜烘皯鍖婚櫌婀栨花闄㈠尯"||orgName == "绗竴浜烘皯鍖婚櫌鍚村北闄㈠尯") {
+          this.sipConfig.sipUri = `${this.randomNum}@192.169.129.198`;
+        }
       } catch (error) {
         console.error("鑾峰彇鍒嗘満鍙峰け璐�:", error);
         // this.updateStatus("failed", "鑾峰彇鍒嗘満鍙峰け璐�");
diff --git a/src/components/Regular/index.vue b/src/components/Regular/index.vue
index 30d359f..86c2bc4 100644
--- a/src/components/Regular/index.vue
+++ b/src/components/Regular/index.vue
@@ -18,13 +18,21 @@
               </el-input> </el-form-item
           ></el-col>
           <el-col :span="12"
-            ><el-form-item label="寮傚父鎻愰啋">
-              <el-radio-group v-model="item.isabnormal">
-                <el-radio :label="1">鏄�</el-radio>
-                <el-radio :label="0">鍚�</el-radio>
-              </el-radio-group>
-            </el-form-item></el-col
-          >
+          ><el-form-item label="寮傚父鎻愰啋">
+            <el-select v-model="item.isabnormal" placeholder="璇烽�夋嫨鐘舵��">
+              <el-option :value="0" label="姝e父" :style="{ color: '#67C23A' }">
+                <span style="color: #67c23a">鈼� 姝e父</span>
+              </el-option>
+
+              <el-option :value="2" label="璀﹀憡" :style="{ color: '#FFBA00' }">
+                <span style="color: #ffba00">鈼� 璀﹀憡</span>
+              </el-option>
+              <el-option :value="1" label="寮傚父" :style="{ color: '#f75c5c' }">
+                <span style="color: #f75c5c">鈼� 寮傚父</span>
+              </el-option>
+            </el-select>
+          </el-form-item></el-col
+        >
           <!-- <el-col :span="12" v-if="intent"
             ><el-form-item label="閫夐」鑺傜偣">
               <el-input
diff --git a/src/components/SortCheckbox/index.vue b/src/components/SortCheckbox/index.vue
index 4ae95f1..45107e3 100644
--- a/src/components/SortCheckbox/index.vue
+++ b/src/components/SortCheckbox/index.vue
@@ -48,12 +48,23 @@
   name: "OrderedCheckboxGroup",
   props: {
     options: {
-      type: Array,
-      default: () => [],
+        type: Array,
+        default: () => [],
+        validator: (value) => {
+            return Array.isArray(value);
+        }
     },
     value: {
-      type: Array,
-      default: () => [],
+        type: Array,
+        default: () => [],
+        validator: (value) => {
+            // 鍏佽绌烘暟缁勶紝浣嗗鏋滄槸闈炴暟缁勫�煎垯鍙戝嚭璀﹀憡
+            if (!Array.isArray(value) && value !== null && value !== undefined) {
+                console.warn('value prop should be an array, received:', typeof value);
+                return false;
+            }
+            return true;
+        }
     },
     initialselectedOrder: {
       type: Array,
@@ -83,16 +94,20 @@
     value: {
       immediate: true,
       handler(newVal) {
-        if (
-          Array.isArray(newVal) &&
-          newVal.length > 0 &&
-          typeof newVal[0] === "object"
-        ) {
-          console.log(this.selectedOrder, "111");
+        // 棣栧厛纭繚newVal鏄暟缁勶紝濡傛灉涓嶆槸鍒欒浆鎹负绌烘暟缁�
+        if (!Array.isArray(newVal)) {
+          console.warn(
+            "Expected array for value prop, received:",
+            typeof newVal
+          );
+          this.checkedValues = [];
+          this.selectedOrder = [];
+          return;
+        }
 
+        if (newVal.length > 0 && typeof newVal[0] === "object") {
           // 1. 浼犲叆鐨勬槸瀵硅薄鏁扮粍 [{ sort, preachform, compensateTime }]
-          this.checkedValues = newVal.map((item) => item.preachform); // 鎻愬彇 preachform 缁勬垚閫変腑鍊兼暟缁�
-          // 鏋勫缓 selectedOrder锛屼紭鍏堜娇鐢ㄤ紶鍏ョ殑 compensateTime锛屽惁鍒欑敤榛樿鍊�
+          this.checkedValues = newVal.map((item) => item.preachform);
           this.selectedOrder = newVal.map((item) => ({
             value: item.preachform,
             compensateTime: item.hasOwnProperty("compensateTime")
@@ -100,12 +115,11 @@
               : this.defaultCompensateTime,
           }));
         } else {
-          // 2. 浼犲叆鐨勬槸瀛楃涓叉暟缁� (濡� ["1", "3", "4"]锛屽吋瀹逛箣鍓嶇殑鐢ㄦ硶)
+          // 2. 浼犲叆鐨勬槸瀛楃涓叉暟缁�
           if (JSON.stringify(newVal) !== JSON.stringify(this.checkedValues)) {
             this.checkedValues = [...newVal];
             console.log(this.selectedOrder, "222");
-            console.log(this.newVal, "22");
-            // 鏋勫缓鎴栨洿鏂� selectedOrder锛屼繚鐣欏凡鏈夌殑 compensateTime
+
             const newOrder = [];
             newVal.forEach((value) => {
               const existingItem = this.selectedOrder.find(
@@ -114,11 +128,14 @@
               if (existingItem) {
                 newOrder.push(existingItem);
               } else {
+                // 淇hasOwnProperty鏂规硶璋冪敤
+                const existingCompensateTime = this.hasOwnProperty(value);
                 newOrder.push({
                   value,
-                  compensateTime: this.hasOwnProperty(value)
-                    ? this.hasOwnProperty(value)
-                    : this.defaultCompensateTime,
+                  compensateTime:
+                    existingCompensateTime !== false
+                      ? existingCompensateTime
+                      : this.defaultCompensateTime,
                 });
               }
             });
@@ -126,7 +143,7 @@
           }
         }
       },
-      deep: true, // 寤鸿娣诲姞 deep: true 浠ョ‘淇濆璞℃暟缁勫唴鐨勫彉鍖栬兘琚崟鑾�
+      deep: true,
     },
     checkedValues(newVal, oldVal) {
       console.log(this.selectedOrder, "333");
@@ -186,15 +203,17 @@
       }
     },
     hasOwnProperty(patfrom) {
-      console.log(patfrom);
-      console.log(this.initialselectedOrder);
-      // 浣跨敤find鏂规硶鏌ユ壘鍖归厤鐨勫璞�
-      const foundObject = this.initialselectedOrder.find(
-        (item) => item.preachform === patfrom
-      );
+      if (!this.initialselectedOrder || !Array.isArray(this.initialselectedOrder)) {
+        return false;
+    }
 
-      // 濡傛灉鎵惧埌瀵硅薄锛岃繑鍥炲叾compensateTime锛涘惁鍒欒繑鍥瀎alse
-      return foundObject ? foundObject.compensateTime : false;
+    // 浣跨敤find鏂规硶鏌ユ壘鍖归厤鐨勫璞�
+    const foundObject = this.initialselectedOrder.find(
+        (item) => item.preachform === patfrom
+    );
+
+    // 濡傛灉鎵惧埌瀵硅薄锛岃繑鍥炲叾compensateTime锛涘惁鍒欒繑鍥瀎alse
+    return foundObject ? foundObject.compensateTime : false;
     },
     // 鍙戝皠鍙樺寲浜嬩欢
     emitChangeEvent() {
diff --git a/src/layout/components/Navbar.vue b/src/layout/components/Navbar.vue
index 3ad514a..77c84b1 100644
--- a/src/layout/components/Navbar.vue
+++ b/src/layout/components/Navbar.vue
@@ -1,12 +1,21 @@
 <template>
   <div class="navbar">
-    <hamburger id="hamburger-container" :is-active="sidebar.opened" class="hamburger-container" @toggleClick="toggleSideBar" />
+    <hamburger
+      id="hamburger-container"
+      :is-active="sidebar.opened"
+      class="hamburger-container"
+      @toggleClick="toggleSideBar"
+    />
 
-    <breadcrumb id="breadcrumb-container" class="breadcrumb-container" v-if="!topNav"/>
-    <top-nav id="topmenu-container" class="topmenu-container" v-if="topNav"/>
+    <breadcrumb
+      id="breadcrumb-container"
+      class="breadcrumb-container"
+      v-if="!topNav"
+    />
+    <top-nav id="topmenu-container" class="topmenu-container" v-if="topNav" />
 
     <div class="right-menu">
-      <template v-if="device!=='mobile'">
+      <template v-if="device !== 'mobile'">
         <search id="header-search" class="right-menu-item" />
 
         <!-- <el-tooltip content="婧愮爜鍦板潃" effect="dark" placement="bottom">
@@ -22,12 +31,15 @@
         <!-- <el-tooltip content="甯冨眬澶у皬" effect="dark" placement="bottom">
           <size-select id="size-select" class="right-menu-item hover-effect" />
         </el-tooltip> -->
-
+        <span class="username">{{ username }}</span>
       </template>
 
-      <el-dropdown class="avatar-container right-menu-item hover-effect" trigger="click">
+      <el-dropdown
+        class="avatar-container right-menu-item hover-effect"
+        trigger="click"
+      >
         <div class="avatar-wrapper">
-          <img :src="avatar" class="user-avatar">
+          <img :src="avatar" class="user-avatar" />
           <i class="el-icon-caret-bottom" />
         </div>
         <el-dropdown-menu slot="dropdown">
@@ -47,15 +59,15 @@
 </template>
 
 <script>
-import { mapGetters } from 'vuex'
-import Breadcrumb from '@/components/Breadcrumb'
-import TopNav from '@/components/TopNav'
-import Hamburger from '@/components/Hamburger'
-import Screenfull from '@/components/Screenfull'
-import SizeSelect from '@/components/SizeSelect'
-import Search from '@/components/HeaderSearch'
-import RuoYiGit from '@/components/RuoYi/Git'
-import RuoYiDoc from '@/components/RuoYi/Doc'
+import { mapGetters } from "vuex";
+import Breadcrumb from "@/components/Breadcrumb";
+import TopNav from "@/components/TopNav";
+import Hamburger from "@/components/Hamburger";
+import Screenfull from "@/components/Screenfull";
+import SizeSelect from "@/components/SizeSelect";
+import Search from "@/components/HeaderSearch";
+import RuoYiGit from "@/components/RuoYi/Git";
+import RuoYiDoc from "@/components/RuoYi/Doc";
 
 export default {
   components: {
@@ -66,48 +78,51 @@
     SizeSelect,
     Search,
     RuoYiGit,
-    RuoYiDoc
+    RuoYiDoc,
   },
   computed: {
-    ...mapGetters([
-      'sidebar',
-      'avatar',
-      'device'
-    ]),
+    ...mapGetters(["sidebar", "avatar", "device"]),
     setting: {
       get() {
-        return this.$store.state.settings.showSettings
+        return this.$store.state.settings.showSettings;
       },
       set(val) {
-        this.$store.dispatch('settings/changeSetting', {
-          key: 'showSettings',
-          value: val
-        })
-      }
+        this.$store.dispatch("settings/changeSetting", {
+          key: "showSettings",
+          value: val,
+        });
+      },
     },
     topNav: {
       get() {
-        return this.$store.state.settings.topNav
-      }
-    }
+        return this.$store.state.settings.topNav;
+      },
+    },
+    username: {
+      get() {
+        return this.$store.state.user.name;
+      },
+    },
   },
   methods: {
     toggleSideBar() {
-      this.$store.dispatch('app/toggleSideBar')
+      this.$store.dispatch("app/toggleSideBar");
     },
     async logout() {
-      this.$confirm('纭畾娉ㄩ攢骞堕��鍑虹郴缁熷悧锛�', '鎻愮ず', {
-        confirmButtonText: '纭畾',
-        cancelButtonText: '鍙栨秷',
-        type: 'warning'
-      }).then(() => {
-        this.$store.dispatch('LogOut').then(() => {
-          location.href = '/index';
+      this.$confirm("纭畾娉ㄩ攢骞堕��鍑虹郴缁熷悧锛�", "鎻愮ず", {
+        confirmButtonText: "纭畾",
+        cancelButtonText: "鍙栨秷",
+        type: "warning",
+      })
+        .then(() => {
+          this.$store.dispatch("LogOut").then(() => {
+            location.href = "/index";
+          });
         })
-      }).catch(() => {});
-    }
-  }
-}
+        .catch(() => {});
+    },
+  },
+};
 </script>
 
 <style lang="scss" scoped>
@@ -116,21 +131,20 @@
   overflow: hidden;
   position: relative;
   background: #fff;
-  box-shadow: 0 1px 4px rgba(0,21,41,.08);
+  box-shadow: 0 1px 4px rgba(0, 21, 41, 0.08);
 
   .hamburger-container {
     line-height: 46px;
     height: 100%;
     float: left;
     cursor: pointer;
-    transition: background .3s;
-    -webkit-tap-highlight-color:transparent;
+    transition: background 0.3s;
+    -webkit-tap-highlight-color: transparent;
 
     &:hover {
-      background: rgba(0, 0, 0, .025)
+      background: rgba(0, 0, 0, 0.025);
     }
   }
-
   .breadcrumb-container {
     float: left;
   }
@@ -149,13 +163,17 @@
     float: right;
     height: 100%;
     line-height: 50px;
+    display: flex; // 鏂板
+    align-items: center; // 鏂板锛氬瀭鐩村眳涓�
+    justify-content: center; // 鍙�夛細姘村钩灞呬腑
 
     &:focus {
       outline: none;
     }
 
     .right-menu-item {
-      display: inline-block;
+      display: inline-flex; // 淇敼涓篿nline-flex
+      align-items: center; // 纭繚鍐呭鍨傜洿灞呬腑
       padding: 0 8px;
       height: 100%;
       font-size: 18px;
@@ -164,17 +182,25 @@
 
       &.hover-effect {
         cursor: pointer;
-        transition: background .3s;
+        transition: background 0.3s;
 
         &:hover {
-          background: rgba(0, 0, 0, .025)
+          background: rgba(0, 0, 0, 0.025);
         }
       }
     }
-
+    .username {
+      // 鍒犻櫎鍘熸潵鐨� margin-bottom: 20px;
+      display: flex;
+      align-items: center;
+      color: #1789fa;
+      height: 100%;
+      padding: 0 12px;
+      white-space: nowrap; // 闃叉鏂囧瓧鎹㈣
+    }
     .avatar-container {
       margin-right: 30px;
-
+      margin-top: 10px;
       .avatar-wrapper {
         margin-top: 5px;
         position: relative;
diff --git a/src/main.js b/src/main.js
index 1207e98..06edb6c 100644
--- a/src/main.js
+++ b/src/main.js
@@ -13,6 +13,7 @@
 import router from "./router";
 import directive from "./directive"; // directive
 import plugins from "./plugins"; // plugins
+import Print from 'vue-print-nb'
 import { download } from "@/utils/request";
 //寮曞叆quill-editor缂栬緫鍣�
 import VueQuillEditor from "vue-quill-editor";
@@ -21,6 +22,8 @@
 import "quill/dist/quill.snow.css";
 import "quill/dist/quill.bubble.css";
 Vue.use(VueQuillEditor);
+Vue.use(Print)
+
 // 寮曞叆
 import { codemirror } from "vue-codemirror";
 import "@/utils/cm-setting.js";
@@ -89,6 +92,14 @@
   Vue.filter(key, filters[key]);
 }
 import moment from "moment"
+// 1. 鍦╩ain.js涓坊鍔犻敊璇洃鍚�
+window.addEventListener('unhandledrejection', (event) => {
+  if (event.reason && event.reason.message &&
+      event.reason.message.includes('Loading chunk')) {
+    // 閲嶆柊鍔犺浇椤甸潰
+    window.location.reload();
+  }
+});
 
 Vue.prototype.$moment = moment;
 
diff --git a/src/plugins/auth.js b/src/plugins/auth.js
index 6c6bc24..302e5b1 100644
--- a/src/plugins/auth.js
+++ b/src/plugins/auth.js
@@ -1,20 +1,31 @@
-import store from '@/store'
+import store from "@/store";
 
 function authPermission(permission) {
   const all_permission = "*:*:*";
-  const permissions = store.getters && store.getters.permissions
+  const permissions = store.getters && store.getters.permissions;
   if (permission && permission.length > 0) {
-    return permissions.some(v => {
-      return all_permission === v || v === permission
-    })
+    return permissions.some((v) => {
+      return all_permission === v || v === permission;
+    });
   } else {
-    return false
+    return false;
   }
 }
 
 function authRole(role) {
   const super_admin = "admin";
-  const roles = store.getters && store.getters.roles
+  const roles = store.getters && store.getters.roles;
+  if (role && role.length > 0) {
+    return roles.some((v) => {
+      return super_admin === v || v === role;
+    });
+  } else {
+    return false;
+  }
+}
+function authRoles(role) {
+  const super_admin = "admin";
+  const roles = store.getters && store.getters.roles;
   if (role && role.length > 0) {
     return roles.some(v => {
       return super_admin === v || v === role
@@ -31,15 +42,15 @@
   },
   // 楠岃瘉鐢ㄦ埛鏄惁鍚湁鎸囧畾鏉冮檺锛屽彧闇�鍖呭惈鍏朵腑涓�涓�
   hasPermiOr(permissions) {
-    return permissions.some(item => {
-      return authPermission(item)
-    })
+    return permissions.some((item) => {
+      return authPermission(item);
+    });
   },
   // 楠岃瘉鐢ㄦ埛鏄惁鍚湁鎸囧畾鏉冮檺锛屽繀椤诲叏閮ㄦ嫢鏈�
   hasPermiAnd(permissions) {
-    return permissions.every(item => {
-      return authPermission(item)
-    })
+    return permissions.every((item) => {
+      return authPermission(item);
+    });
   },
   // 楠岃瘉鐢ㄦ埛鏄惁鍏峰鏌愯鑹�
   hasRole(role) {
@@ -47,14 +58,14 @@
   },
   // 楠岃瘉鐢ㄦ埛鏄惁鍚湁鎸囧畾瑙掕壊锛屽彧闇�鍖呭惈鍏朵腑涓�涓�
   hasRoleOr(roles) {
-    return roles.some(item => {
-      return authRole(item)
-    })
+    return roles.some((item) => {
+      return authRoles(item);
+    });
   },
   // 楠岃瘉鐢ㄦ埛鏄惁鍚湁鎸囧畾瑙掕壊锛屽繀椤诲叏閮ㄦ嫢鏈�
   hasRoleAnd(roles) {
-    return roles.every(item => {
-      return authRole(item)
-    })
-  }
-}
+    return roles.every((item) => {
+      return authRole(item);
+    });
+  },
+};
diff --git a/src/router/index.js b/src/router/index.js
index 8fe8951..b96f433 100644
--- a/src/router/index.js
+++ b/src/router/index.js
@@ -1,10 +1,10 @@
-import Vue from 'vue'
-import Router from 'vue-router'
+import Vue from "vue";
+import Router from "vue-router";
 
-Vue.use(Router)
+Vue.use(Router);
 
 /* Layout */
-import Layout from '@/layout'
+import Layout from "@/layout";
 
 /**
  * Note: 璺敱閰嶇疆椤�
@@ -31,182 +31,187 @@
 // 鍏叡璺敱
 export const constantRoutes = [
   {
-    path: '/redirect',
+    path: "/redirect",
     component: Layout,
     hidden: true,
     children: [
       {
-        path: '/redirect/:path(.*)',
-        component: () => import('@/views/redirect')
-      }
-    ]
+        path: "/redirect/:path(.*)",
+        component: () => import("@/views/redirect"),
+      },
+    ],
   },
   {
-    path: '/login',
-    component: () => import('@/views/login'),
-    hidden: true
-  },
-    {
-    path: '/loginSSO',
-    component: () => import('@/views/loginSSO'),
-    hidden: true
+    path: "/login",
+    component: () => import("@/views/login"),
+    hidden: true,
   },
   {
-    path: '/sf',
-    component: () => import('@/views/outsideChainnew'),
-    hidden: true
+    path: "/loginSSO",
+    component: () => import("@/views/loginSSO"),
+    hidden: true,
   },
   {
-    path: '/wt',
-    component: () => import('@/views/outsideChainwtnew'),
-    hidden: true
+    path: "/sf",
+    component: () => import("@/views/outsideChainnew"),
+    hidden: true,
   },
   {
-    path: '/xj',
-    component: () => import('@/views/outsideChainxjnew'),
-    hidden: true
+    path: "/wt",
+    component: () => import("@/views/outsideChainwtnew"),
+    hidden: true,
   },
   {
-    path: '/satisfaction',
-    component: () => import('@/views/satisfaction'),
-    hidden: true
+    path: "/xj",
+    component: () => import("@/views/outsideChainxjnew"),
+    hidden: true,
   },
   {
-    path: '/outsideChain',
-    component: () => import('@/views/outsideChain'),
-    hidden: true
+    path: "/satisfaction",
+    component: () => import("@/views/satisfaction"),
+    hidden: true,
   },
   {
-    path: '/outsideChainwt',
-    component: () => import('@/views/outsideChainwt'),
-    hidden: true
+    path: "/outsideChain",
+    component: () => import("@/views/outsideChain"),
+    hidden: true,
   },
   {
-    path: '/outsideChainxj',
-    component: () => import('@/views/outsideChainxj'),
-    hidden: true
+    path: "/outsideChainwt",
+    component: () => import("@/views/outsideChainwt"),
+    hidden: true,
   },
   {
-    path: '/previews',
-    component: () => import('@/views/previews'),
-    hidden: true
+    path: "/outsideChainxj",
+    component: () => import("@/views/outsideChainxj"),
+    hidden: true,
   },
   {
-    path: '/register',
-    component: () => import('@/views/register'),
-    hidden: true
+    path: "/previews",
+    component: () => import("@/views/previews"),
+    hidden: true,
   },
   {
-    path: '/404',
-    component: () => import('@/views/error/404'),
-    hidden: true
+    path: "/register",
+    component: () => import("@/views/register"),
+    hidden: true,
   },
   {
-    path: '/401',
-    component: () => import('@/views/error/401'),
-    hidden: true
+    path: "/404",
+    component: () => import("@/views/error/404"),
+    hidden: true,
   },
   {
-    path: '',
+    path: "/401",
+    component: () => import("@/views/error/401"),
+    hidden: true,
+  },
+  {
+    path: "",
     component: Layout,
-    redirect: 'index',
+    redirect: "index",
     children: [
       {
-        path: 'index',
-        component: () => import('@/views/index'),
-        name: 'Index',
-        meta: { title: '棣栭〉', icon: 'dashboard', affix: true }
-      }
-    ]
+        path: "index",
+        component: () => import("@/views/index"),
+        name: "Index",
+        meta: {
+          title: "棣栭〉",
+          icon: "dashboard",
+          affix: true,
+          roles: ["admin", "sysadmin"],
+        },
+      },
+    ],
   },
   {
-    path: '/user',
+    path: "/user",
     component: Layout,
     hidden: true,
-    redirect: 'noredirect',
+    redirect: "noredirect",
     children: [
       {
-        path: 'profile',
-        component: () => import('@/views/system/user/profile/index'),
-        name: 'Profile',
-        meta: { title: '涓汉涓績', icon: 'user' }
-      }
-    ]
-  }
-]
+        path: "profile",
+        component: () => import("@/views/system/user/profile/index"),
+        name: "Profile",
+        meta: { title: "涓汉涓績", icon: "user" },
+      },
+    ],
+  },
+];
 
 // 鍔ㄦ�佽矾鐢憋紝鍩轰簬鐢ㄦ埛鏉冮檺鍔ㄦ�佸幓鍔犺浇
 export const dynamicRoutes = [
   {
-    path: '/system/user-auth',
+    path: "/system/user-auth",
     component: Layout,
     hidden: true,
-    permissions: ['system:user:edit'],
+    permissions: ["system:user:edit"],
     children: [
       {
-        path: 'role/:userId(\\d+)',
-        component: () => import('@/views/system/user/authRole'),
-        name: 'AuthRole',
-        meta: { title: '鍒嗛厤瑙掕壊', activeMenu: '/system/user' }
-      }
-    ]
+        path: "role/:userId(\\d+)",
+        component: () => import("@/views/system/user/authRole"),
+        name: "AuthRole",
+        meta: { title: "鍒嗛厤瑙掕壊", activeMenu: "/system/user" },
+      },
+    ],
   },
   {
-    path: '/system/role-auth',
+    path: "/system/role-auth",
     component: Layout,
     hidden: true,
-    permissions: ['system:role:edit'],
+    permissions: ["system:role:edit"],
     children: [
       {
-        path: 'user/:roleId(\\d+)',
-        component: () => import('@/views/system/role/authUser'),
-        name: 'AuthUser',
-        meta: { title: '鍒嗛厤鐢ㄦ埛', activeMenu: '/system/role' }
-      }
-    ]
+        path: "user/:roleId(\\d+)",
+        component: () => import("@/views/system/role/authUser"),
+        name: "AuthUser",
+        meta: { title: "鍒嗛厤鐢ㄦ埛", activeMenu: "/system/role" },
+      },
+    ],
   },
   {
-    path: '/system/dict-data',
+    path: "/system/dict-data",
     component: Layout,
     hidden: true,
-    permissions: ['system:dict:list'],
+    permissions: ["system:dict:list"],
     children: [
       {
-        path: 'index/:dictId(\\d+)',
-        component: () => import('@/views/system/dict/data'),
-        name: 'Data',
-        meta: { title: '瀛楀吀鏁版嵁', activeMenu: '/system/dict' }
-      }
-    ]
+        path: "index/:dictId(\\d+)",
+        component: () => import("@/views/system/dict/data"),
+        name: "Data",
+        meta: { title: "瀛楀吀鏁版嵁", activeMenu: "/system/dict" },
+      },
+    ],
   },
   {
-    path: '/monitor/job-log',
+    path: "/monitor/job-log",
     component: Layout,
     hidden: true,
-    permissions: ['monitor:job:list'],
+    permissions: ["monitor:job:list"],
     children: [
       {
-        path: 'index/:jobId(\\d+)',
-        component: () => import('@/views/monitor/job/log'),
-        name: 'JobLog',
-        meta: { title: '璋冨害鏃ュ織', activeMenu: '/monitor/job' }
-      }
-    ]
+        path: "index/:jobId(\\d+)",
+        component: () => import("@/views/monitor/job/log"),
+        name: "JobLog",
+        meta: { title: "璋冨害鏃ュ織", activeMenu: "/monitor/job" },
+      },
+    ],
   },
   {
-    path: '/tool/gen-edit',
+    path: "/tool/gen-edit",
     component: Layout,
     hidden: true,
-    permissions: ['tool:gen:edit'],
+    permissions: ["tool:gen:edit"],
     children: [
       {
-        path: 'index/:tableId(\\d+)',
-        component: () => import('@/views/tool/gen/editTable'),
-        name: 'GenEdit',
-        meta: { title: '淇敼鐢熸垚閰嶇疆', activeMenu: '/tool/gen' }
-      }
-    ]
-  }/*,
+        path: "index/:tableId(\\d+)",
+        component: () => import("@/views/tool/gen/editTable"),
+        name: "GenEdit",
+        meta: { title: "淇敼鐢熸垚閰嶇疆", activeMenu: "/tool/gen" },
+      },
+    ],
+  } /*,
   {
     path: '/smartor/archive',
     component: Layout,
@@ -220,17 +225,17 @@
         meta: { title: '鎮h�呯淮鎶�', activeMenu: '/archive/add' }
       }
     ]
-  }*/
-]
+  }*/,
+];
 
 // 闃叉杩炵画鐐瑰嚮澶氭璺敱鎶ラ敊
 let routerPush = Router.prototype.push;
 Router.prototype.push = function push(location) {
-  return routerPush.call(this, location).catch(err => err)
-}
+  return routerPush.call(this, location).catch((err) => err);
+};
 
 export default new Router({
-  mode: 'history', // 鍘绘帀url涓殑#
+  mode: "history", // 鍘绘帀url涓殑#
   scrollBehavior: () => ({ y: 0 }),
-  routes: constantRoutes
-})
+  routes: constantRoutes,
+});
diff --git a/src/store/getters.js b/src/store/getters.js
index c89a97b..73a18ea 100644
--- a/src/store/getters.js
+++ b/src/store/getters.js
@@ -15,6 +15,7 @@
   permissions: (state) => state.user.permissions,
   belongWards: (state) => state.user.belongWards,
   belongDepts: (state) => state.user.belongDepts,
+  satisfactionCategories: (state) => state.user.satisfactionCategories,
   hisUserId: (state) => state.user.hisUserId,
   permission_routes: (state) => state.permission.routes,
   topbarRouters: (state) => state.permission.topbarRouters,
diff --git a/src/store/modules/permission.js b/src/store/modules/permission.js
index 90e3782..5c07e5a 100644
--- a/src/store/modules/permission.js
+++ b/src/store/modules/permission.js
@@ -1,11 +1,10 @@
-import auth from '@/plugins/auth'
-import router, { constantRoutes, dynamicRoutes } from '@/router'
-import { getRouters } from '@/api/menu'
-import Layout from '@/layout/index'
-import ParentView from '@/components/ParentView'
-import InnerLink from '@/layout/components/InnerLink'
+import auth from "@/plugins/auth";
+import router, { constantRoutes, dynamicRoutes } from "@/router";
+import { getRouters } from "@/api/menu";
+import Layout from "@/layout/index";
+import ParentView from "@/components/ParentView";
+import InnerLink from "@/layout/components/InnerLink";
 import store from "@/store";
-
 
 const permission = {
   state: {
@@ -13,144 +12,165 @@
     addRoutes: [],
     defaultRoutes: [],
     topbarRouters: [],
-    sidebarRouters: []
+    sidebarRouters: [],
   },
   mutations: {
     SET_ROUTES: (state, routes) => {
-      state.addRoutes = routes
-      state.routes = constantRoutes.concat(routes)
+      state.addRoutes = routes;
+      state.routes = constantRoutes.concat(routes);
     },
     SET_DEFAULT_ROUTES: (state, routes) => {
-      state.defaultRoutes = constantRoutes.concat(routes)
+      state.defaultRoutes = constantRoutes.concat(routes);
     },
     SET_TOPBAR_ROUTES: (state, routes) => {
-      state.topbarRouters = routes
+      state.topbarRouters = routes;
     },
     SET_SIDEBAR_ROUTERS: (state, routes) => {
-      state.sidebarRouters = routes
+      state.sidebarRouters = routes;
     },
   },
   actions: {
     // 鐢熸垚璺敱
     GenerateRoutes({ commit }) {
-      return new Promise(resolve => {
+      return new Promise((resolve) => {
         // 鍚戝悗绔姹傝矾鐢辨暟鎹�
-        getRouters().then(res => {
-          const sdata = JSON.parse(JSON.stringify(res.data))
-          const rdata = JSON.parse(JSON.stringify(res.data))
-          const sidebarRoutes = filterAsyncRouter(sdata)
-          const rewriteRoutes = filterAsyncRouter(rdata, false, true)
-          const asyncRoutes = filterDynamicRoutes(dynamicRoutes);
-          rewriteRoutes.push({ path: '*', redirect: '/404', hidden: true })
-          router.addRoutes(asyncRoutes);
-          commit('SET_ROUTES', rewriteRoutes)
-          commit('SET_SIDEBAR_ROUTERS', constantRoutes.concat(sidebarRoutes))
-          commit('SET_DEFAULT_ROUTES', sidebarRoutes)
-          commit('SET_TOPBAR_ROUTES', sidebarRoutes)
-          resolve(rewriteRoutes)
-          console.log(res.data,'璺敱鏁版嵁');
-          const result = res.data.find(item => item.name == "Followvisit");
-          Processrouting(result)
+        getRouters().then((res) => {
+          const sdata = JSON.parse(JSON.stringify(res.data));
+          const rdata = JSON.parse(JSON.stringify(res.data));
+          const sidebarRoutes = filterAsyncRouter(sdata);
+          const rewriteRoutes = filterAsyncRouter(rdata, false, true);
+          // 鍏抽敭淇敼锛氬闈欐�佽矾鐢变篃杩涜鏉冮檺杩囨护
+          // console.log(constantRoutes, "闈�");
+          // console.log(dynamicRoutes, "鍔�");
 
-        })
-      })
-    }
-  }
-}
-function Processrouting(result){
-  const arrf=[];
-  const arr=store.getters.Serviceauthority;
-  console.log(result,'result');
-  console.log(arr,'arr');
-  result.children.forEach(objA => {
-    arr.forEach(objB => {
+          const filteredConstantRoutes = filterDynamicRoutes(constantRoutes);
+          const asyncRoutes = filterDynamicRoutes(dynamicRoutes);
+
+          rewriteRoutes.push({ path: "*", redirect: "/404", hidden: true });
+
+          // 娣诲姞杩囨护鍚庣殑璺敱
+          router.addRoutes(filteredConstantRoutes);
+          router.addRoutes(asyncRoutes);
+
+          // 鎻愪氦鍒皊tore鏃朵篃浣跨敤杩囨护鍚庣殑璺敱
+          commit("SET_ROUTES", rewriteRoutes);
+          commit(
+            "SET_SIDEBAR_ROUTERS",
+            filteredConstantRoutes.concat(sidebarRoutes)
+          );
+          commit("SET_DEFAULT_ROUTES", sidebarRoutes);
+          commit("SET_TOPBAR_ROUTES", sidebarRoutes);
+          resolve(rewriteRoutes);
+          console.log(res.data, "璺敱鏁版嵁");
+          const result = res.data.find((item) => item.name == "Followvisit");
+          Processrouting(result);
+        });
+      });
+    },
+  },
+};
+function Processrouting(result) {
+  const arrf = [];
+  const arr = store.getters.Serviceauthority;
+  console.log(result, "result");
+  console.log(arr, "arr");
+  result.children.forEach((objA) => {
+    arr.forEach((objB) => {
       if (objA.meta.title === objB.label) {
         arrf.push(objB);
       }
     });
   });
-  console.log(arrf,'arrf');
-  store.commit('SET_Serviceauthority', arrf);
-
-
+  console.log(arrf, "arrf");
+  store.commit("SET_Serviceauthority", arrf);
 }
 
 // 閬嶅巻鍚庡彴浼犳潵鐨勮矾鐢卞瓧绗︿覆锛岃浆鎹负缁勪欢瀵硅薄
 function filterAsyncRouter(asyncRouterMap, lastRouter = false, type = false) {
-  return asyncRouterMap.filter(route => {
+  return asyncRouterMap.filter((route) => {
     if (type && route.children) {
-      route.children = filterChildren(route.children)
+      route.children = filterChildren(route.children);
     }
     if (route.component) {
       // Layout ParentView 缁勪欢鐗规畩澶勭悊
-      if (route.component === 'Layout') {
-        route.component = Layout
-      } else if (route.component === 'ParentView') {
-        route.component = ParentView
-      } else if (route.component === 'InnerLink') {
-        route.component = InnerLink
+      if (route.component === "Layout") {
+        route.component = Layout;
+      } else if (route.component === "ParentView") {
+        route.component = ParentView;
+      } else if (route.component === "InnerLink") {
+        route.component = InnerLink;
       } else {
-        route.component = loadView(route.component)
+        route.component = loadView(route.component);
       }
     }
     if (route.children != null && route.children && route.children.length) {
-      route.children = filterAsyncRouter(route.children, route, type)
+      route.children = filterAsyncRouter(route.children, route, type);
     } else {
-      delete route['children']
-      delete route['redirect']
+      delete route["children"];
+      delete route["redirect"];
     }
-    return true
-  })
+    return true;
+  });
 }
 
 function filterChildren(childrenMap, lastRouter = false) {
-  var children = []
+  var children = [];
   childrenMap.forEach((el, index) => {
     if (el.children && el.children.length) {
-      if (el.component === 'ParentView' && !lastRouter) {
-        el.children.forEach(c => {
-          c.path = el.path + '/' + c.path
+      if (el.component === "ParentView" && !lastRouter) {
+        el.children.forEach((c) => {
+          c.path = el.path + "/" + c.path;
           if (c.children && c.children.length) {
-            children = children.concat(filterChildren(c.children, c))
-            return
+            children = children.concat(filterChildren(c.children, c));
+            return;
           }
-          children.push(c)
-        })
-        return
+          children.push(c);
+        });
+        return;
       }
     }
     if (lastRouter) {
-      el.path = lastRouter.path + '/' + el.path
+      el.path = lastRouter.path + "/" + el.path;
     }
-    children = children.concat(el)
-  })
-  return children
+    children = children.concat(el);
+  });
+  return children;
 }
 
 // 鍔ㄦ�佽矾鐢遍亶鍘嗭紝楠岃瘉鏄惁鍏峰鏉冮檺
 export function filterDynamicRoutes(routes) {
-  const res = []
-  routes.forEach(route => {
+  const res = [];
+  routes.forEach((route) => {
+    // 棣栧厛妫�鏌ユ潈闄愬瓧绗︿覆 (permissions)
     if (route.permissions) {
       if (auth.hasPermiOr(route.permissions)) {
-        res.push(route)
-      }
-    } else if (route.roles) {
-      if (auth.hasRoleOr(route.roles)) {
-        res.push(route)
+        res.push(route);
       }
     }
-  })
-  return res
+    // 鐒跺悗妫�鏌ヨ鑹叉潈闄� (roles) - 杩欐槸鎮ㄩ渶瑕侀噸鐐瑰叧娉ㄧ殑閮ㄥ垎
+    else if (route.children) {
+      if (
+        route.children[0]?.meta?.roles &&
+        auth.hasRoleOr(route.children[0].meta.roles)
+      ) {
+        res.push(route);
+      }
+    }
+    // 瀵逛簬娌℃湁璁剧疆鏉冮檺鐨勮矾鐢憋紝榛樿鍏佽璁块棶
+    else {
+      res.push(route);
+    }
+  });
+  return res;
 }
 
 export const loadView = (view) => {
-  if (process.env.NODE_ENV === 'development') {
-    return (resolve) => require([`@/views/${view}`], resolve)
+  if (process.env.NODE_ENV === "development") {
+    return (resolve) => require([`@/views/${view}`], resolve);
   } else {
     // 浣跨敤 import 瀹炵幇鐢熶骇鐜鐨勮矾鐢辨噿鍔犺浇
-    return () => import(`@/views/${view}`)
+    return () => import(`@/views/${view}`);
   }
-}
+};
 
-export default permission
+export default permission;
diff --git a/src/store/modules/user.js b/src/store/modules/user.js
index 19ad61d..98f1b61 100644
--- a/src/store/modules/user.js
+++ b/src/store/modules/user.js
@@ -13,6 +13,7 @@
     belongDepts: [],
     roles: [],
     permissions: [],
+    satisfactionCategories:{},
     // 鏈嶅姟绫诲瀷
     Serviceauthority: [
       {
@@ -112,6 +113,9 @@
     SET_hisUserId: (state, hisUserId) => {
       state.hisUserId = hisUserId;
     },
+        SET_satisfactionCategories: (state, satisfactionCategories) => {
+      state.satisfactionCategories = satisfactionCategories;
+    },
     SET_leaveldeptcodes: (state, belongDepts) => {
       state.belongDepts = belongDepts;
     },
@@ -125,10 +129,13 @@
       const username = userInfo.username.trim();
       const password = userInfo.password;
       const code = userInfo.code;
+      const campusid = userInfo.campusid;
 
       const orgid = userInfo.orgid;
+      console.log(orgid, campusid, "88");
+
       return new Promise((resolve, reject) => {
-        login(username, password, code, orgid)
+        login(username, password, code, orgid, campusid)
           .then((res) => {
             setToken(res.token);
             commit("SET_TOKEN", res.token);
@@ -171,13 +178,13 @@
               localStorage.setItem("YongHuXM", "LQZYY");
             } else if (orgid == "47243006833112611A2101") {
               localStorage.setItem("orgname", "搴嗗厓鍘夸腑鍖诲尰闄�");
-              localStorage.setItem("ZuHuID", "1429338802177000004");
+              localStorage.setItem("ZuHuID", "1429338802177000005");
               localStorage.setItem("deptCode", "");
               localStorage.setItem("YongHuID", "1462585966286868480");
               localStorage.setItem("YongHuXM", "QYZYY");
             } else if (orgid == "47234002X33112111A2101") {
               localStorage.setItem("orgname", "闈掔敯鍘夸腑鍖诲尰闄�");
-              localStorage.setItem("ZuHuID", "1429338802177000005");
+              localStorage.setItem("ZuHuID", "1429338802177000004");
               localStorage.setItem("deptCode", "");
               localStorage.setItem("YongHuID", "1462614919332499458");
               localStorage.setItem("YongHuXM", "QTHCZYY");
@@ -190,6 +197,42 @@
             } else if (orgid == "20001001") {
               localStorage.setItem("orgname", "鐪佺珛鍚屽痉缈犺嫅闄㈠尯");
               localStorage.setItem("ZuHuID", "");
+              localStorage.setItem("deptCode", "");
+              localStorage.setItem("YongHuID", "");
+              localStorage.setItem("YongHuXM", "");
+            } else if (orgid == "47252003933112411A2101") {
+              localStorage.setItem("orgname", "鏉鹃槼鍘夸腑鍖诲尰闄�");
+              localStorage.setItem("ZuHuID", "1429338802177000008");
+              localStorage.setItem("deptCode", "");
+              localStorage.setItem("YongHuID", "1497875635748474880");
+              localStorage.setItem("YongHuXM", "SYZYY");
+            } else if (orgid == "47231077933110211A1101") {
+              localStorage.setItem("orgname", "鑾查兘鍖轰汉姘戝尰闄�");
+              localStorage.setItem("ZuHuID", "1429338802177000011");
+              localStorage.setItem("deptCode", "01020901");
+              localStorage.setItem("YongHuID", "1512710152715767808");
+              localStorage.setItem("YongHuXM", "LDRMYY");
+            } else if (orgid == "1" && campusid == 1) {
+              localStorage.setItem("orgname", "绗竴浜烘皯鍖婚櫌婀栨花闄㈠尯");
+              localStorage.setItem("ZuHuID", "");
+              localStorage.setItem("deptCode", "");
+              localStorage.setItem("YongHuID", "");
+              localStorage.setItem("YongHuXM", "");
+            } else if (orgid == "1" && campusid == 2) {
+              localStorage.setItem("orgname", "绗竴浜烘皯鍖婚櫌鍚村北闄㈠尯");
+              localStorage.setItem("ZuHuID", "");
+              localStorage.setItem("deptCode", "");
+              localStorage.setItem("YongHuID", "");
+              localStorage.setItem("YongHuXM", "");
+            } else if (orgid == "47246116333112211A1001") {
+              localStorage.setItem("orgname", "缂欎簯鍘夸汉姘戝尰闄�");
+              localStorage.setItem("ZuHuID", "1429338802177000010");
+              localStorage.setItem("deptCode", "");
+              localStorage.setItem("YongHuID", "");
+              localStorage.setItem("YongHuXM", "");
+            } else if (orgid == "47226079133110211G1001") {
+              localStorage.setItem("orgname", "涓芥按甯傚骞间繚鍋ラ櫌");
+              localStorage.setItem("ZuHuID", "1429338802177000014");
               localStorage.setItem("deptCode", "");
               localStorage.setItem("YongHuID", "");
               localStorage.setItem("YongHuXM", "");
@@ -223,6 +266,15 @@
             commit("SET_nickNAME", user.nickName);
             commit("SET_Id", user.userId);
             commit("SET_hisUserId", user.hisUserId);
+            commit("SET_satisfactionCategories", user.satisfactionCategories);
+
+            // if (user.userName == "admin") {
+            //   commit("SET_leaveldeptcodes", []);
+            //   commit("SET_leavehospitaldistrictcodes", []);
+            // } else {
+            //   commit("SET_leavehospitaldistrictcodes", user.belongWards);
+            //   commit("SET_leaveldeptcodes", user.belongDepts);
+            // }
             commit("SET_leavehospitaldistrictcodes", user.belongWards);
             commit("SET_leaveldeptcodes", user.belongDepts);
             commit("SET_AVATAR", avatar);
diff --git a/src/utils/request.js b/src/utils/request.js
index b07e281..f8c552b 100644
--- a/src/utils/request.js
+++ b/src/utils/request.js
@@ -110,7 +110,9 @@
           }
         )
           .then(() => {
-          this.$router.replace("/login");
+            console.log('閫夋嫨閲嶆柊鐧诲綍');
+
+            this.$router.replace("/login");
           })
           .catch(() => {
             isRelogin.show = false;
diff --git a/src/utils/sipService.js b/src/utils/sipService.js
index a8ce592..5641a20 100644
--- a/src/utils/sipService.js
+++ b/src/utils/sipService.js
@@ -1,5 +1,30 @@
 import JsSIP from "jssip";
-
+import { Notification, MessageBox, Message, Loading } from "element-ui";
+// 鍖婚櫌鏈烘瀯涓嶴IP鏈嶅姟鍣ㄦ槧灏勯厤缃�
+// 鍏徃鏈嶅姟鍣�192.168.100.6
+const HOSPITAL_CONFIG = {
+  涓芥按甯備腑鍖婚櫌: {
+    wsUrl: "wss://192.168.10.124:7443",
+    domain: "192.168.10.124",
+  },
+  榫欐硥甯備汉姘戝尰闄�: {
+    wsUrl: "wss://10.10.0.220:7443",
+    domain: "10.10.0.220",
+  },
+   绗竴浜烘皯鍖婚櫌婀栨花闄㈠尯: {
+    wsUrl: "wss://192.169.129.198:7443",
+    domain: "192.169.129.198",
+  },
+  绗竴浜烘皯鍖婚櫌鍚村北闄㈠尯: {
+    wsUrl: "wss://192.169.129.198:7443",
+    domain: "192.169.129.198",
+  },
+  // 鍙互缁х画娣诲姞鍏朵粬鍖婚櫌閰嶇疆
+  default: {
+    wsUrl: "wss://192.168.10.124:7443",
+    domain: "192.168.10.124",
+  },
+};
 class SipService {
   constructor() {
     this.ua = null;
@@ -9,17 +34,40 @@
     this.onIncomingCall = null;
     this.isRegistered = false; // 鏂板娉ㄥ唽鐘舵�佹爣蹇�
     this.registrationTime = null; // 鏂板娉ㄥ唽鎴愬姛鏃堕棿鎴�
+    this.currentConfig = null; // 瀛樺偍褰撳墠閰嶇疆
   }
-
-  init(config) {
+  // 鑾峰彇鍖婚櫌閰嶇疆鏂规硶
+  getHospitalConfig() {
+    const orgName = localStorage.getItem("orgname");
+    return HOSPITAL_CONFIG[orgName] || HOSPITAL_CONFIG.default;
+  }
+  init(baseConfig) {
     try {
-      this.updateStatus("connecting", "杩炴帴涓�;...");
+      // 鑾峰彇鏈烘瀯鍚嶇О锛屽鏋滄病鏈変紶鍏ュ垯浠巐ocalStorage璇诲彇
+      const orgName = baseConfig.orgName || localStorage.getItem("orgname");
+
+      // 鏍规嵁鏈烘瀯鍚嶇О鑾峰彇瀵瑰簲鐨勬湇鍔″櫒閰嶇疆
+      const hospitalConfig = this.getHospitalConfig(orgName);
+      console.log(hospitalConfig, "88");
+
+      // 鍚堝苟閰嶇疆
+      this.currentConfig = {
+        ...baseConfig,
+        ...hospitalConfig,
+      };
+
+      console.log(
+        `褰撳墠鏈烘瀯: ${orgName}, 浣跨敤鏈嶅姟鍣�: ${this.currentConfig.domain}`
+      );
+
+      this.updateStatus("connecting", "杩炴帴涓�...");
+      console.log(baseConfig.sipUri, "baseConfig.sipUri");
 
       this.ua = new JsSIP.UA({
-        sockets: [new JsSIP.WebSocketInterface(config.wsUrl)],
-        uri: config.sipUri,
-        password: config.password,
-        display_name: config.displayName,
+        sockets: [new JsSIP.WebSocketInterface(this.currentConfig.wsUrl)],
+        uri: baseConfig.sipUri, // 杩欓噷浣跨敤鍩虹鐨剆ipUri锛宒omain閮ㄥ垎浼氳鍔ㄦ�佹浛鎹�
+        password: baseConfig.password,
+        display_name: baseConfig.displayName,
         iceServers: [],
         register: true,
         sessionExpires: 1800,
@@ -77,7 +125,9 @@
       const remaining = minDelay - timeSinceRegistration;
       return {
         canCall: false,
-        reason: `娉ㄥ唽鎴愬姛锛岃绛夊緟 ${Math.ceil(remaining / 1000)} 绉掑悗鍐嶅懠鍙玚,
+        reason: `娉ㄥ唽鎴愬姛锛岃祫婧愬姞杞戒腑璇风瓑寰� ${Math.ceil(
+          remaining / 1000
+        )} 绉掑悗鍐嶅懠鍙玚,
       };
     }
 
@@ -86,6 +136,7 @@
   makeCall(targetNumber) {
     const { canCall, reason } = this.canMakeCall();
     if (!canCall) {
+      Message.error(reason);
       return Promise.reject(new Error(reason));
     }
     return new Promise((resolve, reject) => {
@@ -97,7 +148,8 @@
         if (!this.ua.isRegistered()) {
           throw new Error("SIP鏈敞鍐岋紝鏃犳硶鍛煎彨");
         }
-
+        const targetUri = `sip:${targetNumber}@${this.currentConfig.domain}`;
+        console.log(`鍛煎彨鐩爣: ${targetUri}`);
         const options = {
           sessionTimers: true, // 鍚敤浼氳瘽璁℃椂鍣�
           sessionTimersExpires: 150,
@@ -120,10 +172,7 @@
           },
         };
 
-        this.currentSession = this.ua.call(
-          `sip:${targetNumber}@192.168.10.124`,
-          options
-        );
+        this.currentSession = this.ua.call(targetUri, options);
 
         this.setupPeerConnection(this.currentSession);
         this.setupAudio(this.currentSession);
@@ -150,31 +199,181 @@
     });
   }
 
+  //   normalizeSDP(offer) {
+  //     let sdp = offer.sdp;
+  //  console.log("鍘熷SDP:", sdp); // 璋冭瘯鐢紝鎹曡幏鍘熷SDP
+  //     // 鏍囧噯鍖朣DP
+  //     sdp = sdp.replace(/c=IN IP4.*\r\n/, "c=IN IP4 0.0.0.0\r\n");
+  //     sdp = sdp.replace(
+  //       /m=audio \d+.*\r\n/,
+  //       "m=audio 9 UDP/TLS/RTP/SAVPF 0 8\r\n"
+  //     );
+
+  //     // 纭繚鍖呭惈鍩烘湰缂栬В鐮佸櫒
+  //     if (!sdp.includes("PCMU/8000")) sdp += "a=rtpmap:0 PCMU/8000\r\n";
+  //     if (!sdp.includes("PCMA/8000")) sdp += "a=rtpmap:8 PCMA/8000\r\n";
+
+  //     // 娣诲姞蹇呰灞炴��
+  //     sdp += "a=rtcp-mux\r\n";
+  //     sdp += "a=sendrecv\r\n";
+
+  //     console.log("鏍囧噯鍖栧悗鐨凷DP:", sdp);
+  //     return new RTCSessionDescription({
+  //       type: offer.type,
+  //       sdp: sdp,
+  //     });
+  //   }
+  // 鍦� SipService 绫讳腑鏂板鏂规硶锛岀敤浜庤幏鍙栭拡瀵圭壒瀹氭湇鍔″櫒鐨凷DP澶勭悊绛栫暐
+  getSDPNormalizationStrategy(orgName) {
+    const strategies = {
+      榫欐硥甯備汉姘戝尰闄�: "conservative", // 淇濆畧绛栫暐锛氭渶灏忓寲淇敼锛屼紭鍏堝吋瀹�
+      涓芥按甯備腑鍖婚櫌: "aggressive", // 婵�杩涚瓥鐣ワ細淇濇寔鍘熸湁寮烘爣鍑嗗寲閫昏緫
+      // 鍙互涓哄叾浠栨満鏋勬坊鍔犳洿澶氱瓥鐣�
+    };
+    return strategies[orgName] || "moderate"; // 榛樿绛栫暐
+  }
+
+  /**
+   * 鏍囧噯鍖朣DP Offer - 淇榫欐硥甯備汉姘戝尰闄�488閿欒
+   * 鏍稿績鎬濊矾锛氫粠鈥滃己鍒惰鐩栤�濇敼涓衡�滄櫤鑳戒慨琛モ�濓紝閽堝涓嶅悓鏈嶅姟鍣ㄤ娇鐢ㄥ樊寮傚寲绛栫暐
+   */
   normalizeSDP(offer) {
+    const orgName = localStorage.getItem("orgname");
+    const strategy = this.getSDPNormalizationStrategy(orgName);
     let sdp = offer.sdp;
 
-    // 鏍囧噯鍖朣DP
-    sdp = sdp.replace(/c=IN IP4.*\r\n/, "c=IN IP4 0.0.0.0\r\n");
-    sdp = sdp.replace(
-      /m=audio \d+.*\r\n/,
-      "m=audio 9 UDP/TLS/RTP/SAVPF 0 8\r\n"
-    );
+    console.log(`[SDP鏍囧噯鍖朷 鏈烘瀯: ${orgName}, 绛栫暐: ${strategy}`);
+    console.log("[SDP鏍囧噯鍖朷 鍘熷SDP:", sdp);
 
-    // 纭繚鍖呭惈鍩烘湰缂栬В鐮佸櫒
-    if (!sdp.includes("PCMU/8000")) sdp += "a=rtpmap:0 PCMU/8000\r\n";
-    if (!sdp.includes("PCMA/8000")) sdp += "a=rtpmap:8 PCMA/8000\r\n";
+    if (strategy === "conservative") {
+      // ==================== 淇濆畧绛栫暐锛氶拡瀵归緳娉夊競浜烘皯鍖婚櫌绛変弗鏍兼湇鍔″櫒 ====================
+      // 鍘熷垯锛氶櫎闈炲繀瑕侊紝鍚﹀垯涓嶄慨鏀瑰師鏈塖DP缁撴瀯锛屼粎娣诲姞缂哄け鐨勫叧閿睘鎬�
 
-    // 娣诲姞蹇呰灞炴��
-    sdp += "a=rtcp-mux\r\n";
-    sdp += "a=sendrecv\r\n";
+      // 1. 璋ㄦ厧澶勭悊杩炴帴鍦板潃锛氫粎鍦ㄥ湴鍧�鏄槑鏄惧唴缃戝湴鍧�鏃舵墠淇敼
+      const privateIPRegex =
+        /c=IN IP4 (192\.168|10\.|172\.(1[6-9]|2[0-9]|3[0-1]))/;
+      if (privateIPRegex.test(sdp)) {
+        sdp = sdp.replace(/c=IN IP4.*\r\n/, "c=IN IP4 0.0.0.0\r\n");
+        console.log("[SDP鏍囧噯鍖朷 宸蹭慨鏀硅繛鎺ュ湴鍧�涓� 0.0.0.0");
+      }
 
-    console.log("鏍囧噯鍖栧悗鐨凷DP:", sdp);
+      // 2. 淇濇寔濯掍綋琛屽師鏍凤紝涓嶅己鍒朵慨鏀圭鍙e拰鍗忚
+      // sdp = sdp.replace(/m=audio \d+.*\r\n/, "m=audio 9 UDP/TLS/RTP/SAVPF 0 8\r\n");
+
+      // 3. 鏅鸿兘娣诲姞鍩虹缂栬В鐮佸櫒鏄犲皠锛堜粎鍦ㄧ己澶辨椂娣诲姞锛�
+      const codecMappings = [
+        { pt: 0, name: "PCMU/8000" },
+        { pt: 8, name: "PCMA/8000" },
+      ];
+
+      codecMappings.forEach((codec) => {
+        const rtpmapPattern = `a=rtpmap:${codec.pt} ${codec.name}`;
+        const payloadPattern = ` ${codec.pt} `;
+
+        // 鍙湁褰揝DP涓寘鍚璐熻浇绫诲瀷浣嗙己灏戣缁嗘槧灏勬椂鎵嶆坊鍔�
+        if (sdp.includes(payloadPattern) && !sdp.includes(rtpmapPattern)) {
+          sdp += `${rtpmapPattern}\r\n`;
+          console.log(`[SDP鏍囧噯鍖朷 宸叉坊鍔犵紪瑙g爜鍣ㄦ槧灏�: ${rtpmapPattern}`);
+        }
+      });
+
+      // 4. 鏉′欢鎬ф坊鍔犲繀瑕佸睘鎬э紙閬垮厤閲嶅锛�
+      const essentialAttributes = [
+        { attr: "a=rtcp-mux", desc: "RTCP澶嶇敤" },
+        { attr: "a=sendrecv", desc: "鍙屽悜濯掍綋娴�" },
+      ];
+
+      essentialAttributes.forEach((item) => {
+        if (!sdp.includes(item.attr)) {
+          sdp += `${item.attr}\r\n`;
+          console.log(`[SDP鏍囧噯鍖朷 宸叉坊鍔犲睘鎬�: ${item.desc}`);
+        }
+      });
+    } else if (strategy === "aggressive") {
+      // ==================== 婵�杩涚瓥鐣ワ細淇濇寔鍘熸湁閫昏緫 ====================
+      sdp = sdp.replace(/c=IN IP4.*\r\n/, "c=IN IP4 0.0.0.0\r\n");
+      sdp = sdp.replace(
+        /m=audio \d+.*\r\n/,
+        "m=audio 9 UDP/TLS/RTP/SAVPF 0 8\r\n"
+      );
+
+      // 纭繚鍖呭惈鍩虹缂栬В鐮佸櫒
+      if (!sdp.includes("PCMU/8000")) sdp += "a=rtpmap:0 PCMU/8000\r\n";
+      if (!sdp.includes("PCMA/8000")) sdp += "a=rtpmap:8 PCMA/8000\r\n";
+
+      // 娣诲姞閫氱敤灞炴��
+      sdp += "a=rtcp-mux\r\n";
+      sdp += "a=sendrecv\r\n";
+    } else {
+      // ==================== 榛樿绛栫暐锛氬钩琛℃柟妗� ====================
+      // 閫傚害淇敼锛屽吋椤惧吋瀹规�у拰鍔熻兘鎬�
+      sdp = sdp.replace(/c=IN IP4.*\r\n/, "c=IN IP4 0.0.0.0\r\n");
+
+      // 浠呭湪濯掍綋琛屾牸寮忔槑鏄惧紓甯告椂淇敼
+      if (!sdp.match(/m=audio \d+ RTP\/AVP/)) {
+        sdp = sdp.replace(
+          /m=audio \d+.*\r\n/,
+          "m=audio 9 UDP/TLS/RTP/SAVPF 0 8\r\n"
+        );
+      }
+
+      // 鏅鸿兘娣诲姞缂哄け鐨勫睘鎬�
+      if (!sdp.includes("a=rtcp-mux")) sdp += "a=rtcp-mux\r\n";
+      if (!sdp.includes("a=sendrecv")) sdp += "a=sendrecv\r\n";
+    }
+
+    console.log("[SDP鏍囧噯鍖朷 鏍囧噯鍖栧悗SDP:", sdp);
     return new RTCSessionDescription({
       type: offer.type,
       sdp: sdp,
     });
   }
 
+  /**
+   * 澧炲己鐨凷DP璋冭瘯鏂规硶 - 鐢ㄤ簬瀵规瘮鍒嗘瀽
+   */
+  debugSDPComparison(originalOffer, normalizedOffer, context) {
+    console.group(`[SDP璋冭瘯] ${context}`);
+    console.log(
+      "鍘熷SDP濯掍綋琛�:",
+      originalOffer.sdp.match(/m=audio.*\r\n/)?.[0] || "鏈壘鍒�"
+    );
+    console.log(
+      "鏍囧噯鍖栧悗濯掍綋琛�:",
+      normalizedOffer.sdp.match(/m=audio.*\r\n/)?.[0] || "鏈壘鍒�"
+    );
+    console.log(
+      "鍘熷缂栬В鐮佸櫒鍒楄〃:",
+      originalOffer.sdp.match(/a=rtpmap:\d+.*\r\n/g) || []
+    );
+    console.log(
+      "鏍囧噯鍖栧悗缂栬В鐮佸櫒鍒楄〃:",
+      normalizedOffer.sdp.match(/a=rtpmap:\d+.*\r\n/g) || []
+    );
+    console.groupEnd();
+  }
+
+  // 鍦� setupPeerConnection 鏂规硶涓泦鎴愯皟璇曞姛鑳�
+  setupPeerConnection(session) {
+    session.on("peerconnection", (pc) => {
+      const originalCreateOffer = pc.createOffer.bind(pc);
+
+      pc.createOffer = async (offerOptions) => {
+        try {
+          const offer = await originalCreateOffer(offerOptions);
+          const normalizedOffer = this.normalizeSDP(offer);
+
+          // 璋冭瘯淇℃伅杈撳嚭
+          this.debugSDPComparison(offer, normalizedOffer, "Offer鍒涘缓闃舵");
+
+          return normalizedOffer;
+        } catch (error) {
+          console.error("鍒涘缓Offer澶辫触:", error);
+          throw error;
+        }
+      };
+    });
+  }
   handleCallFailure(e, reject) {
     if (e.response?.status_code === 422) {
       const serverMinSE = e.response.headers["Min-SE"]?.[0]?.raw || "鏈煡";
diff --git a/src/views/Satisfaction/configurationmyd/batch.vue b/src/views/Satisfaction/configurationmyd/batch.vue
new file mode 100644
index 0000000..10d6619
--- /dev/null
+++ b/src/views/Satisfaction/configurationmyd/batch.vue
@@ -0,0 +1,922 @@
+<template>
+  <div class="batch-process">
+    <!-- 椤甸潰鏍囬 -->
+    <div class="page-header">
+      <div class="header-content">
+        <h2 class="page-title">寮傚父鎵归噺澶勭悊</h2>
+        <p class="page-description">鎵归噺澶勭悊閫変腑鐨勫紓甯稿弽棣�</p>
+        <div class="header-actions">
+          <el-button
+            type="primary"
+            icon="el-icon-check"
+            @click="handleBatchSubmit"
+            :loading="batchProcessing"
+          >
+            鎵归噺鎻愪氦澶勭悊
+          </el-button>
+          <el-button type="warning" icon="el-icon-back" @click="handleGoBack">
+            杩斿洖寮傚父鍒楄〃
+          </el-button>
+        </div>
+      </div>
+    </div>
+
+    <!-- 寮傚父鍒楄〃 -->
+    <div class="list-section">
+      <el-card shadow="never">
+        <div class="filter-section">
+          <el-form
+            :model="filterParams"
+            :inline="true"
+            size="medium"
+            class="filter-form"
+          >
+            <el-form-item label="璐熻矗绉戝">
+              <el-select
+                v-model="filterParams.deptId"
+                placeholder="璇烽�夋嫨绉戝"
+                clearable
+                style="width: 200px"
+              >
+                <el-option
+                  v-for="dept in deptList"
+                  :key="dept.id"
+                  :label="dept.name"
+                  :value="dept.id"
+                />
+              </el-select>
+            </el-form-item>
+            <el-form-item label="澶勭悊鐘舵��">
+              <el-select
+                v-model="filterParams.status"
+                placeholder="璇烽�夋嫨鐘舵��"
+                clearable
+                style="width: 200px"
+              >
+                <el-option label="寰呭鐞�" :value="0" />
+                <el-option label="澶勭悊涓�" :value="1" />
+                <el-option label="宸插鐞�" :value="2" />
+              </el-select>
+            </el-form-item>
+            <el-form-item>
+              <el-button
+                type="primary"
+                icon="el-icon-search"
+                @click="handleFilter"
+              >
+                绛涢��
+              </el-button>
+              <el-button icon="el-icon-refresh" @click="handleResetFilter">
+                閲嶇疆
+              </el-button>
+            </el-form-item>
+          </el-form>
+        </div>
+
+        <el-table
+          v-loading="loading"
+          :data="exceptionList"
+          :border="true"
+          style="width: 100%"
+          @selection-change="handleSelectionChange"
+          class="exception-table"
+        >
+          <el-table-column type="selection" width="55" align="center" />
+
+          <el-table-column
+            label="搴忓彿"
+            type="index"
+            width="60"
+            align="center"
+          />
+
+          <el-table-column
+            label="璐熻矗绉戝"
+            prop="responsibilityDept"
+            width="120"
+            align="center"
+          >
+            <template slot-scope="{ row }">
+              <el-tag type="primary">{{ row.responsibilityDept }}</el-tag>
+            </template>
+          </el-table-column>
+
+          <el-table-column
+            label="涓嶆弧鎰忚鎯�"
+            prop="unsatisfactoryDetail"
+            min-width="200"
+            align="center"
+          >
+            <template slot-scope="{ row }">
+              <div class="detail-content">
+                {{ row.unsatisfactoryDetail }}
+              </div>
+            </template>
+          </el-table-column>
+
+          <el-table-column label="鎮h�呬俊鎭�" width="300" align="center">
+            <template slot-scope="{ row }">
+              <div class="patient-info">
+                <div class="patient-item">
+                  <span class="label">濮撳悕锛�</span>
+                  <span class="value">{{ row.patientName }}</span>
+                </div>
+                <div class="patient-item">
+                  <span class="label">鎬у埆锛�</span>
+                  <span class="value">{{
+                    row.gender === 1 ? "鐢�" : "濂�"
+                  }}</span>
+                </div>
+                <div class="patient-item">
+                  <span class="label">骞撮緞锛�</span>
+                  <span class="value">{{ row.age }}宀�</span>
+                </div>
+                <div class="patient-item">
+                  <span class="label">鐢佃瘽锛�</span>
+                  <span class="value">{{ row.phone }}</span>
+                </div>
+              </div>
+            </template>
+          </el-table-column>
+
+          <el-table-column label="鍑洪櫌淇℃伅" width="250" align="center">
+            <template slot-scope="{ row }">
+              <div class="discharge-info">
+                <div class="info-item">
+                  <span class="label">绉戝锛�</span>
+                  <span class="value">{{ row.dischargeDept }}</span>
+                </div>
+                <div class="info-item">
+                  <span class="label">鐥呭尯锛�</span>
+                  <span class="value">{{ row.dischargeWard }}</span>
+                </div>
+                <div class="info-item">
+                  <span class="label">濉啓鏃堕棿锛�</span>
+                  <span class="value time">{{ row.fillTime }}</span>
+                </div>
+              </div>
+            </template>
+          </el-table-column>
+
+          <el-table-column
+            label="澶勭悊鐘舵��"
+            prop="processStatus"
+            width="100"
+            align="center"
+          >
+            <template slot-scope="{ row }">
+              <el-tag :type="getStatusTagType(row.processStatus)" effect="dark">
+                {{ getStatusText(row.processStatus) }}
+              </el-tag>
+            </template>
+          </el-table-column>
+
+          <el-table-column
+            label="鎿嶄綔"
+            width="210"
+            align="center"
+            fixed="right"
+          >
+            <template slot-scope="{ row }">
+              <el-button
+                type="primary"
+                size="small"
+                icon="el-icon-view"
+                @click="handleViewDetail(row)"
+              >
+                鏌ョ湅璇︽儏
+              </el-button>
+              <el-button
+                type="warning"
+                size="small"
+                icon="el-icon-edit"
+                @click="handleProcess(row)"
+                :disabled="row.processStatus === 2"
+              >
+                澶勭悊
+              </el-button>
+            </template>
+          </el-table-column>
+        </el-table>
+
+        <!-- 鍒嗛〉 -->
+        <div class="pagination-section">
+          <el-pagination
+            background
+            layout="total, sizes, prev, pager, next, jumper"
+            :current-page="filterParams.pageNum"
+            :page-size="filterParams.pageSize"
+            :page-sizes="[10, 20, 30, 50]"
+            :total="total"
+            @size-change="handleSizeChange"
+            @current-change="handlePageChange"
+          />
+        </div>
+      </el-card>
+    </div>
+
+    <!-- 澶勭悊瀵硅瘽妗� -->
+    <el-dialog
+      title="澶勭悊寮傚父鍙嶉"
+      :visible.sync="processDialogVisible"
+      width="600px"
+      center
+    >
+      <el-form
+        :model="processForm"
+        :rules="processRules"
+        ref="processForm"
+        label-width="100px"
+        size="medium"
+      >
+        <el-form-item label="澶勭悊鐘舵��" prop="status">
+          <el-select
+            v-model="processForm.status"
+            placeholder="璇烽�夋嫨澶勭悊鐘舵��"
+            style="width: 100%"
+          >
+            <el-option label="澶勭悊涓�" :value="1" />
+            <el-option label="宸插鐞�" :value="2" />
+            <el-option label="宸查┏鍥�" :value="3" />
+          </el-select>
+        </el-form-item>
+
+        <el-form-item label="鎶ュ绉戝" prop="reportDepts">
+          <el-select
+            v-model="processForm.reportDepts"
+            placeholder="璇烽�夋嫨鎶ュ绉戝"
+            multiple
+            filterable
+            collapse-tags
+            style="width: 100%"
+          >
+            <el-option
+              v-for="dept in deptList"
+              :key="dept.id"
+              :label="dept.name"
+              :value="dept.id"
+            />
+          </el-select>
+        </el-form-item>
+
+        <el-form-item label="澶勭悊澶囨敞" prop="remark">
+          <el-input
+            v-model="processForm.remark"
+            type="textarea"
+            :rows="4"
+            placeholder="璇疯緭鍏ュ鐞嗗娉紙鏈�澶�500瀛楋級"
+            maxlength="500"
+            show-word-limit
+          />
+        </el-form-item>
+
+        <el-form-item label="闄勪欢涓婁紶">
+          <el-upload
+            class="upload-demo"
+            action="#"
+            :on-preview="handlePreview"
+            :on-remove="handleRemove"
+            :before-remove="beforeRemove"
+            :limit="3"
+            :on-exceed="handleExceed"
+            :file-list="fileList"
+          >
+            <el-button size="small" type="primary">鐐瑰嚮涓婁紶</el-button>
+            <div slot="tip" class="el-upload__tip">
+              鏀寔涓婁紶鍥剧墖銆佹枃妗g瓑闄勪欢锛屽崟涓枃浠朵笉瓒呰繃10MB
+            </div>
+          </el-upload>
+        </el-form-item>
+      </el-form>
+      <span slot="footer" class="dialog-footer">
+        <el-button @click="processDialogVisible = false">鍙栨秷</el-button>
+        <el-button type="primary" @click="submitProcess" :loading="processing">
+          鎻愪氦澶勭悊
+        </el-button>
+      </span>
+    </el-dialog>
+
+    <!-- 鎵归噺澶勭悊瀵硅瘽妗� -->
+    <el-dialog
+      title="鎵归噺澶勭悊寮傚父鍙嶉"
+      :visible.sync="batchDialogVisible"
+      width="600px"
+      center
+    >
+      <el-form
+        :model="batchProcessForm"
+        :rules="processRules"
+        ref="batchProcessForm"
+        label-width="100px"
+        size="medium"
+      >
+        <el-form-item label="澶勭悊鐘舵��" prop="status">
+          <el-select
+            v-model="batchProcessForm.status"
+            placeholder="璇烽�夋嫨澶勭悊鐘舵��"
+            style="width: 100%"
+          >
+            <el-option label="澶勭悊涓�" :value="1" />
+            <el-option label="宸插鐞�" :value="2" />
+            <el-option label="宸查┏鍥�" :value="3" />
+          </el-select>
+        </el-form-item>
+
+        <el-form-item label="鎶ュ绉戝" prop="reportDepts">
+          <el-select
+            v-model="batchProcessForm.reportDepts"
+            placeholder="璇烽�夋嫨鎶ュ绉戝"
+            multiple
+            filterable
+            collapse-tags
+            style="width: 100%"
+          >
+            <el-option
+              v-for="dept in deptList"
+              :key="dept.id"
+              :label="dept.name"
+              :value="dept.id"
+            />
+          </el-select>
+        </el-form-item>
+
+        <el-form-item label="澶勭悊澶囨敞" prop="remark">
+          <el-input
+            v-model="batchProcessForm.remark"
+            type="textarea"
+            :rows="4"
+            placeholder="璇疯緭鍏ュ鐞嗗娉紙鏈�澶�500瀛楋級"
+            maxlength="500"
+            show-word-limit
+          />
+        </el-form-item>
+      </el-form>
+      <span slot="footer" class="dialog-footer">
+        <el-button @click="batchDialogVisible = false">鍙栨秷</el-button>
+        <el-button
+          type="primary"
+          @click="submitBatchProcess"
+          :loading="batchProcessing"
+        >
+          鎵归噺鎻愪氦
+        </el-button>
+      </span>
+    </el-dialog>
+    <!-- 寮傚父璇︽儏寮规 -->
+    <Details-anomaly
+      :visible="detailDialogVisible"
+      :record-id="selectedRecordId"
+      :title="detailDialogTitle"
+      @update:visible="handleDetailDialogClose"
+      @processed="handleProcessed"
+      @close="handleDetailDialogClose"
+    />
+  </div>
+</template>
+
+<script>
+import DetailsAnomaly from "./components/DetailsAnomaly.vue";
+export default {
+  name: "BatchProcess",
+  components: {
+    DetailsAnomaly,
+  },
+  data() {
+    return {
+      // 娣诲姞浠ヤ笅鏁版嵁
+      detailDialogVisible: false,
+      selectedRecordId: null,
+      detailDialogTitle: "寮傚父鍙嶉璇︽儏",
+      // 褰撳墠澶勭悊鐨勫紓甯窱D
+      currentExceptionId: null,
+
+      // 鎵归噺閫変腑鐨勫紓甯窱D
+      selectedExceptionIds: [],
+
+      // 杩囨护鍙傛暟
+      filterParams: {
+        deptId: "",
+        status: "",
+        pageNum: 1,
+        pageSize: 10,
+      },
+
+      // 鍔犺浇鐘舵��
+      loading: false,
+      processing: false,
+      batchProcessing: false,
+
+      // 绉戝鍒楄〃
+      deptList: [
+        { id: 1, name: "蹇冭绠″唴绉�" },
+        { id: 2, name: "绁炵粡鍐呯" },
+        { id: 3, name: "鏅绉�" },
+        { id: 4, name: "楠ㄧ" },
+        { id: 5, name: "濡囦骇绉�" },
+        { id: 6, name: "鍎跨" },
+        { id: 7, name: "鎬ヨ瘖绉�" },
+        { id: 8, name: "鍛煎惛鍐呯" },
+        { id: 9, name: "娑堝寲鍐呯" },
+        { id: 10, name: "鍐呭垎娉岀" },
+      ],
+
+      // 寮傚父鍒楄〃鏁版嵁
+      exceptionList: [],
+      total: 0,
+
+      // 澶勭悊瀵硅瘽妗�
+      processDialogVisible: false,
+      processForm: {
+        status: "",
+        reportDepts: [],
+        remark: "",
+      },
+      processRules: {
+        status: [
+          { required: true, message: "璇烽�夋嫨澶勭悊鐘舵��", trigger: "change" },
+        ],
+        remark: [
+          { required: true, message: "璇疯緭鍏ュ鐞嗗娉�", trigger: "blur" },
+          {
+            min: 5,
+            max: 500,
+            message: "澶囨敞闀垮害鍦� 5 鍒� 500 涓瓧绗�",
+            trigger: "blur",
+          },
+        ],
+      },
+      fileList: [],
+
+      // 鎵归噺澶勭悊瀵硅瘽妗�
+      batchDialogVisible: false,
+      batchProcessForm: {
+        status: "",
+        reportDepts: [],
+        remark: "",
+      },
+    };
+  },
+
+  mounted() {
+    this.loadExceptionList();
+  },
+
+  methods: {
+    // 鍔犺浇寮傚父鍒楄〃
+    async loadExceptionList() {
+      this.loading = true;
+      try {
+        // Mock 鏁版嵁
+        await new Promise((resolve) => {
+          setTimeout(() => {
+            this.exceptionList = [
+              {
+                id: 1,
+                responsibilityDept: "蹇冭绠″唴绉�",
+                unsatisfactoryDetail:
+                  "鍖荤敓鏌ユ埧鏃堕棿澶煭锛屾矡閫氫笉澶熷厖鍒嗭紝瀵圭梾鎯呰В閲婁笉澶熻缁�",
+                patientName: "寮犲厛鐢�",
+                gender: 1,
+                age: 45,
+                phone: "138****1234",
+                dischargeDept: "蹇冭绠″唴绉�",
+                dischargeWard: "鍐呯涓�鐥呭尯",
+                fillTime: "2024-01-15 10:30:25",
+                processStatus: 0,
+                questionnaireId: 1001,
+              },
+              {
+                id: 2,
+                responsibilityDept: "绁炵粡鍐呯",
+                unsatisfactoryDetail:
+                  "鎶ゅ+鎵撻拡鎶�鏈笉浣筹紝鎵庝簡涓夋鎵嶆垚鍔燂紝涓旀�佸害涓嶅鑰愬績",
+                patientName: "鏉庡コ澹�",
+                gender: 0,
+                age: 38,
+                phone: "139****5678",
+                dischargeDept: "绁炵粡鍐呯",
+                dischargeWard: "鍐呯浜岀梾鍖�",
+                fillTime: "2024-01-14 16:20:10",
+                processStatus: 0,
+                questionnaireId: 1002,
+              },
+              {
+                id: 3,
+                responsibilityDept: "鏅绉�",
+                unsatisfactoryDetail: "鏈悗鎹㈣嵂涓嶅強鏃讹紝浼ゅ彛鐤肩棝鏃舵病鏈夊強鏃跺鐞�",
+                patientName: "鐜嬪厛鐢�",
+                gender: 1,
+                age: 52,
+                phone: "137****9012",
+                dischargeDept: "鏅绉�",
+                dischargeWard: "澶栫涓�鐥呭尯",
+                fillTime: "2024-01-13 09:15:45",
+                processStatus: 1,
+                questionnaireId: 1003,
+              },
+              {
+                id: 4,
+                responsibilityDept: "楠ㄧ",
+                unsatisfactoryDetail: "搴峰鎸囧涓嶅涓撲笟锛屽鎭㈠杩囩▼鎻忚堪涓嶆竻妤�",
+                patientName: "鍒樺コ澹�",
+                gender: 0,
+                age: 65,
+                phone: "136****3456",
+                dischargeDept: "楠ㄧ",
+                dischargeWard: "澶栫浜岀梾鍖�",
+                fillTime: "2024-01-12 14:40:30",
+                processStatus: 0,
+                questionnaireId: 1004,
+              },
+              {
+                id: 5,
+                responsibilityDept: "濡囦骇绉�",
+                unsatisfactoryDetail:
+                  "浜у墠妫�鏌ユ帓闃熸椂闂磋繃闀匡紝绛夊緟鏈熼棿娌℃湁浼戞伅搴т綅",
+                patientName: "闄堝コ澹�",
+                gender: 0,
+                age: 28,
+                phone: "135****7890",
+                dischargeDept: "濡囦骇绉�",
+                dischargeWard: "濡囦骇绉戠梾鍖�",
+                fillTime: "2024-01-11 11:25:15",
+                processStatus: 2,
+                questionnaireId: 1005,
+              },
+              {
+                id: 6,
+                responsibilityDept: "鍎跨",
+                unsatisfactoryDetail:
+                  "鍎跨鐢ㄨ嵂鍓傞噺浜や唬涓嶆竻鏅帮紝鐢ㄨ嵂娉ㄦ剰浜嬮」娌℃湁璇存槑",
+                patientName: "璧靛疂瀹�",
+                gender: 1,
+                age: 5,
+                phone: "134****1234",
+                dischargeDept: "鍎跨",
+                dischargeWard: "鍎跨鐥呭尯",
+                fillTime: "2024-01-10 15:50:20",
+                processStatus: 0,
+                questionnaireId: 1006,
+              },
+              {
+                id: 7,
+                responsibilityDept: "鎬ヨ瘖绉�",
+                unsatisfactoryDetail: "鎬ヨ瘖绛夊緟鏃堕棿杩囬暱锛岀梾鎯呮病鏈夊緱鍒板強鏃惰瘎浼�",
+                patientName: "瀛欏厛鐢�",
+                gender: 1,
+                age: 40,
+                phone: "133****5678",
+                dischargeDept: "鎬ヨ瘖绉�",
+                dischargeWard: "鎬ヨ瘖鐥呭尯",
+                fillTime: "2024-01-09 10:15:40",
+                processStatus: 0,
+                questionnaireId: 1007,
+              },
+              {
+                id: 8,
+                responsibilityDept: "鍛煎惛鍐呯",
+                unsatisfactoryDetail: "鍖荤敓寮�鑽緝澶氾紝璐圭敤杈冮珮锛屾病鏈夎鏄庡繀瑕佹��",
+                patientName: "鍛ㄥコ澹�",
+                gender: 0,
+                age: 55,
+                phone: "132****9012",
+                dischargeDept: "鍛煎惛鍐呯",
+                dischargeWard: "鍐呯涓�鐥呭尯",
+                fillTime: "2024-01-08 13:30:55",
+                processStatus: 1,
+                questionnaireId: 1008,
+              },
+            ];
+            this.total = this.exceptionList.length;
+            resolve();
+          }, 500);
+        });
+      } finally {
+        this.loading = false;
+      }
+    },
+
+    // 鑾峰彇鐘舵�佹爣绛剧被鍨�
+    getStatusTagType(status) {
+      switch (status) {
+        case 0:
+          return "warning"; // 寰呭鐞�
+        case 1:
+          return "primary"; // 澶勭悊涓�
+        case 2:
+          return "success"; // 宸插鐞�
+        default:
+          return "info";
+      }
+    },
+
+    // 鑾峰彇鐘舵�佹枃鏈�
+    getStatusText(status) {
+      switch (status) {
+        case 0:
+          return "寰呭鐞�";
+        case 1:
+          return "澶勭悊涓�";
+        case 2:
+          return "宸插鐞�";
+        default:
+          return "鏈煡";
+      }
+    },
+
+    // 澶勭悊绛涢��
+    handleFilter() {
+      this.filterParams.pageNum = 1;
+      this.loadExceptionList();
+    },
+
+    // 閲嶇疆绛涢��
+    handleResetFilter() {
+      this.filterParams = {
+        deptId: "",
+        status: "",
+        pageNum: 1,
+        pageSize: 10,
+      };
+      this.loadExceptionList();
+    },
+
+    // 澶勭悊閫夋嫨鍙樺寲
+    handleSelectionChange(selection) {
+      this.selectedExceptionIds = selection.map((item) => item.id);
+    },
+
+    // 澶勭悊鎵归噺鎻愪氦
+    handleBatchSubmit() {
+      if (this.selectedExceptionIds.length === 0) {
+        this.$message.warning("璇峰厛閫夋嫨瑕佸鐞嗙殑寮傚父鍙嶉");
+        return;
+      }
+      this.batchDialogVisible = true;
+    },
+
+    // 杩斿洖寮傚父鍒楄〃
+    handleGoBack() {
+      this.$router.push("/satisfaction/exception/list");
+    },
+
+    // 鏌ョ湅璇︽儏
+    handleViewDetail(row) {
+      this.selectedRecordId = row.id;
+      this.detailDialogTitle = `${row.patientName} - 寮傚父鍙嶉璇︽儏`;
+      this.detailDialogVisible = true;
+    },
+    // 澶勭悊璇︽儏寮规鍏抽棴
+    handleDetailDialogClose() {
+      this.detailDialogVisible = false;
+      this.selectedRecordId = null;
+    }, // 澶勭悊瀹屾垚鍚庣殑鍥炶皟
+    handleProcessed() {
+      // 閲嶆柊鍔犺浇鏁版嵁
+      this.loadExceptionList();
+    },
+    // 澶勭悊鍗曚釜寮傚父
+    handleProcess(row) {
+      this.currentExceptionId = row.id;
+      this.processForm = {
+        status: row.processStatus === 0 ? 1 : row.processStatus,
+        reportDepts: [],
+        remark: "",
+      };
+      this.processDialogVisible = true;
+    },
+
+    // 鎻愪氦澶勭悊
+    async submitProcess() {
+      this.$refs.processForm.validate(async (valid) => {
+        if (valid) {
+          this.processing = true;
+          try {
+            // Mock API璋冪敤
+            await new Promise((resolve) => setTimeout(resolve, 1000));
+
+            this.$message.success("澶勭悊鎻愪氦鎴愬姛");
+            this.processDialogVisible = false;
+            this.loadExceptionList();
+          } finally {
+            this.processing = false;
+          }
+        }
+      });
+    },
+
+    // 鎻愪氦鎵归噺澶勭悊
+    async submitBatchProcess() {
+      this.$refs.batchProcessForm.validate(async (valid) => {
+        if (valid) {
+          this.batchProcessing = true;
+          try {
+            // Mock API璋冪敤
+            await new Promise((resolve) => setTimeout(resolve, 1500));
+
+            this.$message.success(
+              `宸叉壒閲忓鐞� ${this.selectedExceptionIds.length} 鏉″紓甯稿弽棣坄
+            );
+            this.batchDialogVisible = false;
+            this.selectedExceptionIds = [];
+            this.loadExceptionList();
+          } finally {
+            this.batchProcessing = false;
+          }
+        }
+      });
+    },
+
+    // 鍒嗛〉澶у皬鍙樺寲
+    handleSizeChange(size) {
+      this.filterParams.pageSize = size;
+      this.filterParams.pageNum = 1;
+      this.loadExceptionList();
+    },
+
+    // 椤电爜鍙樺寲
+    handlePageChange(page) {
+      this.filterParams.pageNum = page;
+      this.loadExceptionList();
+    },
+
+    // 鏂囦欢涓婁紶鐩稿叧鏂规硶
+    handlePreview(file) {
+      console.log("棰勮鏂囦欢:", file);
+    },
+
+    handleRemove(file, fileList) {
+      console.log("绉婚櫎鏂囦欢:", file, fileList);
+    },
+
+    beforeRemove(file) {
+      return this.$confirm(`纭畾绉婚櫎 ${file.name}锛焋);
+    },
+
+    handleExceed(files, fileList) {
+      this.$message.warning(
+        `褰撳墠闄愬埗閫夋嫨 3 涓枃浠讹紝鏈閫夋嫨浜� ${files.length} 涓枃浠讹紝鍏遍�夋嫨浜� ${
+          files.length + fileList.length
+        } 涓枃浠禶
+      );
+    },
+  },
+};
+</script>
+
+<style lang="scss" scoped>
+.batch-process {
+  padding: 20px;
+  background-color: #f5f7fa;
+  min-height: 100vh;
+
+  .page-header {
+    margin-bottom: 20px;
+    padding: 20px;
+    background: linear-gradient(135deg, #5788fe 0%, #66b1ff 100%);
+    border-radius: 8px;
+    color: white;
+
+    .header-content {
+      .page-title {
+        margin: 0 0 8px 0;
+        font-size: 20px;
+        font-weight: 600;
+      }
+
+      .page-description {
+        margin: 0 0 20px 0;
+        opacity: 0.9;
+        font-size: 14px;
+      }
+
+      .header-actions {
+        display: flex;
+        gap: 10px;
+      }
+    }
+  }
+
+  .list-section {
+    .filter-section {
+      margin-bottom: 20px;
+
+      .filter-form {
+        display: flex;
+        flex-wrap: wrap;
+        align-items: center;
+
+        ::v-deep .el-form-item {
+          margin-bottom: 0;
+          margin-right: 20px;
+
+          &:last-child {
+            margin-right: 0;
+          }
+        }
+      }
+    }
+
+    .exception-table {
+      ::v-deep .el-table__header-wrapper {
+        th {
+          background-color: #f8f9fa;
+          font-weight: 600;
+          color: #333;
+        }
+      }
+
+      .detail-content {
+        font-size: 13px;
+        color: #606266;
+        line-height: 1.5;
+        text-align: left;
+      }
+
+      .patient-info {
+        .patient-item {
+          display: flex;
+          justify-content: space-between;
+          align-items: center;
+          margin-bottom: 5px;
+          padding: 2px 0;
+
+          .label {
+            font-size: 12px;
+            color: #606266;
+            min-width: 40px;
+          }
+
+          .value {
+            font-size: 13px;
+            color: #333;
+            font-weight: 500;
+            text-align: right;
+            flex: 1;
+          }
+        }
+      }
+
+      .discharge-info {
+        .info-item {
+          display: flex;
+          justify-content: space-between;
+          align-items: center;
+          margin-bottom: 5px;
+          padding: 2px 0;
+
+          .label {
+            font-size: 12px;
+            color: #606266;
+            min-width: 50px;
+          }
+
+          .value {
+            font-size: 13px;
+            color: #333;
+            font-weight: 500;
+            text-align: right;
+            flex: 1;
+
+            &.time {
+              font-size: 12px;
+              color: #909399;
+            }
+          }
+        }
+      }
+    }
+
+    .pagination-section {
+      display: flex;
+      justify-content: center;
+      padding: 20px 0 0 0;
+    }
+  }
+}
+
+@media (max-width: 768px) {
+  .batch-process {
+    padding: 10px;
+
+    .page-header {
+      .header-actions {
+        flex-direction: column;
+        align-items: stretch;
+      }
+    }
+
+    .list-section {
+      .filter-section {
+        .filter-form {
+          ::v-deep .el-form-item {
+            width: 100%;
+            margin-right: 0;
+            margin-bottom: 10px;
+          }
+        }
+      }
+    }
+  }
+}
+</style>
diff --git a/src/views/Satisfaction/configurationmyd/components/DetailsAnomaly.vue b/src/views/Satisfaction/configurationmyd/components/DetailsAnomaly.vue
new file mode 100644
index 0000000..57b4dff
--- /dev/null
+++ b/src/views/Satisfaction/configurationmyd/components/DetailsAnomaly.vue
@@ -0,0 +1,923 @@
+<template>
+  <el-dialog
+    :title="title"
+    :visible.sync="dialogVisible"
+    width="900px"
+    top="5vh"
+    class="exception-detail-dialog"
+    @close="handleClose"
+  >
+    <!-- 鍩烘湰淇℃伅 -->
+    <div class="info-section">
+      <div class="section-title">鍩烘湰淇℃伅</div>
+      <el-row :gutter="20">
+        <el-col :span="8">
+          <div class="info-item">
+            <span class="label">鎮h�呭鍚嶏細</span>
+            <span class="value">{{ currentRecord.patientName }}</span>
+          </div>
+        </el-col>
+        <el-col :span="8">
+          <div class="info-item">
+            <span class="label">鎬у埆锛�</span>
+            <span class="value">{{ currentRecord.gender === 1 ? '鐢�' : '濂�' }}</span>
+          </div>
+        </el-col>
+        <el-col :span="8">
+          <div class="info-item">
+            <span class="label">骞撮緞锛�</span>
+            <span class="value">{{ currentRecord.age }}宀�</span>
+          </div>
+        </el-col>
+        <el-col :span="8">
+          <div class="info-item">
+            <span class="label">鑱旂郴鏂瑰紡锛�</span>
+            <span class="value">{{ currentRecord.phone }}</span>
+          </div>
+        </el-col>
+        <el-col :span="8">
+          <div class="info-item">
+            <span class="label">鍑洪櫌绉戝锛�</span>
+            <span class="value">{{ currentRecord.dischargeDept }}</span>
+          </div>
+        </el-col>
+        <el-col :span="8">
+          <div class="info-item">
+            <span class="label">鍑洪櫌鐥呭尯锛�</span>
+            <span class="value">{{ currentRecord.dischargeWard }}</span>
+          </div>
+        </el-col>
+        <el-col :span="8">
+          <div class="info-item">
+            <span class="label">濉啓鏃堕棿锛�</span>
+            <span class="value">{{ currentRecord.fillTime }}</span>
+          </div>
+        </el-col>
+        <el-col :span="8">
+          <div class="info-item">
+            <span class="label">璐熻矗绉戝锛�</span>
+            <el-tag type="primary">{{ currentRecord.responsibilityDept }}</el-tag>
+          </div>
+        </el-col>
+        <el-col :span="8">
+          <div class="info-item">
+            <span class="label">澶勭悊鐘舵�侊細</span>
+            <el-tag
+              :type="getStatusTagType(currentRecord.processStatus)"
+              effect="dark"
+            >
+              {{ getStatusText(currentRecord.processStatus) }}
+            </el-tag>
+          </div>
+        </el-col>
+      </el-row>
+    </div>
+
+    <!-- 闂嵎璇︽儏 -->
+    <div class="questionnaire-section">
+      <div class="section-title">闂嵎濉啓璇︽儏</div>
+      <div class="questionnaire-content">
+        <div class="question-item" v-for="(question, index) in questionnaireData" :key="index">
+          <div class="question-header">
+            <span class="question-index">{{ index + 1 }}.</span>
+            <span class="question-text">{{ question.question }}</span>
+            <el-tag
+              size="mini"
+              :type="question.type === 1 ? 'primary' : 'success'"
+              class="question-type"
+            >
+              {{ question.type === 1 ? '鍗曢�夐' : '澶氶�夐' }}
+            </el-tag>
+          </div>
+          <div class="question-options">
+            <el-radio-group
+              v-model="question.answer"
+              v-if="question.type === 1"
+              disabled
+            >
+              <el-radio
+                v-for="option in question.options"
+                :key="option.value"
+                :label="option.value"
+                :class="{ 'unsatisfactory-option': isUnsatisfactoryOption(option.value) }"
+              >
+                {{ option.text }}
+              </el-radio>
+            </el-radio-group>
+            <el-checkbox-group
+              v-model="question.answer"
+              v-else
+              disabled
+            >
+              <el-checkbox
+                v-for="option in question.options"
+                :key="option.value"
+                :label="option.value"
+                :class="{ 'unsatisfactory-option': isUnsatisfactoryOption(option.value) }"
+              >
+                {{ option.text }}
+              </el-checkbox>
+            </el-checkbox-group>
+          </div>
+          <div v-if="question.additional" class="additional-remark">
+            <div class="remark-label">琛ュ厖璇存槑锛�</div>
+            <div class="remark-content">{{ question.additional }}</div>
+          </div>
+        </div>
+      </div>
+    </div>
+
+    <!-- 澶勭悊璁板綍 -->
+    <div class="process-section">
+      <div class="section-title">澶勭悊璁板綍</div>
+      <div class="process-timeline" v-if="processRecords.length > 0">
+        <el-timeline>
+          <el-timeline-item
+            v-for="(record, index) in processRecords"
+            :key="index"
+            :timestamp="record.time"
+            placement="top"
+          >
+            <el-card>
+              <div class="process-item">
+                <div class="process-header">
+                  <span class="process-user">{{ record.user }}</span>
+                  <el-tag
+                    size="small"
+                    :type="getStatusTagType(record.status)"
+                  >
+                    {{ getStatusText(record.status) }}
+                  </el-tag>
+                </div>
+                <div class="process-content">
+                  <div v-if="record.reportDepts && record.reportDepts.length > 0" class="process-depts">
+                    <span class="label">鎶ュ绉戝锛�</span>
+                    <el-tag
+                      v-for="dept in record.reportDepts"
+                      :key="dept"
+                      size="small"
+                      type="info"
+                      class="dept-tag"
+                    >
+                      {{ dept }}
+                    </el-tag>
+                  </div>
+                  <div v-if="record.remark" class="process-remark">
+                    <span class="label">澶勭悊澶囨敞锛�</span>
+                    <span class="content">{{ record.remark }}</span>
+                  </div>
+                  <div v-if="record.attachments && record.attachments.length > 0" class="process-attachments">
+                    <span class="label">闄勪欢锛�</span>
+                    <el-button
+                      v-for="file in record.attachments"
+                      :key="file.id"
+                      type="text"
+                      size="small"
+                      icon="el-icon-document"
+                      @click="handlePreviewFile(file)"
+                    >
+                      {{ file.name }}
+                    </el-button>
+                  </div>
+                </div>
+              </div>
+            </el-card>
+          </el-timeline-item>
+        </el-timeline>
+      </div>
+      <div v-else class="no-record">
+        鏆傛棤澶勭悊璁板綍
+      </div>
+    </div>
+
+    <span slot="footer" class="dialog-footer">
+      <el-button
+        type="primary"
+        icon="el-icon-edit"
+        @click="handleProcess"
+        v-if="currentRecord.processStatus !== 2"
+      >
+        澶勭悊寮傚父
+      </el-button>
+      <el-button @click="dialogVisible = false">鍏抽棴</el-button>
+    </span>
+
+    <!-- 澶勭悊瀵硅瘽妗� -->
+    <el-dialog
+      title="澶勭悊寮傚父鍙嶉"
+      :visible.sync="processDialogVisible"
+      width="600px"
+      center
+      append-to-body
+    >
+      <el-form
+        :model="processForm"
+        :rules="processRules"
+        ref="processForm"
+        label-width="100px"
+        size="medium"
+      >
+        <el-form-item label="澶勭悊鐘舵��" prop="status">
+          <el-select
+            v-model="processForm.status"
+            placeholder="璇烽�夋嫨澶勭悊鐘舵��"
+            style="width: 100%"
+          >
+            <el-option label="澶勭悊涓�" :value="1" />
+            <el-option label="宸插鐞�" :value="2" />
+            <el-option label="宸查┏鍥�" :value="3" />
+          </el-select>
+        </el-form-item>
+
+        <el-form-item label="鎶ュ绉戝" prop="reportDepts">
+          <el-select
+            v-model="processForm.reportDepts"
+            placeholder="璇烽�夋嫨鎶ュ绉戝"
+            multiple
+            filterable
+            collapse-tags
+            style="width: 100%"
+          >
+            <el-option
+              v-for="dept in deptList"
+              :key="dept.id"
+              :label="dept.name"
+              :value="dept.id"
+            />
+          </el-select>
+        </el-form-item>
+
+        <el-form-item label="澶勭悊澶囨敞" prop="remark">
+          <el-input
+            v-model="processForm.remark"
+            type="textarea"
+            :rows="4"
+            placeholder="璇疯緭鍏ュ鐞嗗娉紙鏈�澶�500瀛楋級"
+            maxlength="500"
+            show-word-limit
+          />
+        </el-form-item>
+
+        <el-form-item label="闄勪欢涓婁紶">
+          <el-upload
+            class="upload-demo"
+            action="#"
+            :on-preview="handleFilePreview"
+            :on-remove="handleFileRemove"
+            :before-remove="beforeFileRemove"
+            :limit="3"
+            :on-exceed="handleFileExceed"
+            :file-list="fileList"
+          >
+            <el-button size="small" type="primary">鐐瑰嚮涓婁紶</el-button>
+            <div slot="tip" class="el-upload__tip">鏀寔涓婁紶鍥剧墖銆佹枃妗g瓑闄勪欢锛屽崟涓枃浠朵笉瓒呰繃10MB</div>
+          </el-upload>
+        </el-form-item>
+      </el-form>
+      <span slot="footer" class="dialog-footer">
+        <el-button @click="processDialogVisible = false">鍙栨秷</el-button>
+        <el-button
+          type="primary"
+          @click="submitProcess"
+          :loading="processing"
+        >
+          鎻愪氦澶勭悊
+        </el-button>
+      </span>
+    </el-dialog>
+  </el-dialog>
+</template>
+
+<script>
+export default {
+  name: 'ExceptionDetailDialog',
+  props: {
+    // 鏄惁鏄剧ず瀵硅瘽妗�
+    visible: {
+      type: Boolean,
+      default: false
+    },
+    // 璁板綍ID
+    recordId: {
+      type: [Number, String],
+      default: null
+    },
+    // 瀵硅瘽妗嗘爣棰�
+    title: {
+      type: String,
+      default: '寮傚父鍙嶉璇︽儏'
+    }
+  },
+  data() {
+    return {
+      // 褰撳墠璁板綍
+      currentRecord: {},
+
+      // 闂嵎鏁版嵁
+      questionnaireData: [],
+
+      // 澶勭悊璁板綍
+      processRecords: [],
+
+      // 绉戝鍒楄〃
+      deptList: [
+        { id: 1, name: '蹇冭绠″唴绉�' },
+        { id: 2, name: '绁炵粡鍐呯' },
+        { id: 3, name: '鏅绉�' },
+        { id: 4, name: '楠ㄧ' },
+        { id: 5, name: '濡囦骇绉�' },
+        { id: 6, name: '鍎跨' },
+        { id: 7, name: '鎬ヨ瘖绉�' },
+        { id: 8, name: '鍛煎惛鍐呯' }
+      ],
+
+      // 澶勭悊瀵硅瘽妗�
+      processDialogVisible: false,
+      processing: false,
+      processForm: {
+        status: '',
+        reportDepts: [],
+        remark: ''
+      },
+      processRules: {
+        status: [
+          { required: true, message: '璇烽�夋嫨澶勭悊鐘舵��', trigger: 'change' }
+        ],
+        remark: [
+          { required: true, message: '璇疯緭鍏ュ鐞嗗娉�', trigger: 'blur' },
+          { min: 5, max: 500, message: '澶囨敞闀垮害鍦� 5 鍒� 500 涓瓧绗�', trigger: 'blur' }
+        ]
+      },
+      fileList: [],
+
+      // 鍔犺浇鐘舵��
+      loading: false
+    };
+  },
+
+  computed: {
+    dialogVisible: {
+      get() {
+        return this.visible;
+      },
+      set(val) {
+        this.$emit('update:visible', val);
+      }
+    }
+  },
+
+  watch: {
+    visible: {
+      immediate: true,
+      handler(val) {
+        if (val && this.recordId) {
+          this.loadData();
+        }
+      }
+    }
+  },
+
+  methods: {
+    // 鍔犺浇鏁版嵁
+    async loadData() {
+      this.loading = true;
+      try {
+        await Promise.all([
+          this.loadRecordDetail(),
+          this.loadQuestionnaireData(),
+          this.loadProcessRecords()
+        ]);
+      } finally {
+        this.loading = false;
+      }
+    },
+
+    // 鍔犺浇璁板綍璇︽儏
+    async loadRecordDetail() {
+      return new Promise(resolve => {
+        setTimeout(() => {
+          // 鏍规嵁涓嶅悓鐨剅ecordId杩斿洖涓嶅悓鐨刴ock鏁版嵁
+          const mockRecords = {
+            1: {
+              id: 1,
+              patientName: '寮犲厛鐢�',
+              gender: 1,
+              age: 45,
+              phone: '13800138000',
+              dischargeDept: '蹇冭绠″唴绉�',
+              dischargeWard: '鍐呯涓�鐥呭尯',
+              fillTime: '2024-01-15 10:30:25',
+              responsibilityDept: '蹇冭绠″唴绉�',
+              processStatus: 0
+            },
+            2: {
+              id: 2,
+              patientName: '鏉庡コ澹�',
+              gender: 0,
+              age: 38,
+              phone: '13900139000',
+              dischargeDept: '绁炵粡鍐呯',
+              dischargeWard: '鍐呯浜岀梾鍖�',
+              fillTime: '2024-01-14 16:20:10',
+              responsibilityDept: '绁炵粡鍐呯',
+              processStatus: 0
+            },
+            3: {
+              id: 3,
+              patientName: '鐜嬪厛鐢�',
+              gender: 1,
+              age: 52,
+              phone: '13700137000',
+              dischargeDept: '鏅绉�',
+              dischargeWard: '澶栫涓�鐥呭尯',
+              fillTime: '2024-01-13 09:15:45',
+              responsibilityDept: '鏅绉�',
+              processStatus: 1
+            }
+          };
+
+          this.currentRecord = mockRecords[this.recordId] || {
+            id: 1,
+            patientName: '寮犲厛鐢�',
+            gender: 1,
+            age: 45,
+            phone: '13800138000',
+            dischargeDept: '蹇冭绠″唴绉�',
+            dischargeWard: '鍐呯涓�鐥呭尯',
+            fillTime: '2024-01-15 10:30:25',
+            responsibilityDept: '蹇冭绠″唴绉�',
+            processStatus: 0
+          };
+          resolve();
+        }, 300);
+      });
+    },
+
+    // 鍔犺浇闂嵎鏁版嵁
+    async loadQuestionnaireData() {
+      return new Promise(resolve => {
+        setTimeout(() => {
+          this.questionnaireData = [
+            {
+              question: '鎮ㄥ鍖绘姢浜哄憳鐨勬湇鍔℃�佸害鏄惁婊℃剰锛�',
+              type: 1,
+              options: [
+                { value: '闈炲父婊℃剰', text: '闈炲父婊℃剰' },
+                { value: '婊℃剰', text: '婊℃剰' },
+                { value: '涓�鑸�', text: '涓�鑸�' },
+                { value: '涓嶆弧鎰�', text: '涓嶆弧鎰�' },
+                { value: '闈炲父涓嶆弧鎰�', text: '闈炲父涓嶆弧鎰�' }
+              ],
+              answer: '涓嶆弧鎰�',
+              additional: '鍖荤敓鏌ユ埧鏃堕棿澶煭锛屾矡閫氫笉澶熷厖鍒嗭紝瀵圭梾鎯呰В閲婁笉澶熻缁�'
+            },
+            {
+              question: '鎮ㄥ鍖荤敓鐨勮瘖鐤楁按骞冲拰鎶�鏈兘鍔涜瘎浠峰浣曪紵',
+              type: 1,
+              options: [
+                { value: '闈炲父涓撲笟', text: '闈炲父涓撲笟' },
+                { value: '姣旇緝涓撲笟', text: '姣旇緝涓撲笟' },
+                { value: '涓�鑸�', text: '涓�鑸�' },
+                { value: '涓嶅涓撲笟', text: '涓嶅涓撲笟' },
+                { value: '闈炲父涓嶄笓涓�', text: '闈炲父涓嶄笓涓�' }
+              ],
+              answer: '姣旇緝涓撲笟',
+              additional: ''
+            },
+            {
+              question: '鎮ㄥ鍖婚櫌鐨勭幆澧冨拰鍗敓鐘跺喌鏄惁婊℃剰锛�',
+              type: 1,
+              options: [
+                { value: '闈炲父婊℃剰', text: '闈炲父婊℃剰' },
+                { value: '婊℃剰', text: '婊℃剰' },
+                { value: '涓�鑸�', text: '涓�鑸�' },
+                { value: '涓嶆弧鎰�', text: '涓嶆弧鎰�' },
+                { value: '闈炲父涓嶆弧鎰�', text: '闈炲父涓嶆弧鎰�' }
+              ],
+              answer: '涓�鑸�',
+              additional: ''
+            },
+            {
+              question: '鎮ㄨ涓哄尰鎶や汉鍛樹笌鎮ㄧ殑娌熼�氭槸鍚﹀厖鍒嗭紵',
+              type: 1,
+              options: [
+                { value: '闈炲父鍏呭垎', text: '闈炲父鍏呭垎' },
+                { value: '姣旇緝鍏呭垎', text: '姣旇緝鍏呭垎' },
+                { value: '涓�鑸�', text: '涓�鑸�' },
+                { value: '涓嶅鍏呭垎', text: '涓嶅鍏呭垎' },
+                { value: '闈炲父涓嶅厖鍒�', text: '闈炲父涓嶅厖鍒�' }
+              ],
+              answer: '涓嶅鍏呭垎',
+              additional: '鍖荤敓璁茶В鐥呮儏鏃惰閫熷お蹇紝娌℃湁缁欒冻澶熺殑鏃堕棿鎻愰棶'
+            },
+            {
+              question: '鎮ㄥ绛夊緟灏辫瘖鍜屾不鐤楃殑鏃堕棿鏄惁婊℃剰锛�',
+              type: 1,
+              options: [
+                { value: '闈炲父婊℃剰', text: '闈炲父婊℃剰' },
+                { value: '婊℃剰', text: '婊℃剰' },
+                { value: '涓�鑸�', text: '涓�鑸�' },
+                { value: '涓嶆弧鎰�', text: '涓嶆弧鎰�' },
+                { value: '闈炲父涓嶆弧鎰�', text: '闈炲父涓嶆弧鎰�' }
+              ],
+              answer: '涓嶆弧鎰�',
+              additional: '棰勭害鐨�9鐐癸紝瀹為檯10鐐规墠瑙佸埌鍖荤敓'
+            }
+          ];
+          resolve();
+        }, 300);
+      });
+    },
+
+    // 鍔犺浇澶勭悊璁板綍
+    async loadProcessRecords() {
+      return new Promise(resolve => {
+        setTimeout(() => {
+          this.processRecords = [
+            {
+              id: 1,
+              time: '2024-01-15 14:20:30',
+              user: '寮犲尰鐢�',
+              status: 1, // 澶勭悊涓�
+              reportDepts: ['鍖诲姟绉�', '鎶ょ悊閮�'],
+              remark: '宸叉敹鍒板弽棣堬紝姝e湪瀹夋帓鐩稿叧浜哄憳鏍告煡鎯呭喌',
+              attachments: [
+                { id: 1, name: '鍒濇璋冩煡璁板綍.docx' },
+                { id: 2, name: '鎮h�呮矡閫氳褰�.jpg' }
+              ]
+            },
+            {
+              id: 2,
+              time: '2024-01-15 10:45:12',
+              user: '绯荤粺',
+              status: 0, // 寰呭鐞�
+              remark: '绯荤粺鑷姩璇嗗埆涓哄紓甯稿弽棣堬紝宸插垎閰嶅埌璐d换绉戝',
+              attachments: []
+            }
+          ];
+          resolve();
+        }, 300);
+      });
+    },
+
+    // 鍒ゆ柇鏄惁涓轰笉婊℃剰閫夐」
+    isUnsatisfactoryOption(value) {
+      const unsatisfactoryValues = [
+        '涓嶆弧鎰�',
+        '闈炲父涓嶆弧鎰�',
+        '涓嶅涓撲笟',
+        '闈炲父涓嶄笓涓�',
+        '涓嶅鍏呭垎',
+        '闈炲父涓嶅厖鍒�'
+      ];
+      return unsatisfactoryValues.includes(value);
+    },
+
+    // 鑾峰彇鐘舵�佹爣绛剧被鍨�
+    getStatusTagType(status) {
+      switch (status) {
+        case 0: return 'warning'; // 寰呭鐞�
+        case 1: return 'primary'; // 澶勭悊涓�
+        case 2: return 'success'; // 宸插鐞�
+        case 3: return 'danger';  // 宸查┏鍥�
+        default: return 'info';
+      }
+    },
+
+    // 鑾峰彇鐘舵�佹枃鏈�
+    getStatusText(status) {
+      switch (status) {
+        case 0: return '寰呭鐞�';
+        case 1: return '澶勭悊涓�';
+        case 2: return '宸插鐞�';
+        case 3: return '宸查┏鍥�';
+        default: return '鏈煡';
+      }
+    },
+
+    // 澶勭悊寮傚父
+    handleProcess() {
+      this.processForm = {
+        status: this.currentRecord.processStatus === 0 ? 1 : this.currentRecord.processStatus,
+        reportDepts: [],
+        remark: ''
+      };
+      this.processDialogVisible = true;
+    },
+
+    // 鎻愪氦澶勭悊
+    async submitProcess() {
+      this.$refs.processForm.validate(async (valid) => {
+        if (valid) {
+          this.processing = true;
+          try {
+            // Mock API璋冪敤
+            await new Promise(resolve => setTimeout(resolve, 1000));
+
+            this.$message.success('澶勭悊鎻愪氦鎴愬姛');
+            this.processDialogVisible = false;
+
+            // 閲嶆柊鍔犺浇鏁版嵁
+            await this.loadData();
+
+            // 瑙﹀彂鐖剁粍浠跺埛鏂�
+            this.$emit('processed');
+          } finally {
+            this.processing = false;
+          }
+        }
+      });
+    },
+
+    // 棰勮鏂囦欢
+    handlePreviewFile(file) {
+      this.$message.info(`棰勮鏂囦欢: ${file.name}`);
+    },
+
+    // 澶勭悊瀵硅瘽妗嗗叧闂�
+    handleClose() {
+      this.$emit('close');
+    },
+
+    // 鏂囦欢涓婁紶鐩稿叧鏂规硶
+    handleFilePreview(file) {
+      console.log('棰勮鏂囦欢:', file);
+    },
+
+    handleFileRemove(file, fileList) {
+      console.log('绉婚櫎鏂囦欢:', file, fileList);
+    },
+
+    beforeFileRemove(file) {
+      return this.$confirm(`纭畾绉婚櫎 ${file.name}锛焋);
+    },
+
+    handleFileExceed(files, fileList) {
+      this.$message.warning(`褰撳墠闄愬埗閫夋嫨 3 涓枃浠讹紝鏈閫夋嫨浜� ${files.length} 涓枃浠讹紝鍏遍�夋嫨浜� ${files.length + fileList.length} 涓枃浠禶);
+    }
+  }
+};
+</script>
+
+<style lang="scss" scoped>
+.exception-detail-dialog {
+  ::v-deep .el-dialog {
+    max-height: 85vh;
+    display: flex;
+    flex-direction: column;
+
+    .el-dialog__body {
+      flex: 1;
+      overflow-y: auto;
+      padding: 20px;
+    }
+  }
+
+  .info-section {
+    margin-bottom: 20px;
+    padding: 20px;
+    background: #f8f9fa;
+    border-radius: 8px;
+    border: 1px solid #ebeef5;
+
+    .section-title {
+      font-size: 16px;
+      font-weight: 600;
+      color: #303133;
+      margin-bottom: 15px;
+      padding-bottom: 10px;
+      border-bottom: 2px solid #409EFF;
+    }
+
+    .info-item {
+      margin-bottom: 12px;
+      display: flex;
+      align-items: center;
+
+      .label {
+        font-size: 14px;
+        color: #606266;
+        min-width: 80px;
+        font-weight: 500;
+      }
+
+      .value {
+        font-size: 14px;
+        color: #303133;
+        font-weight: 500;
+      }
+    }
+  }
+
+  .questionnaire-section {
+    margin-bottom: 20px;
+    padding: 20px;
+    background: #fff;
+    border-radius: 8px;
+    border: 1px solid #ebeef5;
+
+    .section-title {
+      font-size: 16px;
+      font-weight: 600;
+      color: #303133;
+      margin-bottom: 15px;
+      padding-bottom: 10px;
+      border-bottom: 2px solid #409EFF;
+    }
+
+    .questionnaire-content {
+      .question-item {
+        margin-bottom: 20px;
+        padding: 15px;
+        border-radius: 6px;
+        border: 1px solid #ebeef5;
+        transition: all 0.3s;
+
+        &:hover {
+          border-color: #409EFF;
+          box-shadow: 0 2px 12px 0 rgba(64, 158, 255, 0.1);
+        }
+
+        .question-header {
+          display: flex;
+          align-items: center;
+          margin-bottom: 15px;
+          padding-bottom: 10px;
+          border-bottom: 1px dashed #dcdfe6;
+
+          .question-index {
+            font-weight: 600;
+            color: #409EFF;
+            margin-right: 8px;
+            font-size: 15px;
+          }
+
+          .question-text {
+            flex: 1;
+            font-size: 15px;
+            color: #303133;
+            font-weight: 500;
+            line-height: 1.5;
+          }
+
+          .question-type {
+            margin-left: 10px;
+          }
+        }
+
+        .question-options {
+          ::v-deep .el-radio-group {
+            display: flex;
+            flex-direction: column;
+            gap: 10px;
+          }
+
+          ::v-deep .el-checkbox-group {
+            display: flex;
+            flex-wrap: wrap;
+            gap: 15px;
+          }
+
+          ::v-deep .el-radio,
+          ::v-deep .el-checkbox {
+            margin: 0;
+            padding: 8px 12px;
+            border-radius: 4px;
+            border: 1px solid #ebeef5;
+            transition: all 0.3s;
+
+            &:hover {
+              background: #f5f7fa;
+            }
+
+            &.unsatisfactory-option {
+              border-color: #e6a23c;
+              background: #fdf6ec;
+            }
+          }
+        }
+
+        .additional-remark {
+          margin-top: 15px;
+          padding: 12px;
+          background: #f0f9ff;
+          border-radius: 6px;
+          border-left: 4px solid #409EFF;
+
+          .remark-label {
+            font-size: 13px;
+            color: #606266;
+            font-weight: 500;
+            margin-bottom: 5px;
+          }
+
+          .remark-content {
+            font-size: 14px;
+            color: #303133;
+            line-height: 1.6;
+          }
+        }
+      }
+    }
+  }
+
+  .process-section {
+    .section-title {
+      font-size: 16px;
+      font-weight: 600;
+      color: #303133;
+      margin-bottom: 15px;
+      padding-bottom: 10px;
+      border-bottom: 2px solid #409EFF;
+    }
+
+    .process-timeline {
+      ::v-deep .el-timeline-item {
+        padding-bottom: 20px;
+
+        .el-timeline-item__timestamp {
+          font-size: 13px;
+          color: #909399;
+        }
+      }
+
+      .process-item {
+        .process-header {
+          display: flex;
+          justify-content: space-between;
+          align-items: center;
+          margin-bottom: 10px;
+
+          .process-user {
+            font-size: 14px;
+            font-weight: 600;
+            color: #409EFF;
+          }
+        }
+
+        .process-content {
+          .process-depts {
+            margin-bottom: 8px;
+
+            .label {
+              font-size: 13px;
+              color: #606266;
+              margin-right: 5px;
+            }
+
+            .dept-tag {
+              margin-right: 5px;
+              margin-bottom: 5px;
+            }
+          }
+
+          .process-remark {
+            margin-bottom: 8px;
+
+            .label {
+              font-size: 13px;
+              color: #606266;
+              margin-right: 5px;
+            }
+
+            .content {
+              font-size: 13px;
+              color: #303133;
+              line-height: 1.5;
+            }
+          }
+
+          .process-attachments {
+            .label {
+              font-size: 13px;
+              color: #606266;
+              margin-right: 5px;
+            }
+
+            ::v-deep .el-button {
+              margin-right: 8px;
+              margin-bottom: 5px;
+            }
+          }
+        }
+      }
+    }
+
+    .no-record {
+      text-align: center;
+      padding: 40px 0;
+      color: #909399;
+      font-style: italic;
+      background: #f8f9fa;
+      border-radius: 6px;
+    }
+  }
+
+  .dialog-footer {
+    display: flex;
+    justify-content: flex-end;
+    align-items: center;
+    gap: 10px;
+  }
+}
+</style>
diff --git a/src/views/Satisfaction/configurationmyd/dispose.vue b/src/views/Satisfaction/configurationmyd/dispose.vue
new file mode 100644
index 0000000..8a59106
--- /dev/null
+++ b/src/views/Satisfaction/configurationmyd/dispose.vue
@@ -0,0 +1,980 @@
+<template>
+  <div class="exception-list">
+    <!-- 椤甸潰鏍囬 -->
+    <div class="page-header">
+      <div class="header-content">
+        <h2 class="page-title">婊℃剰搴﹀紓甯稿鐞�</h2>
+        <p class="page-description">鐩戞帶鍜屽鐞嗘弧鎰忓害闂嵎涓殑寮傚父鍙嶉</p>
+      </div>
+    </div>
+
+    <!-- 鏌ヨ鏉′欢鍖哄煙 -->
+    <div class="search-section">
+      <el-card shadow="never">
+        <el-form
+          :model="queryParams"
+          ref="queryForm"
+          size="medium"
+          :inline="true"
+          label-width="120px"
+          class="search-form"
+        >
+          <el-form-item label="婊℃剰搴︽ā鏉�" prop="templateId">
+            <el-select
+              v-model="queryParams.templateId"
+              placeholder="璇烽�夋嫨妯℃澘"
+              clearable
+              style="width: 200px"
+            >
+              <el-option
+                v-for="template in templateList"
+                :key="template.id"
+                :label="template.name"
+                :value="template.id"
+              />
+            </el-select>
+          </el-form-item>
+
+          <el-form-item label="璐d换绉戝" prop="deptIds">
+            <el-select
+              v-model="queryParams.deptIds"
+              placeholder="璇烽�夋嫨璐d换绉戝"
+              clearable
+              filterable
+              multiple
+              collapse-tags
+              style="width: 300px"
+            >
+              <el-option
+                v-for="dept in deptList"
+                :key="dept.id"
+                :label="dept.name"
+                :value="dept.id"
+              />
+            </el-select>
+          </el-form-item>
+
+          <el-form-item label="缁熻鏃堕棿" prop="dateRange">
+            <el-date-picker
+              v-model="queryParams.dateRange"
+              type="daterange"
+              range-separator="鑷�"
+              start-placeholder="寮�濮嬫棩鏈�"
+              end-placeholder="缁撴潫鏃ユ湡"
+              value-format="yyyy-MM-dd"
+              :picker-options="pickerOptions"
+              style="width: 380px"
+            />
+          </el-form-item>
+
+          <el-form-item>
+            <el-button
+              type="primary"
+              icon="el-icon-search"
+              @click="handleSearch"
+              :loading="loading"
+            >
+              鏌ヨ
+            </el-button>
+            <el-button icon="el-icon-refresh" @click="handleReset">
+              閲嶇疆
+            </el-button>
+          </el-form-item>
+        </el-form>
+      </el-card>
+    </div>
+
+    <!-- 鎵归噺鎿嶄綔 -->
+    <div class="batch-section">
+      <el-card shadow="never">
+        <div class="batch-actions">
+          <el-button
+            type="primary"
+            icon="el-icon-s-operation"
+            :disabled="selectedIds.length === 0"
+            @click="handleBatchProcess"
+          >
+            鎵归噺澶勭悊 ({{ selectedIds.length }})
+          </el-button>
+          <el-button
+            type="info"
+            icon="el-icon-download"
+            @click="handleExport"
+          >
+            瀵煎嚭寮傚父鏁版嵁
+          </el-button>
+          <el-button
+            type="warning"
+            icon="el-icon-refresh-right"
+            @click="refreshData"
+          >
+            鍒锋柊鏁版嵁
+          </el-button>
+        </div>
+      </el-card>
+    </div>
+
+    <!-- 寮傚父缁熻姒傝 -->
+    <div class="overview-section">
+      <el-row :gutter="20">
+        <el-col :span="6">
+          <el-card shadow="never" class="stat-card">
+            <div class="stat-content">
+              <div class="stat-icon" style="background: #f0f9ff;">
+                <i class="el-icon-s-claim" style="color: #5788FE;"></i>
+              </div>
+              <div class="stat-info">
+                <div class="stat-title">鎬诲紓甯告暟閲�</div>
+                <div class="stat-value">{{ overviewData.totalExceptionCount }}</div>
+              </div>
+            </div>
+          </el-card>
+        </el-col>
+        <el-col :span="6">
+          <el-card shadow="never" class="stat-card">
+            <div class="stat-content">
+              <div class="stat-icon" style="background: #f0f9ff;">
+                <i class="el-icon-s-flag" style="color: #E6A23C;"></i>
+              </div>
+              <div class="stat-info">
+                <div class="stat-title">寰呭鐞嗗紓甯�</div>
+                <div class="stat-value">{{ overviewData.pendingCount }}</div>
+              </div>
+            </div>
+          </el-card>
+        </el-col>
+        <el-col :span="6">
+          <el-card shadow="never" class="stat-card">
+            <div class="stat-content">
+              <div class="stat-icon" style="background: #f0f9ff;">
+                <i class="el-icon-check" style="color: #67C23A;"></i>
+              </div>
+              <div class="stat-info">
+                <div class="stat-title">宸插鐞嗗紓甯�</div>
+                <div class="stat-value">{{ overviewData.processedCount }}</div>
+              </div>
+            </div>
+          </el-card>
+        </el-col>
+        <el-col :span="6">
+          <el-card shadow="never" class="stat-card">
+            <div class="stat-content">
+              <div class="stat-icon" style="background: #f0f9ff;">
+                <i class="el-icon-s-order" style="color: #909399;"></i>
+              </div>
+              <div class="stat-info">
+                <div class="stat-title">浠婃棩澶勭悊鏁�</div>
+                <div class="stat-value">{{ overviewData.todayProcessedCount }}</div>
+              </div>
+            </div>
+          </el-card>
+        </el-col>
+      </el-row>
+    </div>
+
+    <!-- 寮傚父鍒楄〃 -->
+    <div class="list-section">
+      <el-card shadow="never">
+        <el-table
+          v-loading="loading"
+          :data="exceptionList"
+          :border="true"
+          style="width: 100%"
+          @selection-change="handleSelectionChange"
+          class="exception-table"
+        >
+          <el-table-column
+            type="selection"
+            width="55"
+            align="center"
+          />
+
+          <el-table-column
+            label="搴忓彿"
+            type="index"
+            width="60"
+            align="center"
+          />
+
+          <el-table-column
+            label="棰樼洰鍐呭"
+            prop="questionContent"
+            min-width="300"
+            align="center"
+          >
+            <template slot-scope="{ row }">
+              <div class="question-content">
+                <span class="question-text">{{ row.questionContent }}</span>
+                <div class="question-tags">
+                  <el-tag
+                    size="mini"
+                    :type="getQuestionTypeTag(row.questionType)"
+                  >
+                    {{ row.questionType === 1 ? '鍗曢�夐' : '澶氶�夐' }}
+                  </el-tag>
+                  <el-tag
+                    size="mini"
+                    type="info"
+                  >
+                    {{ row.templateName }}
+                  </el-tag>
+                </div>
+              </div>
+            </template>
+          </el-table-column>
+
+          <el-table-column
+            label="璐熻矗绉戝"
+            prop="responsibilityDepts"
+            width="180"
+            align="center"
+          >
+            <template slot-scope="{ row }">
+              <div class="dept-list">
+                <el-tag
+                  v-for="dept in row.responsibilityDepts"
+                  :key="dept.id"
+                  size="small"
+                  type="primary"
+                  class="dept-tag"
+                >
+                  {{ dept.name }}
+                </el-tag>
+              </div>
+            </template>
+          </el-table-column>
+
+          <el-table-column
+            label="濉啓鎯呭喌"
+            width="200"
+            align="center"
+          >
+            <template slot-scope="{ row }">
+              <div class="fill-statistics">
+                <div class="stat-item">
+                  <span class="stat-label">鏈夋晥濉啓锛�</span>
+                  <span class="stat-value">{{ row.validFillCount }}</span>
+                </div>
+                <div class="stat-item">
+                  <span class="stat-label">寮傚父濉啓锛�</span>
+                  <span class="stat-value exception-count">{{ row.exceptionFillCount }}</span>
+                </div>
+              </div>
+            </template>
+          </el-table-column>
+
+          <el-table-column
+            label="寮傚父浠诲姟"
+            width="280"
+            align="center"
+          >
+            <template slot-scope="{ row }">
+              <div class="exception-tasks">
+                <div class="task-category">
+                  <div class="task-title">宸插鐞�</div>
+                  <div class="task-count processed">{{ row.processedCount }}</div>
+                </div>
+                <div class="task-category">
+                  <div class="task-title">寰呭鐞�</div>
+                  <div class="task-count pending">{{ row.pendingCount }}</div>
+                </div>
+                <div class="task-category">
+                  <div class="task-title">寮傚父鎬绘暟</div>
+                  <div class="task-count total">{{ row.totalExceptionCount }}</div>
+                </div>
+              </div>
+            </template>
+          </el-table-column>
+
+          <el-table-column
+            label="鏈�杩戝鐞�"
+            prop="lastProcessTime"
+            width="180"
+            align="center"
+          >
+            <template slot-scope="{ row }">
+              <div v-if="row.lastProcessTime" class="last-process">
+                <div class="process-time">{{ row.lastProcessTime }}</div>
+                <div class="process-user">{{ row.lastProcessUser }}</div>
+              </div>
+              <span v-else class="no-process">鏆傛棤澶勭悊璁板綍</span>
+            </template>
+          </el-table-column>
+
+          <el-table-column
+            label="鎿嶄綔"
+            width="180"
+            align="center"
+            fixed="right"
+          >
+            <template slot-scope="{ row }">
+              <!-- <el-button
+                type="primary"
+                size="small"
+                icon="el-icon-view"
+                @click="handleViewDetail(row)"
+              >
+                璇︽儏
+              </el-button> -->
+              <el-button
+                type="warning"
+                size="small"
+                icon="el-icon-s-operation"
+                @click="handleBatchQuestion(row)"
+              >
+                鎵归噺澶勭悊
+              </el-button>
+            </template>
+          </el-table-column>
+        </el-table>
+
+        <!-- 鍒嗛〉 -->
+        <div class="pagination-section">
+          <el-pagination
+            background
+            layout="total, sizes, prev, pager, next, jumper"
+            :current-page="queryParams.pageNum"
+            :page-size="queryParams.pageSize"
+            :page-sizes="[10, 20, 30, 50]"
+            :total="total"
+            @size-change="handleSizeChange"
+            @current-change="handlePageChange"
+          />
+        </div>
+      </el-card>
+    </div>
+  </div>
+</template>
+
+<script>
+export default {
+  name: 'ExceptionList',
+  data() {
+    return {
+      // 鏌ヨ鍙傛暟
+      queryParams: {
+        templateId: '',
+        deptIds: [],
+        dateRange: [],
+        pageNum: 1,
+        pageSize: 10
+      },
+
+      // 鍔犺浇鐘舵��
+      loading: false,
+
+      // 閫変腑鐨処D
+      selectedIds: [],
+
+      // 妯℃澘鍒楄〃
+      templateList: [
+        { id: 1, name: '鍑洪櫌婊℃剰搴﹂棶鍗�' },
+        { id: 2, name: '浣忛櫌婊℃剰搴﹂棶鍗�' },
+        { id: 3, name: '闂ㄨ瘖婊℃剰搴﹂棶鍗�' },
+        { id: 4, name: '甯哥敤婊℃剰搴﹂棶鍗�' }
+      ],
+
+      // 绉戝鍒楄〃
+      deptList: [
+        { id: 1, name: '蹇冭绠″唴绉�' },
+        { id: 2, name: '绁炵粡鍐呯' },
+        { id: 3, name: '鏅绉�' },
+        { id: 4, name: '楠ㄧ' },
+        { id: 5, name: '濡囦骇绉�' },
+        { id: 6, name: '鍎跨' },
+        { id: 7, name: '鎬ヨ瘖绉�' },
+        { id: 8, name: '鍛煎惛鍐呯' },
+        { id: 9, name: '娑堝寲鍐呯' },
+        { id: 10, name: '鍐呭垎娉岀' },
+        { id: 11, name: '鑲惧唴绉�' },
+        { id: 12, name: '鑲跨槫绉�' }
+      ],
+
+      // 寮傚父鍒楄〃鏁版嵁
+      exceptionList: [],
+      total: 0,
+
+      // 缁熻姒傝鏁版嵁
+      overviewData: {
+        totalExceptionCount: 0,
+        pendingCount: 0,
+        processedCount: 0,
+        todayProcessedCount: 0
+      },
+
+      // 鏃ユ湡閫夋嫨鍣ㄩ�夐」
+      pickerOptions: {
+        shortcuts: [
+          {
+            text: '鏈�杩戜竴鍛�',
+            onClick(picker) {
+              const end = new Date();
+              const start = new Date();
+              start.setTime(start.getTime() - 3600 * 1000 * 24 * 7);
+              picker.$emit('pick', [start, end]);
+            }
+          },
+          {
+            text: '鏈�杩戜竴涓湀',
+            onClick(picker) {
+              const end = new Date();
+              const start = new Date();
+              start.setTime(start.getTime() - 3600 * 1000 * 24 * 30);
+              picker.$emit('pick', [start, end]);
+            }
+          },
+          {
+            text: '鏈�杩戜笁涓湀',
+            onClick(picker) {
+              const end = new Date();
+              const start = new Date();
+              start.setTime(start.getTime() - 3600 * 1000 * 24 * 90);
+              picker.$emit('pick', [start, end]);
+            }
+          }
+        ],
+        disabledDate(time) {
+          return time.getTime() > Date.now();
+        }
+      }
+    };
+  },
+
+  mounted() {
+    this.loadData();
+  },
+
+  methods: {
+    // 鍔犺浇鏁版嵁
+    async loadData() {
+      this.loading = true;
+      try {
+        await Promise.all([
+          this.loadExceptionList(),
+          this.loadOverviewData()
+        ]);
+      } finally {
+        this.loading = false;
+      }
+    },
+
+    // 鍔犺浇寮傚父鍒楄〃
+    async loadExceptionList() {
+      return new Promise((resolve) => {
+        setTimeout(() => {
+          // Mock 鏁版嵁
+          this.exceptionList = [
+            {
+              id: 1,
+              questionId: 101,
+              questionContent: '鎮ㄥ鍖绘姢浜哄憳鐨勬湇鍔℃�佸害鏄惁婊℃剰锛�',
+              questionType: 1, // 1: 鍗曢�夐, 2: 澶氶�夐
+              templateName: '鍑洪櫌婊℃剰搴﹂棶鍗�',
+              responsibilityDepts: [
+                { id: 1, name: '蹇冭绠″唴绉�' },
+                { id: 2, name: '绁炵粡鍐呯' }
+              ],
+              validFillCount: 145,
+              exceptionFillCount: 8,
+              processedCount: 5,
+              pendingCount: 3,
+              totalExceptionCount: 8,
+              lastProcessTime: '2024-01-15 10:30:25',
+              lastProcessUser: '寮犲尰鐢�'
+            },
+            {
+              id: 2,
+              questionId: 102,
+              questionContent: '鎮ㄥ鍖荤敓鐨勮瘖鐤楁按骞冲拰鎶�鏈兘鍔涜瘎浠峰浣曪紵',
+              questionType: 1,
+              templateName: '浣忛櫌婊℃剰搴﹂棶鍗�',
+              responsibilityDepts: [
+                { id: 3, name: '鏅绉�' },
+                { id: 4, name: '楠ㄧ' }
+              ],
+              validFillCount: 120,
+              exceptionFillCount: 12,
+              processedCount: 8,
+              pendingCount: 4,
+              totalExceptionCount: 12,
+              lastProcessTime: '2024-01-14 16:20:10',
+              lastProcessUser: '鏉庢姢澹暱'
+            },
+            {
+              id: 3,
+              questionId: 103,
+              questionContent: '鎮ㄥ鍖婚櫌鐨勭幆澧冨拰鍗敓鐘跺喌鏄惁婊℃剰锛�',
+              questionType: 1,
+              templateName: '闂ㄨ瘖婊℃剰搴﹂棶鍗�',
+              responsibilityDepts: [
+                { id: 5, name: '濡囦骇绉�' },
+                { id: 6, name: '鍎跨' },
+                { id: 7, name: '鎬ヨ瘖绉�' }
+              ],
+              validFillCount: 180,
+              exceptionFillCount: 15,
+              processedCount: 10,
+              pendingCount: 5,
+              totalExceptionCount: 15,
+              lastProcessTime: '2024-01-13 09:15:45',
+              lastProcessUser: '鐜嬩富浠�'
+            },
+            {
+              id: 4,
+              questionId: 104,
+              questionContent: '鎮ㄨ涓哄尰鎶や汉鍛樹笌鎮ㄧ殑娌熼�氭槸鍚﹀厖鍒嗭紵',
+              questionType: 1,
+              templateName: '甯哥敤婊℃剰搴﹂棶鍗�',
+              responsibilityDepts: [
+                { id: 8, name: '鍛煎惛鍐呯' },
+                { id: 9, name: '娑堝寲鍐呯' }
+              ],
+              validFillCount: 95,
+              exceptionFillCount: 6,
+              processedCount: 4,
+              pendingCount: 2,
+              totalExceptionCount: 6,
+              lastProcessTime: '2024-01-12 14:40:30',
+              lastProcessUser: '璧靛尰鐢�'
+            },
+            {
+              id: 5,
+              questionId: 105,
+              questionContent: '鎮ㄥ绛夊緟灏辫瘖鍜屾不鐤楃殑鏃堕棿鏄惁婊℃剰锛�',
+              questionType: 1,
+              templateName: '浣忛櫌婊℃剰搴﹂棶鍗�',
+              responsibilityDepts: [
+                { id: 10, name: '鍐呭垎娉岀' },
+                { id: 11, name: '鑲惧唴绉�' }
+              ],
+              validFillCount: 200,
+              exceptionFillCount: 25,
+              processedCount: 15,
+              pendingCount: 10,
+              totalExceptionCount: 25,
+              lastProcessTime: '2024-01-11 11:25:15',
+              lastProcessUser: '瀛欐姢澹�'
+            },
+            {
+              id: 6,
+              questionId: 106,
+              questionContent: '鎮ㄥ鍖婚櫌鏀惰垂鐨勯�忔槑搴﹀拰鍚堢悊鎬ц瘎浠峰浣曪紵',
+              questionType: 1,
+              templateName: '闂ㄨ瘖婊℃剰搴﹂棶鍗�',
+              responsibilityDepts: [
+                { id: 12, name: '鑲跨槫绉�' }
+              ],
+              validFillCount: 160,
+              exceptionFillCount: 18,
+              processedCount: 12,
+              pendingCount: 6,
+              totalExceptionCount: 18,
+              lastProcessTime: '2024-01-10 15:50:20',
+              lastProcessUser: '鍛ㄥ尰鐢�'
+            },
+            {
+              id: 7,
+              questionId: 107,
+              questionContent: '鎮ㄤ細鍚戜翰鍙嬫帹鑽愭垜浠尰闄㈠悧锛�',
+              questionType: 1,
+              templateName: '鍑洪櫌婊℃剰搴﹂棶鍗�',
+              responsibilityDepts: [
+                { id: 1, name: '蹇冭绠″唴绉�' },
+                { id: 8, name: '鍛煎惛鍐呯' }
+              ],
+              validFillCount: 110,
+              exceptionFillCount: 7,
+              processedCount: 5,
+              pendingCount: 2,
+              totalExceptionCount: 7,
+              lastProcessTime: '2024-01-09 10:15:40',
+              lastProcessUser: '鍚翠富浠�'
+            },
+            {
+              id: 8,
+              questionId: 108,
+              questionContent: '鎮ㄥ浠ヤ笅鍝簺鏂归潰姣旇緝婊℃剰锛堝閫夛級锛�',
+              questionType: 2,
+              templateName: '甯哥敤婊℃剰搴﹂棶鍗�',
+              responsibilityDepts: [
+                { id: 2, name: '绁炵粡鍐呯' },
+                { id: 3, name: '鏅绉�' },
+                { id: 5, name: '濡囦骇绉�' }
+              ],
+              validFillCount: 135,
+              exceptionFillCount: 9,
+              processedCount: 6,
+              pendingCount: 3,
+              totalExceptionCount: 9,
+              lastProcessTime: '2024-01-08 13:30:55',
+              lastProcessUser: '閮戝尰鐢�'
+            }
+          ];
+          this.total = this.exceptionList.length;
+          resolve();
+        }, 500);
+      });
+    },
+
+    // 鍔犺浇姒傝鏁版嵁
+    async loadOverviewData() {
+      return new Promise((resolve) => {
+        setTimeout(() => {
+          // 璁$畻缁熻鏁版嵁
+          const totalExceptionCount = this.exceptionList.reduce((sum, item) => sum + item.totalExceptionCount, 0);
+          const pendingCount = this.exceptionList.reduce((sum, item) => sum + item.pendingCount, 0);
+          const processedCount = this.exceptionList.reduce((sum, item) => sum + item.processedCount, 0);
+
+          this.overviewData = {
+            totalExceptionCount,
+            pendingCount,
+            processedCount,
+            todayProcessedCount: 8 // 浠婃棩澶勭悊鏁� mock
+          };
+          resolve();
+        }, 300);
+      });
+    },
+
+    // 鑾峰彇棰樼洰绫诲瀷鏍囩鏍峰紡
+    getQuestionTypeTag(type) {
+      return type === 1 ? 'primary' : 'success';
+    },
+
+    // 澶勭悊鏌ヨ
+    handleSearch() {
+      this.queryParams.pageNum = 1;
+      this.loadData();
+    },
+
+    // 澶勭悊閲嶇疆
+    handleReset() {
+      this.$refs.queryForm.resetFields();
+      this.queryParams.dateRange = [];
+      this.queryParams.pageNum = 1;
+      this.loadData();
+    },
+
+    // 澶勭悊鎵归噺澶勭悊
+    handleBatchProcess() {
+      if (this.selectedIds.length === 0) {
+        this.$message.warning('璇峰厛閫夋嫨瑕佸鐞嗙殑寮傚父棰樼洰');
+        return;
+      }
+
+      // 璺宠浆鍒版壒閲忓鐞嗛〉闈�
+      this.$router.push({
+        path: '/satisfaction/exception/batch-process',
+        query: {
+          questionIds: this.selectedIds.join(',')
+        }
+      });
+    },
+
+    // 澶勭悊瀵煎嚭
+    handleExport() {
+      this.$message.success('瀵煎嚭鍔熻兘寮�鍙戜腑...');
+    },
+
+    // 鍒锋柊鏁版嵁
+    refreshData() {
+      this.loadData();
+      this.$message.success('鏁版嵁宸插埛鏂�');
+    },
+
+    // 澶勭悊閫夋嫨鍙樺寲
+    handleSelectionChange(selection) {
+      this.selectedIds = selection.map(item => item.questionId);
+    },
+
+    // 澶勭悊鏌ョ湅璇︽儏
+    handleViewDetail(row) {
+      this.$router.push({
+        path: '/satisfaction/exception/detail',
+        query: {
+          id: row.questionId
+        }
+      });
+    },
+
+    // 澶勭悊鍗曚釜棰樼洰鎵归噺澶勭悊
+    handleBatchQuestion(row) {
+      this.$router.push({
+        path: '/Intelligentcenter/batch',
+        query: {
+          questionId: row.questionId
+        }
+      });
+    },
+
+    // 澶勭悊鍒嗛〉澶у皬鍙樺寲
+    handleSizeChange(size) {
+      this.queryParams.pageSize = size;
+      this.queryParams.pageNum = 1;
+      this.loadExceptionList();
+    },
+
+    // 澶勭悊椤电爜鍙樺寲
+    handlePageChange(page) {
+      this.queryParams.pageNum = page;
+      this.loadExceptionList();
+    }
+  }
+};
+</script>
+
+<style lang="scss" scoped>
+.exception-list {
+  padding: 20px;
+  background-color: #f5f7fa;
+  min-height: 100vh;
+
+  .page-header {
+    margin-bottom: 20px;
+    padding: 20px;
+    background: linear-gradient(135deg, #5788FE 0%, #66b1ff 100%);
+    border-radius: 8px;
+    color: white;
+
+    .header-content {
+      .page-title {
+        margin: 0 0 8px 0;
+        font-size: 20px;
+        font-weight: 600;
+      }
+
+      .page-description {
+        margin: 0;
+        opacity: 0.9;
+        font-size: 14px;
+      }
+    }
+  }
+
+  .search-section {
+    margin-bottom: 20px;
+
+    .search-form {
+      display: flex;
+      flex-wrap: wrap;
+      align-items: center;
+
+      ::v-deep .el-form-item {
+        margin-bottom: 0;
+        margin-right: 20px;
+
+        &:last-child {
+          margin-right: 0;
+        }
+      }
+    }
+  }
+
+  .batch-section {
+    margin-bottom: 20px;
+
+    .batch-actions {
+      display: flex;
+      gap: 10px;
+      align-items: center;
+    }
+  }
+
+  .overview-section {
+    margin-bottom: 20px;
+
+    .stat-card {
+      .stat-content {
+        display: flex;
+        align-items: center;
+        gap: 20px;
+
+        .stat-icon {
+          width: 60px;
+          height: 60px;
+          border-radius: 12px;
+          display: flex;
+          align-items: center;
+          justify-content: center;
+
+          i {
+            font-size: 28px;
+          }
+        }
+
+        .stat-info {
+          flex: 1;
+
+          .stat-title {
+            font-size: 14px;
+            color: #606266;
+            margin-bottom: 8px;
+          }
+
+          .stat-value {
+            font-size: 24px;
+            font-weight: 600;
+            color: #303133;
+          }
+        }
+      }
+    }
+  }
+
+  .list-section {
+    .exception-table {
+      ::v-deep .el-table__header-wrapper {
+        th {
+          background-color: #f8f9fa;
+          font-weight: 600;
+          color: #333;
+        }
+      }
+
+      .question-content {
+        .question-text {
+          display: block;
+          font-size: 14px;
+          color: #303133;
+          margin-bottom: 8px;
+          line-height: 1.5;
+        }
+
+        .question-tags {
+          display: flex;
+          gap: 5px;
+          justify-content: center;
+        }
+      }
+
+      .dept-list {
+        display: flex;
+        flex-direction: column;
+        gap: 5px;
+        align-items: center;
+
+        .dept-tag {
+          margin: 2px 0;
+        }
+      }
+
+      .fill-statistics {
+        .stat-item {
+          display: flex;
+          justify-content: space-between;
+          align-items: center;
+          margin-bottom: 5px;
+          padding: 2px 0;
+
+          .stat-label {
+            font-size: 12px;
+            color: #606266;
+          }
+
+          .stat-value {
+            font-size: 14px;
+            font-weight: 500;
+            color: #333;
+          }
+
+          .exception-count {
+            color: #e6a23c;
+            font-weight: 600;
+          }
+        }
+      }
+
+      .exception-tasks {
+        display: flex;
+        justify-content: space-around;
+        align-items: center;
+
+        .task-category {
+          text-align: center;
+          padding: 5px 8px;
+          border-radius: 6px;
+          min-width: 70px;
+
+          .task-title {
+            font-size: 12px;
+            color: #606266;
+            margin-bottom: 5px;
+          }
+
+          .task-count {
+            font-size: 18px;
+            font-weight: 600;
+            line-height: 1;
+
+            &.processed {
+              color: #67c23a;
+            }
+
+            &.pending {
+              color: #e6a23c;
+            }
+
+            &.total {
+              color: #5788FE;
+            }
+          }
+        }
+      }
+
+      .last-process {
+        .process-time {
+          font-size: 12px;
+          color: #606266;
+          margin-bottom: 4px;
+        }
+
+        .process-user {
+          font-size: 13px;
+          color: #5788FE;
+          font-weight: 500;
+        }
+      }
+
+      .no-process {
+        color: #909399;
+        font-style: italic;
+      }
+    }
+
+    .pagination-section {
+      display: flex;
+      justify-content: center;
+      padding: 20px 0 0 0;
+    }
+  }
+}
+
+@media (max-width: 768px) {
+  .exception-list {
+    padding: 10px;
+
+    .search-section {
+      .search-form {
+        ::v-deep .el-form-item {
+          width: 100%;
+          margin-right: 0;
+          margin-bottom: 10px;
+        }
+      }
+    }
+
+    .overview-section {
+      .el-row {
+        margin-left: 0;
+        margin-right: 0;
+
+        .el-col {
+          padding-left: 0;
+          padding-right: 0;
+          margin-bottom: 10px;
+        }
+      }
+    }
+  }
+}
+</style>
diff --git a/src/views/Satisfaction/configurationmyd/index.vue b/src/views/Satisfaction/configurationmyd/index.vue
new file mode 100644
index 0000000..b92dfd9
--- /dev/null
+++ b/src/views/Satisfaction/configurationmyd/index.vue
@@ -0,0 +1,2376 @@
+<template>
+  <div class="satisfaction-exception-config">
+    <!-- 椤甸潰鏍囬 -->
+    <div class="page-header">
+      <div class="header-content">
+        <h2 class="page-title">婊℃剰搴﹂鐩紓甯稿鐞嗛厤缃�</h2>
+        <p class="page-description">
+          鍩轰簬妯℃澘閰嶇疆婊℃剰搴﹂鐩殑璐d换绉戝鍜屾姤澶囩瀹�
+        </p>
+      </div>
+    </div>
+
+    <!-- 妯℃澘閫夋嫨鍖哄煙 -->
+    <div class="template-section">
+      <el-card shadow="never">
+        <div class="template-header">
+          <h3 class="template-title">妯℃澘閫夋嫨</h3>
+          <p class="template-tip">璇峰厛閫夋嫨妯℃澘绫诲瀷鍜屽叿浣撴ā鏉�</p>
+        </div>
+
+        <el-form
+          :model="templateForm"
+          :rules="templateRules"
+          ref="templateForm"
+          label-width="120px"
+          size="medium"
+        >
+          <el-row :gutter="20">
+            <el-col :span="8">
+              <el-form-item label="妯℃澘绫诲瀷" prop="templateType">
+                <el-select
+                  v-model="templateForm.templateType"
+                  placeholder="璇烽�夋嫨妯℃澘绫诲瀷"
+                  clearable
+                  @change="handleTemplateTypeChange"
+                  style="width: 100%"
+                >
+                  <el-option label="闂嵎妯℃澘" :value="1" />
+                  <el-option label="璇煶妯℃澘" :value="2" />
+                </el-select>
+              </el-form-item>
+            </el-col>
+
+            <el-col :span="8">
+              <el-form-item
+                label="閫夋嫨妯℃澘"
+                prop="templateId"
+                :rules="
+                  templateForm.templateType
+                    ? [
+                        {
+                          required: true,
+                          message: '璇烽�夋嫨妯℃澘',
+                          trigger: 'change',
+                        },
+                      ]
+                    : []
+                "
+              >
+                <el-select
+                  v-model="templateForm.templateId"
+                  placeholder="璇烽�夋嫨妯℃澘"
+                  clearable
+                  filterable
+                  @change="handleTemplateChange"
+                  style="width: 100%"
+                >
+                  <el-option
+                    v-for="template in filteredTemplateOptions"
+                    :key="template.id"
+                    :label="template.templateName"
+                    :value="template.id"
+                  />
+                  <div
+                    v-if="templateOptionsLoading"
+                    slot="empty"
+                    class="select-loading"
+                  >
+                    <i class="el-icon-loading"></i>
+                    <span>鍔犺浇涓�...</span>
+                  </div>
+                </el-select>
+              </el-form-item>
+            </el-col>
+
+            <el-col :span="8">
+              <el-form-item>
+                <el-button
+                  type="primary"
+                  icon="el-icon-search"
+                  @click="handleLoadTemplate"
+                  :loading="templateLoading"
+                  :disabled="!templateForm.templateId"
+                >
+                  鍔犺浇妯℃澘棰樼洰
+                </el-button>
+                <el-button icon="el-icon-refresh" @click="handleResetTemplate">
+                  閲嶇疆
+                </el-button>
+              </el-form-item>
+            </el-col>
+          </el-row>
+        </el-form>
+      </el-card>
+    </div>
+
+    <!-- 妯℃澘淇℃伅 -->
+    <div v-if="currentTemplateInfo" class="template-info-section">
+      <el-card shadow="never">
+        <div class="template-info">
+          <div class="info-left">
+            <h3 class="template-name">
+              {{ currentTemplateInfo.templateName }}
+            </h3>
+            <div class="template-meta">
+              <span class="meta-item">
+                <i class="el-icon-s-order"></i>
+                妯℃澘绫诲瀷锛歿{
+                  templateForm.templateType === 1 ? "闂嵎妯℃澘" : "璇煶妯℃澘"
+                }}
+              </span>
+              <span class="meta-item">
+                <i class="el-icon-s-management"></i>
+                棰樼洰鎬绘暟锛歿{ currentTemplateInfo.questionCount || 0 }}
+              </span>
+              <span class="meta-item">
+                <i class="el-icon-star-on"></i>
+                婊℃剰搴﹂鐩細{{ satisfactionQuestionsCount }}
+              </span>
+            </div>
+          </div>
+          <div class="info-right">
+            <el-tag
+              :type="
+                currentTemplateInfo.templateStatus === 1 ? 'success' : 'info'
+              "
+              size="medium"
+            >
+              {{ currentTemplateInfo.templateStatus === 1 ? "鍚敤" : "鍋滅敤" }}
+            </el-tag>
+          </div>
+        </div>
+      </el-card>
+    </div>
+
+    <!-- 鎼滅储鍖哄煙锛堥鐩瓫閫夛級 -->
+    <div v-if="questionList.length > 0" class="search-section">
+      <el-card shadow="never" class="search-container">
+        <el-form :model="queryParams" :inline="true" size="medium">
+          <el-form-item label="闂涓婚">
+            <el-input
+              v-model="queryParams.scriptTopic"
+              placeholder="璇疯緭鍏ラ棶棰樹富棰�"
+              clearable
+              @keyup.enter.native="handleQuery"
+            />
+          </el-form-item>
+          <el-form-item label="闂鍐呭">
+            <el-input
+              v-model="queryParams.scriptContent"
+              placeholder="璇疯緭鍏ラ棶棰樺唴瀹�"
+              clearable
+              @keyup.enter.native="handleQuery"
+            />
+          </el-form-item>
+          <el-form-item>
+            <el-button
+              type="primary"
+              icon="el-icon-search"
+              @click="handleQuery"
+            >
+              绛涢�夐鐩�
+            </el-button>
+            <el-button icon="el-icon-refresh" @click="resetQuery">
+              閲嶇疆绛涢��
+            </el-button>
+          </el-form-item>
+        </el-form>
+      </el-card>
+    </div>
+
+    <!-- 閰嶇疆鍒楄〃 -->
+    <div class="config-content">
+      <!-- 鎵归噺鎿嶄綔鏍� -->
+      <div v-if="questionList.length > 0" class="batch-actions-card">
+        <el-card shadow="never">
+          <div class="batch-actions">
+            <el-button
+              type="success"
+              icon="el-icon-check"
+              :loading="batchSaving"
+              :disabled="!hasChanges || batchSaving"
+              @click="handleBatchSave"
+              size="medium"
+            >
+              {{ batchSaving ? "鎵归噺淇濆瓨涓�..." : "鎵归噺淇濆瓨閰嶇疆" }}
+            </el-button>
+            <span v-if="changedCount > 0" class="change-count">
+              鏈� {{ changedCount }} 椤归厤缃渶瑕佷繚瀛�
+            </span>
+            <div class="total-count">
+              鍏� {{ filteredQuestionList.length }} 鏉¤褰�
+            </div>
+          </div>
+        </el-card>
+      </div>
+
+      <div v-if="loading" class="loading-wrapper">
+        <div class="loading-spinner">
+          <i class="el-icon-loading"></i>
+          <span>鍔犺浇涓�...</span>
+        </div>
+      </div>
+
+      <div
+        v-else-if="questionList.length === 0 && templateForm.templateId"
+        class="empty-wrapper"
+      >
+        <el-empty description="璇ユā鏉夸腑鏆傛棤婊℃剰搴﹂鐩�">
+          <p class="empty-tip">
+            璇烽�夋嫨鍏朵粬妯℃澘鎴栨鏌ユā鏉夸腑鏄惁鍖呭惈婊℃剰搴︾被鍨嬮鐩紙鍒嗙被ID:
+            404,405,406锛�
+          </p>
+        </el-empty>
+      </div>
+
+      <!-- 涓�琛屼竴琛岀殑鍗$墖鍒楄〃 -->
+      <div v-else-if="filteredQuestionList.length > 0" class="question-list">
+        <div
+          v-for="(question, index) in filteredQuestionList"
+          :key="question.id"
+          class="question-item"
+        >
+          <el-card
+            shadow="hover"
+            class="question-card"
+            :class="{ 'has-changes': question.hasChanges }"
+          >
+            <!-- 鍗$墖澶撮儴 -->
+            <div class="card-header">
+              <div class="header-left">
+                <div class="question-index">
+                  <span class="index-number">{{ index + 1 }}</span>
+                  <div class="index-line"></div>
+                </div>
+                <div class="question-basic-info">
+                  <div class="question-title-section">
+                    <h3 class="question-topic" :title="question.scriptTopic">
+                      {{ question.scriptTopic || "鏃犱富棰�" }}
+                    </h3>
+                    <div class="question-tags">
+                      <dict-tag
+                        :options="askvaluetype"
+                        :value="question.scriptType"
+                        size="small"
+                      />
+                      <el-tag
+                        v-if="question.targetname"
+                        size="small"
+                        type="info"
+                      >
+                        {{ question.targetname }}
+                      </el-tag>
+                    </div>
+                  </div>
+                  <div class="question-content-section">
+                    <span class="content-label">棰樼洰鍐呭锛�</span>
+                    <span class="content-text">{{
+                      question.scriptContent
+                    }}</span>
+                  </div>
+                </div>
+              </div>
+              <div class="header-right">
+                <!-- 寮傚父閫夐」鐘舵�� -->
+                <div
+                  class="option-status"
+                  v-if="
+                    templateForm.templateType != 3 &&
+                    templateForm.templateType != 4
+                  "
+                >
+                  <el-tooltip
+                    :content="
+                      checkHasAbnormalOptions(question)
+                        ? '宸叉湁寮傚父閫夐」'
+                        : '鏆傛棤寮傚父閫夐」'
+                    "
+                    placement="top"
+                  >
+                    <el-tag
+                      :type="
+                        checkHasAbnormalOptions(question) ? 'success' : 'danger'
+                      "
+                      size="small"
+                      class="status-tag"
+                    >
+                      <i
+                        :class="
+                          checkHasAbnormalOptions(question)
+                            ? 'el-icon-success'
+                            : 'el-icon-warning'
+                        "
+                      ></i>
+                      {{
+                        checkHasAbnormalOptions(question)
+                          ? "寮傚父閫夐」宸查厤缃�"
+                          : "鏃犲紓甯搁�夐」"
+                      }}
+                    </el-tag>
+                  </el-tooltip>
+                </div>
+
+                <el-button
+                  type="text"
+                  icon="el-icon-view"
+                  @click="previewQuestion(question)"
+                  size="small"
+                >
+                  棰勮
+                </el-button>
+
+                <!-- 娣诲姞閰嶇疆閫夐」鎸夐挳 -->
+                <el-button
+                  v-if="
+                    templateForm.templateType != 3 &&
+                    templateForm.templateType != 4
+                  "
+                  type="text"
+                  icon="el-icon-setting"
+                  @click="openOptionDialog(question)"
+                  size="small"
+                >
+                  閰嶇疆閫夐」
+                </el-button>
+              </div>
+            </div>
+
+            <!-- 寮傚父澶勭悊閰嶇疆 -->
+            <div class="config-section">
+              <div class="config-title">
+                <i class="el-icon-setting"></i>
+                <span>寮傚父澶勭悊閰嶇疆</span>
+              </div>
+
+              <el-form
+                :model="question.exceptionConfig"
+                :rules="configRules"
+                ref="configForm"
+                label-width="100px"
+                size="small"
+                class="config-form"
+              >
+                <div class="config-fields">
+                  <!-- 璐d换绉戝锛堝閫夛級 -->
+                  <div class="config-field">
+                    <el-form-item
+                      label="璐d换绉戝"
+                      prop="responsibilityDept"
+                      class="config-item"
+                    >
+                      <el-select
+                        v-model="question.exceptionConfig.responsibilityDept"
+                        placeholder="璇烽�夋嫨璐d换绉戝"
+                        filterable
+                        clearable
+                        multiple
+                        style="width: 100%"
+                        @change="handleConfigChange(question)"
+                      >
+                        <el-option
+                          v-for="dept in deptOptions"
+                          :key="dept.id"
+                          :label="dept.label"
+                          :value="dept.deptCode"
+                        />
+                      </el-select>
+                      <div class="config-tip">
+                        璐熻矗澶勭悊璇ラ鐩弽棣堢殑绉戝锛屽彲澶氶��
+                      </div>
+                    </el-form-item>
+                  </div>
+
+                  <!-- 鎶ュ绉戝锛堝閫夛級 -->
+                  <div class="config-field">
+                    <el-form-item
+                      label="鎶ュ绉戝"
+                      prop="reportDept"
+                      class="config-item"
+                    >
+                      <el-select
+                        v-model="question.exceptionConfig.reportDept"
+                        placeholder="璇烽�夋嫨鎶ュ绉戝"
+                        filterable
+                        clearable
+                        multiple
+                        style="width: 100%"
+                        @change="handleConfigChange(question)"
+                      >
+                        <el-option
+                          v-for="dept in deptOptions"
+                          :key="dept.id"
+                          :label="dept.label"
+                          :value="dept.deptCode"
+                        />
+                      </el-select>
+                      <div class="config-tip">
+                        闇�瑕佹帴鏀跺紓甯稿弽棣堢殑绉戝锛屽彲澶氶��
+                      </div>
+                    </el-form-item>
+                  </div>
+                </div>
+
+                <!-- 褰撳墠閰嶇疆淇℃伅 -->
+                <div v-if="question.hasChanges" class="current-config">
+                  <div class="config-preview">
+                    <div class="preview-item">
+                      <span class="preview-label">璐d换绉戝锛�</span>
+                      <span class="preview-value">
+                        {{
+                          getDeptNames(
+                            question.exceptionConfig.responsibilityDept || []
+                          ).join(", ")
+                        }}
+                      </span>
+                    </div>
+                    <div class="preview-item">
+                      <span class="preview-label">鎶ュ绉戝锛�</span>
+                      <span class="preview-value">
+                        {{
+                          getDeptNames(
+                            question.exceptionConfig.reportDept || []
+                          ).join(", ")
+                        }}
+                      </span>
+                    </div>
+                  </div>
+                </div>
+
+                <!-- 閰嶇疆鐘舵�佸拰鎿嶄綔鎸夐挳 -->
+                <div class="config-footer">
+                  <div v-if="question.saveStatus" class="save-status">
+                    <el-alert
+                      :type="question.saveStatus.type"
+                      :title="question.saveStatus.message"
+                      :closable="false"
+                      show-icon
+                      :effect="
+                        question.saveStatus.type === 'success'
+                          ? 'dark'
+                          : 'light'
+                      "
+                      size="small"
+                    />
+                  </div>
+
+                  <div class="config-actions">
+                    <el-button
+                      type="primary"
+                      :loading="question.saving"
+                      :disabled="!question.hasChanges"
+                      @click="saveSingleConfig(question)"
+                      size="small"
+                      icon="el-icon-check"
+                    >
+                      {{ question.saving ? "淇濆瓨涓�..." : "淇濆瓨閰嶇疆" }}
+                    </el-button>
+                    <el-button
+                      v-if="question.hasChanges"
+                      type="text"
+                      @click="resetSingleConfig(question)"
+                      size="small"
+                    >
+                      閲嶇疆
+                    </el-button>
+                  </div>
+                </div>
+              </el-form>
+            </div>
+          </el-card>
+        </div>
+      </div>
+    </div>
+<!-- 閫夐」閰嶇疆瀵硅瘽妗� -->
+<el-dialog
+  title="閫夐」寮傚父鐘舵�侀厤缃�"
+  :visible.sync="optionDialogVisible"
+  width="700px"
+  center
+  :close-on-click-modal="false"
+>
+  <div v-if="editingQuestion" class="option-config-wrapper">
+    <div class="dialog-header">
+      <h4>{{ editingQuestion.scriptTopic || '鏃犱富棰�' }}</h4>
+      <p class="dialog-subtitle">{{ editingQuestion.scriptContent }}</p>
+    </div>
+
+    <div class="option-list">
+      <el-alert
+        v-if="!currentOptions.some(opt => opt.isabnormal === 1)"
+        title="璇疯嚦灏戣缃竴涓紓甯搁�夐」锛堟爣璁颁负寮傚父锛�"
+        type="warning"
+        :closable="false"
+        show-icon
+        style="margin-bottom: 20px;"
+      />
+
+      <div v-for="(option, index) in currentOptions" :key="index" class="option-item">
+        <el-form
+          :model="option"
+          :rules="optionRules"
+          ref="optionForm"
+          size="small"
+          class="option-form"
+        >
+          <el-row :gutter="12" align="middle">
+            <el-col :span="2">
+              <div class="option-index">#{{ index + 1 }}</div>
+            </el-col>
+
+            <el-col :span="12">
+              <el-form-item prop="targetvalue">
+                <el-input
+                  v-model="option.targetvalue"
+                  placeholder="璇疯緭鍏ラ�夐」鍐呭"
+                  clearable
+                  maxlength="200"
+                  show-word-limit
+                />
+              </el-form-item>
+            </el-col>
+
+            <el-col :span="6">
+              <el-form-item prop="isabnormal">
+                <el-select
+                  v-model="option.isabnormal"
+                  placeholder="閫夋嫨鐘舵��"
+                  style="width: 100%"
+                >
+                  <el-option
+                    v-for="status in abnormalOptions"
+                    :key="status.value"
+                    :label="status.label"
+                    :value="status.value"
+                  >
+                    <el-tag :type="status.type" size="small">{{ status.label }}</el-tag>
+                  </el-option>
+                </el-select>
+              </el-form-item>
+            </el-col>
+
+            <el-col :span="4">
+              <el-button
+                type="danger"
+                icon="el-icon-delete"
+                @click="removeOption(index)"
+                size="small"
+                circle
+                plain
+              />
+            </el-col>
+          </el-row>
+        </el-form>
+      </div>
+
+      <!-- <el-button
+        type="primary"
+        icon="el-icon-plus"
+        @click="addNewOption"
+        size="small"
+        plain
+        style="width: 100%; margin-top: 10px;"
+      >
+        娣诲姞閫夐」
+      </el-button> -->
+    </div>
+  </div>
+
+  <span slot="footer" class="dialog-footer">
+    <el-button @click="optionDialogVisible = false">鍙栨秷</el-button>
+    <el-button type="primary" @click="saveOptions" :loading="savingOptions">
+      淇濆瓨閰嶇疆
+    </el-button>
+  </span>
+</el-dialog>
+    <!-- 棰樼洰棰勮瀵硅瘽妗� -->
+    <el-dialog
+      title="棰樼洰棰勮"
+      :visible.sync="previewVisible"
+      width="600px"
+      center
+    >
+      <div v-if="currentPreview" class="preview-wrapper">
+        <div class="preview-header">
+          <h4>{{ currentPreview.scriptTopic || "鏃犱富棰�" }}</h4>
+          <div class="preview-tags">
+            <dict-tag
+              :options="askvaluetype"
+              :value="currentPreview.scriptType"
+              size="small"
+            />
+            <el-tag v-if="currentPreview.targetname" size="small" type="info">
+              {{ currentPreview.targetname }}
+            </el-tag>
+          </div>
+        </div>
+        <!-- 妯℃澘棰樼洰灞曠ず -->
+
+        <div class="preview-content" v-if="templateForm.templateType == 1">
+          <p class="preview-question">{{ currentPreview.scriptContent }}</p>
+
+          <div
+            v-if="
+              currentPreview.scriptType != 3 && currentPreview.scriptType != 4
+            "
+            class="preview-options"
+          >
+            <el-radio-group v-model="previewAnswer">
+              <el-radio
+                v-for="(
+                  option, idx
+                ) in currentPreview.svyLibTemplateTargetoptions || []"
+                :key="idx"
+                :label="option.optioncontent"
+                class="option-item"
+              >
+                {{ option.optioncontent }}
+              </el-radio>
+            </el-radio-group>
+          </div>
+
+          <div v-else class="preview-textarea">
+            <el-input
+              type="textarea"
+              placeholder="璇疯緭鍏ュ洖绛�"
+              v-model="previewAnswer"
+              :rows="4"
+            />
+          </div>
+        </div>
+        <!-- 璇煶棰樼洰灞曠ず -->
+        <div class="preview-content" v-else>
+          <p class="preview-question">{{ currentPreview.scriptContent }}</p>
+
+          <div
+            v-if="
+              currentPreview.scriptType != 3 && currentPreview.scriptType != 4
+            "
+            class="preview-options"
+          >
+            <el-radio-group v-model="previewAnswer">
+              <el-radio
+                v-for="(
+                  option, idx
+                ) in currentPreview.ivrLibaScriptTargetoptionList || []"
+                :key="idx"
+                :label="option.targetvalue"
+                class="option-item"
+              >
+                {{ option.targetvalue }}
+              </el-radio>
+            </el-radio-group>
+          </div>
+
+          <div v-else class="preview-textarea">
+            <el-input
+              type="textarea"
+              placeholder="璇疯緭鍏ュ洖绛�"
+              v-model="previewAnswer"
+              :rows="4"
+            />
+          </div>
+        </div>
+      </div>
+      <span slot="footer" class="dialog-footer">
+        <el-button @click="previewVisible = false">鍏抽棴</el-button>
+      </span>
+    </el-dialog>
+
+    <!-- 淇濆瓨鎴愬姛鎻愮ず -->
+    <el-dialog
+      title="淇濆瓨鎴愬姛"
+      :visible.sync="saveSuccessVisible"
+      width="400px"
+      center
+    >
+      <div class="success-content">
+        <i class="el-icon-success success-icon"></i>
+        <p class="success-text">閰嶇疆宸叉垚鍔熶繚瀛橈紒</p>
+      </div>
+      <span slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="saveSuccessVisible = false"
+          >纭畾</el-button
+        >
+      </span>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import {
+  compileissue,
+  compileQtemplate,
+  compileFollowup,
+  getQtemplatelist,
+  getFollowuplist,
+  getvFollowup,
+  getQtemplateobj,
+  selectInfoByConditiony,
+} from "@/api/AiCentre/index";
+import { deptTreeSelect } from "@/api/system/user";
+import store from "@/store";
+import Pagination from "@/components/Pagination";
+
+export default {
+  name: "SatisfactionExceptionConfig",
+  components: { Pagination },
+  data() {
+    return {
+      // 妯℃澘琛ㄥ崟
+      templateForm: {
+        templateType: "",
+        templateId: "",
+      },
+      templateRules: {
+        templateType: [
+          { required: true, message: "璇烽�夋嫨妯℃澘绫诲瀷", trigger: "change" },
+        ],
+      },
+      // 閫夐」绠$悊鐩稿叧
+      optionDialogVisible: false,
+      currentOptions: [],
+      editingQuestion: null,
+      optionRules: {
+        targetvalue: [
+          { required: true, message: "璇疯緭鍏ラ�夐」鍐呭", trigger: "blur" },
+        ],
+        isabnormal: [
+          { required: true, message: "璇烽�夋嫨寮傚父鐘舵��", trigger: "change" },
+        ],
+      },
+
+      // 寮傚父鐘舵�侀�夐」
+      abnormalOptions: [
+        { label: "姝e父", value: 0, type: "success" },
+        { label: "寮傚父", value: 1, type: "danger" },
+        { label: "璀﹀憡", value: 2, type: "warning" },
+      ],
+      // 妯℃澘閫夐」
+      questionnaireTemplates: [], // 闂嵎妯℃澘鍒楄〃
+      followupTemplates: [], // 璇煶妯℃澘鍒楄〃
+      templateOptionsLoading: false,
+
+      // 褰撳墠妯℃澘淇℃伅
+      currentTemplateInfo: null,
+      templateLoading: false,
+
+      // 鏌ヨ鍙傛暟
+      queryParams: {
+        scriptTopic: "",
+        scriptContent: "",
+      },
+
+      // 鏁版嵁鍒楄〃
+      questionList: [],
+      loading: false,
+      batchSaving: false,
+
+      // 瀛楀吀鏁版嵁
+      askvaluetype: store.getters.askvaluetype || [],
+      qyoptions: store.getters.usable || [],
+
+      // 绉戝閫夐」
+      deptOptions: [],
+
+      // 棰勮鐩稿叧
+      previewVisible: false,
+      currentPreview: null,
+      previewAnswer: "",
+
+      // 淇濆瓨鐩稿叧
+      saveSuccessVisible: false,
+      hasChanges: false,
+      changedCount: 0,
+
+      // 婊℃剰搴﹀垎绫籌D
+      satisfactionCategoryIds: ["404", "405", "406", "10039", "10041", "10042"],
+      questionnaireCategorys: [],
+      voiceCategories: [],
+      // 琛ㄥ崟楠岃瘉瑙勫垯
+      configRules: {
+        responsibilityDept: [
+          {
+            required: true,
+            message: "璇疯嚦灏戦�夋嫨涓�涓矗浠荤瀹�",
+            trigger: "change",
+          },
+          {
+            validator: (rule, value, callback) => {
+              if (!value || value.length === 0) {
+                callback(new Error("璇疯嚦灏戦�夋嫨涓�涓矗浠荤瀹�"));
+              } else {
+                callback();
+              }
+            },
+            trigger: "change",
+          },
+        ],
+        reportDept: [
+          {
+            required: true,
+            message: "璇疯嚦灏戦�夋嫨涓�涓姤澶囩瀹�",
+            trigger: "change",
+          },
+          {
+            validator: (rule, value, callback) => {
+              if (!value || value.length === 0) {
+                callback(new Error("璇疯嚦灏戦�夋嫨涓�涓姤澶囩瀹�"));
+              } else {
+                callback();
+              }
+            },
+            trigger: "change",
+          },
+        ],
+      },
+    };
+  },
+  computed: {
+    // 鏍规嵁妯℃澘绫诲瀷杩囨护妯℃澘閫夐」
+    filteredTemplateOptions() {
+      if (this.templateForm.templateType === 1) {
+        return this.questionnaireTemplates;
+      } else if (this.templateForm.templateType === 2) {
+        return this.followupTemplates;
+      }
+      return [];
+    },
+
+    // 婊℃剰搴﹂鐩暟閲�
+    satisfactionQuestionsCount() {
+      if (this.templateForm.templateType === 1) {
+        return this.questionList.filter((q) =>
+          this.questionnaireCategorys.includes(q.categoryid)
+        ).length;
+      } else if (this.templateForm.templateType === 2) {
+        return this.questionList.filter((q) =>
+          this.voiceCategories.includes(q.scriptAssortid)
+        ).length;
+      }
+    },
+    // 妫�鏌ラ鐩槸鍚︽湁寮傚父閫夐」
+    hasAbnormalOption(question) {
+      return (question) => {
+        if (!question) return false;
+
+        // 闂嵎妯℃澘
+        if (this.templateForm.templateType === 1) {
+          const options = question.svyLibTemplateTargetoptions || [];
+          return options.some((opt) => opt.isabnormal === 1);
+        }
+        // 璇煶妯℃澘
+        else if (this.templateForm.templateType === 2) {
+          const options = question.ivrLibaScriptTargetoptionList || [];
+          return options.some((opt) => opt.isabnormal === 1);
+        }
+
+        return false;
+      };
+    },
+    // 绛涢�夊悗鐨勯鐩垪琛�
+    filteredQuestionList() {
+      let filtered = this.questionList;
+      console.log(this.questionnaireCategorys);
+
+      // 绛涢�夋弧鎰忓害棰樼洰
+      if (this.templateForm.templateType === 1) {
+        filtered = filtered.filter((q) =>
+          this.questionnaireCategorys.includes(q.categoryid)
+        );
+      } else if (this.templateForm.templateType === 2) {
+        filtered = filtered.filter((q) =>
+          this.voiceCategories.includes(q.scriptAssortid)
+        );
+      }
+
+      // 搴旂敤鎼滅储鏉′欢
+      if (this.queryParams.scriptTopic) {
+        const keyword = this.queryParams.scriptTopic.toLowerCase();
+        filtered = filtered.filter(
+          (q) => q.scriptTopic && q.scriptTopic.toLowerCase().includes(keyword)
+        );
+      }
+
+      if (this.queryParams.scriptContent) {
+        const keyword = this.queryParams.scriptContent.toLowerCase();
+        filtered = filtered.filter(
+          (q) =>
+            q.scriptContent && q.scriptContent.toLowerCase().includes(keyword)
+        );
+      }
+
+      return filtered;
+    },
+  },
+  created() {
+    if (store.getters.satisfactionCategories) {
+      this.questionnaireCategorys =
+        store.getters.satisfactionCategories.questionnaireCategorys.map(
+          (item) => item.categoryid
+        );
+      this.voiceCategories =
+        store.getters.satisfactionCategories.voiceCategories.map(
+          (item) => item.categoryid
+        );
+    }
+    this.getDeptOptions();
+    this.loadAllTemplates();
+  },
+  methods: {
+    /** 鍔犺浇鎵�鏈夋ā鏉垮垪琛� */
+    loadAllTemplates() {
+      this.templateOptionsLoading = true;
+
+      // 骞惰鍔犺浇闂嵎妯℃澘鍜岃闊虫ā鏉�
+      Promise.all([
+        this.loadQuestionnaireTemplates(),
+        this.loadFollowupTemplates(),
+      ]).finally(() => {
+        this.templateOptionsLoading = false;
+      });
+    },
+
+    /** 鏌ヨ绉戝鍒楄〃 */
+    getDeptOptions() {
+      deptTreeSelect()
+        .then((res) => {
+          if (res.code == 200) {
+            this.deptOptions = this.flattenArray(res.data) || [];
+          }
+        })
+        .catch((error) => {
+          console.error("鑾峰彇绉戝鍒楄〃澶辫触:", error);
+          this.$message.error("鑾峰彇绉戝鍒楄〃澶辫触");
+        });
+    },
+
+    flattenArray(multiArray) {
+      let result = [];
+
+      function flatten(element) {
+        if (element.children && element.children.length > 0) {
+          element.children.forEach((child) => flatten(child));
+        } else {
+          let item = JSON.parse(JSON.stringify(element));
+          result.push(item);
+        }
+      }
+
+      multiArray.forEach((element) => flatten(element));
+      return result;
+    },
+
+    /** 鏍规嵁绉戝缂栫爜鑾峰彇绉戝鍚嶇О */
+    getDeptName(deptCode) {
+      if (!deptCode) return "";
+      const dept = this.deptOptions.find((d) => d.deptCode === deptCode);
+      return dept ? dept.label : deptCode;
+    },
+
+    /** 鏍规嵁绉戝缂栫爜鏁扮粍鑾峰彇绉戝鍚嶇О鏁扮粍 */
+    getDeptNames(deptCodes) {
+      if (!Array.isArray(deptCodes) || deptCodes.length === 0) return [];
+      return deptCodes
+        .map((code) => this.getDeptName(code))
+        .filter((name) => name && name.trim());
+    },
+
+    /** 妯℃澘绫诲瀷鍙樻洿 */
+    handleTemplateTypeChange() {
+      this.templateForm.templateId = "";
+      this.currentTemplateInfo = null;
+      this.questionList = [];
+    },
+
+    /** 鍔犺浇闂嵎妯℃澘鍒楄〃 */
+    loadQuestionnaireTemplates() {
+      return new Promise((resolve) => {
+        getQtemplatelist({ pageSize: 1000 })
+          .then((res) => {
+            if (res.code === 200) {
+              this.questionnaireTemplates = (res.rows || []).map((item) => ({
+                id: item.svyid,
+                templateName: item.svyname,
+                isavailable: item.isavailable,
+              }));
+            } else {
+              this.$message.error(res.msg || "鍔犺浇闂嵎妯℃澘澶辫触");
+            }
+            resolve();
+          })
+          .catch((error) => {
+            console.error("鍔犺浇闂嵎妯℃澘澶辫触:", error);
+            this.$message.error("鍔犺浇闂嵎妯℃澘澶辫触");
+            resolve();
+          });
+      });
+    },
+
+    /** 鍔犺浇璇煶妯℃澘鍒楄〃 */
+    loadFollowupTemplates() {
+      return new Promise((resolve) => {
+        getFollowuplist({ pageSize: 1000 })
+          .then((res) => {
+            if (res.code === 200) {
+              this.followupTemplates = (res.rows || []).map((item) => ({
+                id: item.id,
+                templateName: item.templateName,
+                isavailable: item.isavailable,
+              }));
+            } else {
+              this.$message.error(res.msg || "鍔犺浇璇煶妯℃澘澶辫触");
+            }
+            resolve();
+          })
+          .catch((error) => {
+            console.error("鍔犺浇璇煶妯℃澘澶辫触:", error);
+            this.$message.error("鍔犺浇璇煶妯℃澘澶辫触");
+            resolve();
+          });
+      });
+    },
+
+    /** 妯℃澘閫夋嫨鍙樻洿 */
+    handleTemplateChange(templateId) {
+      if (templateId) {
+        const selectedTemplate = this.filteredTemplateOptions.find(
+          (t) => t.id === templateId
+        );
+        if (selectedTemplate) {
+          this.currentTemplateInfo = {
+            templateName: selectedTemplate.templateName,
+            templateStatus: selectedTemplate.isavailable,
+            questionCount: 0,
+          };
+        }
+        // 鍔犺浇妯℃澘璇︽儏鏁版嵁
+        this.templateLoading = true;
+        this.loading = true;
+        this.questionList = [];
+
+        if (this.templateForm.templateType === 1) {
+          this.loadQuestionnaireTemplateDetail();
+        } else if (this.templateForm.templateType === 2) {
+          this.loadFollowupTemplateDetail();
+        }
+      } else {
+        this.currentTemplateInfo = null;
+        this.questionList = [];
+      }
+    },
+
+    /** 鍔犺浇妯℃澘璇︽儏鍜岄鐩� */
+    handleLoadTemplate() {
+      this.$refs.templateForm.validate((valid) => {
+        if (!valid) {
+          this.$message.warning("璇峰厛閫夋嫨妯℃澘");
+          return;
+        }
+
+        this.templateLoading = true;
+        this.loading = true;
+        this.questionList = [];
+
+        if (this.templateForm.templateType === 1) {
+          this.loadQuestionnaireTemplateDetail();
+        } else if (this.templateForm.templateType === 2) {
+          this.loadFollowupTemplateDetail();
+        }
+      });
+    },
+
+    /** 鍔犺浇闂嵎妯℃澘璇︽儏 */
+    loadQuestionnaireTemplateDetail() {
+      getQtemplateobj({ svyid: this.templateForm.templateId })
+        .then((res) => {
+          this.templateLoading = false;
+          this.loading = false;
+
+          if (res.code === 200 && res.rows && res.rows.length > 0) {
+            const templateDetail = res.rows[0];
+
+            // 鏇存柊妯℃澘淇℃伅
+            this.currentTemplateInfo = {
+              ...templateDetail,
+              templateName: templateDetail.svyname,
+              templateStatus: templateDetail.isavailable,
+              questionCount: templateDetail.svyTemplateLibScripts?.length || 0,
+            };
+
+            // 鎻愬彇棰樼洰鍒楄〃
+            const questions = templateDetail.svyTemplateLibScripts || [];
+            this.processQuestions(questions);
+
+            this.$message.success(`鎴愬姛鍔犺浇 ${questions.length} 涓鐩甡);
+          } else {
+            this.$message.error(res.msg || "鍔犺浇妯℃澘璇︽儏澶辫触");
+          }
+        })
+        .catch((error) => {
+          this.templateLoading = false;
+          this.loading = false;
+          console.error("鍔犺浇闂嵎妯℃澘璇︽儏澶辫触:", error);
+          this.$message.error("鍔犺浇妯℃澘璇︽儏澶辫触");
+        });
+    },
+
+    /** 鍔犺浇璇煶妯℃澘璇︽儏 */
+    loadFollowupTemplateDetail() {
+      getvFollowup({ id: this.templateForm.templateId })
+        .then((res) => {
+          this.templateLoading = false;
+          this.loading = false;
+
+          if (res.code === 200) {
+            const templateDetail = res.data;
+
+            // 鏇存柊妯℃澘淇℃伅
+            this.currentTemplateInfo = {
+              ...this.currentTemplateInfo,
+              templateName: templateDetail.templateName,
+              templateStatus: templateDetail.isavailable,
+              questionCount:
+                templateDetail.ivrLibaTemplateScriptVOList?.length || 0,
+            };
+
+            // 鎻愬彇棰樼洰鍒楄〃
+            const questions = templateDetail.ivrLibaTemplateScriptVOList || [];
+            this.processQuestions(questions);
+
+            this.$message.success(`鎴愬姛鍔犺浇 ${questions.length} 涓鐩甡);
+          } else {
+            this.$message.error(res.msg || "鍔犺浇妯℃澘璇︽儏澶辫触");
+          }
+        })
+        .catch((error) => {
+          this.templateLoading = false;
+          this.loading = false;
+          console.error("鍔犺浇璇煶妯℃澘璇︽儏澶辫触:", error);
+          this.$message.error("鍔犺浇妯℃澘璇︽儏澶辫触");
+        });
+    },
+
+    /** 澶勭悊棰樼洰鏁版嵁 */
+    processQuestions(questions) {
+      this.questionList = questions.map((question) => {
+        // 瑙f瀽璐d换绉戝鍜屾姤澶囩瀹�
+        let exceptionConfig = {
+          responsibilityDept: [], // 璐d换绉戝缂栫爜鏁扮粍
+          reportDept: [], // 鎶ュ绉戝缂栫爜鏁扮粍
+        };
+
+        // 浠庨鐩《灞傚瓧娈佃鍙栨暟鎹�
+        if (question.dutyDeptCode) {
+          // 浠庨�楀彿鍒嗛殧鐨勫瓧绗︿覆杞负鏁扮粍
+          exceptionConfig.responsibilityDept = question.dutyDeptCode
+            .split(",")
+            .map((code) => code.trim())
+            .filter((code) => code);
+        }
+
+        if (question.reportDeptCode) {
+          exceptionConfig.reportDept = question.reportDeptCode
+            .split(",")
+            .map((code) => code.trim())
+            .filter((code) => code);
+        }
+
+        return {
+          ...question,
+          // 缁熶竴瀛楁鍚�
+          id: question.id || question.scriptId,
+          scriptTopic: question.scriptTopic || question.scriptTopic,
+          scriptContent: question.scriptContent || question.scriptContent,
+          scriptType: question.scriptType,
+          isavailable: question.isavailable,
+          targetname: question.targetname,
+          categoryid: question.categoryid || question.categoryid,
+          originalConfig: JSON.parse(JSON.stringify(exceptionConfig)),
+          exceptionConfig: exceptionConfig,
+          hasChanges: false,
+          saving: false,
+          saveStatus: null,
+        };
+      });
+
+      this.updateChangedStatus();
+    },
+
+    /** 閲嶇疆妯℃澘閫夋嫨 */
+    handleResetTemplate() {
+      this.templateForm = {
+        templateType: "",
+        templateId: "",
+      };
+      this.currentTemplateInfo = null;
+      this.questionList = [];
+      this.resetQuery();
+      this.$refs.templateForm?.clearValidate();
+    },
+
+    /** 閰嶇疆鍙樻洿澶勭悊 */
+    handleConfigChange(question) {
+      this.$nextTick(() => {
+        const index = this.filteredQuestionList.findIndex(
+          (q) => q.id === question.id
+        );
+        if (index !== -1) {
+          const formRef = this.$refs.configForm && this.$refs.configForm[index];
+          if (formRef) {
+            formRef.validate((valid) => {
+              if (valid) {
+                question.hasChanges = !this.isConfigEqual(
+                  question.exceptionConfig,
+                  question.originalConfig
+                );
+                this.updateChangedStatus();
+              }
+            });
+          }
+        }
+      });
+    },
+
+    /** 姣旇緝閰嶇疆鏄惁鏀瑰彉 */
+    isConfigEqual(config1, config2) {
+      if (!config1 || !config2) return false;
+
+      const responsibility1 = [...(config1.responsibilityDept || [])]
+        .sort()
+        .join(",")
+        .toLowerCase();
+      const responsibility2 = [...(config2.responsibilityDept || [])]
+        .sort()
+        .join(",")
+        .toLowerCase();
+      const report1 = [...(config1.reportDept || [])]
+        .sort()
+        .join(",")
+        .toLowerCase();
+      const report2 = [...(config2.reportDept || [])]
+        .sort()
+        .join(",")
+        .toLowerCase();
+
+      return responsibility1 === responsibility2 && report1 === report2;
+    },
+
+    /** 鏇存柊鍙樻洿鐘舵�� */
+    updateChangedStatus() {
+      const changedItems = this.questionList.filter((q) => q.hasChanges);
+      this.changedCount = changedItems.length;
+      this.hasChanges = changedItems.length > 0;
+    },
+
+    /** 淇濆瓨鍗曚釜棰樼洰閰嶇疆 */
+    async saveSingleConfig(question) {
+      if (!question.hasChanges) return;
+
+      const index = this.filteredQuestionList.findIndex(
+        (q) => q.id === question.id
+      );
+      console.log(index, "filteredQuestionList");
+
+      if (index === -1) return;
+
+      const formRef = this.$refs.configForm && this.$refs.configForm[index];
+      if (!formRef) return;
+
+      const valid = await formRef.validate();
+      if (!valid) {
+        this.$message.warning("璇峰厛瀹屾垚蹇呭~椤�");
+        return;
+      }
+
+      question.saving = true;
+      question.saveStatus = null;
+
+      try {
+        // 鑾峰彇褰撳墠妯℃澘璇︽儏
+        let templateDetail;
+        if (this.templateForm.templateType === 1) {
+          // 闂嵎妯℃澘
+          const res = await getQtemplateobj({
+            svyid: this.templateForm.templateId,
+          });
+          if (res.code !== 200 || !res.rows || res.rows.length === 0) {
+            throw new Error(res.msg || "鑾峰彇妯℃澘璇︽儏澶辫触");
+          }
+          templateDetail = res.rows[0];
+        } else if (this.templateForm.templateType === 2) {
+          // 璇煶妯℃澘
+          const res = await getvFollowup({ id: this.templateForm.templateId });
+          if (res.code !== 200) {
+            throw new Error(res.msg || "鑾峰彇妯℃澘璇︽儏澶辫触");
+          }
+          templateDetail = res.data;
+        }
+
+        // 鏇存柊棰樼洰閰嶇疆
+        let updatedTemplateDetail = { ...templateDetail };
+        let questionsField =
+          this.templateForm.templateType === 1
+            ? "svyTemplateLibScripts"
+            : "ivrLibaTemplateScriptVOList";
+
+        const questions = updatedTemplateDetail[questionsField] || [];
+        const questionIndex = questions.findIndex((q) => q.id === question.id);
+
+        if (questionIndex === -1) {
+          throw new Error("鏈壘鍒伴鐩�");
+        }
+
+        // 鑾峰彇绉戝鍚嶇О
+        const responsibilityDeptNames = this.getDeptNames(
+          question.exceptionConfig.responsibilityDept
+        );
+        const reportDeptNames = this.getDeptNames(
+          question.exceptionConfig.reportDept
+        );
+
+        // 鐩存帴鏇存柊棰樼洰椤跺眰瀛楁
+        questions[questionIndex] = {
+          ...questions[questionIndex],
+          // 璁剧疆Excel瑕佹眰鐨勫瓧娈�
+          dutyDeptCode: question.exceptionConfig.responsibilityDept.join(","),
+          dutyDeptName: responsibilityDeptNames.join(","),
+          reportDeptCode: question.exceptionConfig.reportDept.join(","),
+          reportDeptName: reportDeptNames.join(","),
+        };
+
+        // 鏇存柊妯℃澘
+        updatedTemplateDetail[questionsField] = questions;
+
+        // 淇濆瓨妯℃澘
+        let response;
+        if (this.templateForm.templateType === 1) {
+          response = await compileQtemplate({
+            ...updatedTemplateDetail,
+            id: this.templateForm.templateId,
+            isoperation: 2,
+          });
+        } else {
+          response = await compileFollowup({
+            ...updatedTemplateDetail,
+            id: this.templateForm.templateId,
+            isoperation: 2,
+          });
+        }
+
+        if (response.code === 200) {
+          this.handleSaveSuccess(question);
+        } else {
+          throw new Error(response.msg || "淇濆瓨澶辫触");
+        }
+      } catch (error) {
+        console.error("淇濆瓨澶辫触:", error);
+        question.saveStatus = {
+          type: "error",
+          message: error.message || "淇濆瓨澶辫触锛岃绋嶅悗閲嶈瘯",
+        };
+        this.$message.error(error.message || "淇濆瓨澶辫触锛岃绋嶅悗閲嶈瘯");
+      } finally {
+        question.saving = false;
+      }
+    },
+
+    /** 澶勭悊淇濆瓨鎴愬姛 */
+    /** 澶勭悊淇濆瓨鎴愬姛 */
+    handleSaveSuccess(question) {
+      // 鍚屾椂鏇存柊棰樼洰椤跺眰瀛楁
+      const responsibilityDeptNames = this.getDeptNames(
+        question.exceptionConfig.responsibilityDept
+      );
+      const reportDeptNames = this.getDeptNames(
+        question.exceptionConfig.reportDept
+      );
+
+      // 鏇存柊棰樼洰鏈韩鐨勫瓧娈�
+      question.dutyDeptCode =
+        question.exceptionConfig.responsibilityDept.join(",");
+      question.dutyDeptName = responsibilityDeptNames.join(",");
+      question.reportDeptCode = question.exceptionConfig.reportDept.join(",");
+      question.reportDeptName = reportDeptNames.join(",");
+
+      // 鏇存柊鍘熷閰嶇疆
+      question.originalConfig = JSON.parse(
+        JSON.stringify(question.exceptionConfig)
+      );
+      question.hasChanges = false;
+      question.saveStatus = {
+        type: "success",
+        message: "閰嶇疆淇濆瓨鎴愬姛",
+      };
+
+      this.updateChangedStatus();
+      this.$message.success("閰嶇疆淇濆瓨鎴愬姛");
+
+      // 5绉掑悗娓呴櫎鎴愬姛鎻愮ず
+      setTimeout(() => {
+        question.saveStatus = null;
+      }, 5000);
+    },
+
+    /** 閲嶇疆鍗曚釜棰樼洰閰嶇疆 */
+    resetSingleConfig(question) {
+      this.$confirm("纭畾瑕侀噸缃綋鍓嶉鐩殑閰嶇疆鍚楋紵", "鎻愮ず", {
+        confirmButtonText: "纭畾",
+        cancelButtonText: "鍙栨秷",
+        type: "warning",
+      })
+        .then(() => {
+          question.exceptionConfig = JSON.parse(
+            JSON.stringify(question.originalConfig)
+          );
+          // 鍚屾椂閲嶇疆棰樼洰椤跺眰瀛楁
+          const responsibilityDeptNames = this.getDeptNames(
+            question.exceptionConfig.responsibilityDept
+          );
+          const reportDeptNames = this.getDeptNames(
+            question.exceptionConfig.reportDept
+          );
+
+          question.dutyDeptCode =
+            question.exceptionConfig.responsibilityDept.join(",");
+          question.dutyDeptName = responsibilityDeptNames.join(",");
+          question.reportDeptCode =
+            question.exceptionConfig.reportDept.join(",");
+          question.reportDeptName = reportDeptNames.join(",");
+
+          question.hasChanges = false;
+          question.saveStatus = null;
+          this.updateChangedStatus();
+          this.$message.success("閰嶇疆宸查噸缃�");
+        })
+        .catch(() => {});
+    },
+
+    /** 鎵归噺淇濆瓨閰嶇疆 */
+    async handleBatchSave() {
+      if (!this.hasChanges || this.batchSaving) return;
+
+      this.$confirm("纭畾瑕佷繚瀛樻墍鏈変慨鏀硅繃鐨勯厤缃悧锛�", "鎵归噺淇濆瓨", {
+        confirmButtonText: "纭畾",
+        cancelButtonText: "鍙栨秷",
+        type: "warning",
+      })
+        .then(async () => {
+          this.batchSaving = true;
+
+          const changedQuestions = this.questionList.filter(
+            (q) => q.hasChanges
+          );
+          const results = [];
+
+          for (const question of changedQuestions) {
+            try {
+              await this.saveSingleConfig(question);
+              results.push({
+                id: question.id,
+                success:
+                  !question.hasChanges &&
+                  question.saveStatus?.type === "success",
+              });
+            } catch (error) {
+              results.push({
+                id: question.id,
+                success: false,
+              });
+            }
+          }
+
+          this.batchSaving = false;
+
+          const successCount = results.filter((r) => r.success).length;
+          const failCount = results.length - successCount;
+
+          if (failCount === 0) {
+            this.saveSuccessVisible = true;
+            this.$message.success(`鎴愬姛淇濆瓨 ${successCount} 涓厤缃甡);
+          } else {
+            this.$message.warning(
+              `鎴愬姛淇濆瓨 ${successCount} 涓紝澶辫触 ${failCount} 涓猔
+            );
+          }
+        })
+        .catch(() => {
+          this.batchSaving = false;
+        });
+    },
+
+    /** 棰勮棰樼洰 */
+    previewQuestion(question) {
+      this.currentPreview = { ...question };
+      this.previewAnswer = "";
+      this.previewVisible = true;
+    },
+    /** 妫�鏌ラ鐩槸鍚︽湁寮傚父閫夐」 */
+    checkHasAbnormalOptions(question) {
+      if (this.templateForm.templateType === 1) {
+        return (question.svyLibTemplateTargetoptions || []).some(
+          (opt) => opt.isabnormal === 1
+        );
+      } else if (this.templateForm.templateType === 2) {
+        return (question.ivrLibaScriptTargetoptionList || []).some(
+          (opt) => opt.isabnormal === 1
+        );
+      }
+      return false;
+    },
+
+    /** 鎵撳紑閫夐」绠$悊瀵硅瘽妗� */
+    openOptionDialog(question) {
+      this.editingQuestion = question;
+
+      // 澶嶅埗閫夐」鏁版嵁
+      if (this.templateForm.templateType === 1) {
+        this.currentOptions = JSON.parse(
+          JSON.stringify(question.svyLibTemplateTargetoptions || [])
+        ).map((opt) => ({
+          ...opt,
+          id: opt.id,
+          targetvalue: opt.optioncontent || "",
+          isabnormal: opt.isabnormal || 0,
+        }));
+      } else if (this.templateForm.templateType === 2) {
+        this.currentOptions = JSON.parse(
+          JSON.stringify(question.ivrLibaScriptTargetoptionList || [])
+        ).map((opt) => ({
+          ...opt,
+          targetvalue: opt.targetvalue || "",
+          isabnormal: opt.isabnormal || 0,
+        }));
+      }
+
+      this.optionDialogVisible = true;
+    },
+
+    /** 娣诲姞鏂伴�夐」 */
+    addNewOption() {
+      this.currentOptions.push({
+        id: Date.now(), // 涓存椂ID
+        targetvalue: "",
+        isabnormal: 0,
+        isNew: true,
+      });
+    },
+
+    /** 鍒犻櫎閫夐」 */
+    removeOption(index) {
+      this.currentOptions.splice(index, 1);
+    },
+
+    /** 淇濆瓨閫夐」閰嶇疆 */
+    async saveOptions() {
+      try {
+        // 楠岃瘉蹇呭~椤�
+        for (const option of this.currentOptions) {
+          if (!option.targetvalue || option.targetvalue.trim() === "") {
+            this.$message.warning("璇峰~鍐欐墍鏈夐�夐」鍐呭");
+            return;
+          }
+        }
+
+        // 妫�鏌ユ槸鍚︽湁寮傚父閫夐」
+        const hasAbnormal = this.currentOptions.some(
+          (opt) => opt.isabnormal === 1
+        );
+
+        if (!hasAbnormal) {
+          this.$message.warning("璇疯嚦灏戣缃竴涓紓甯搁�夐」锛坕sabnormal=1锛�");
+          return;
+        }
+
+        // 淇濆瓨閫昏緫 - 鏇存柊棰樼洰瀵硅薄鐨勯�夐」鏁版嵁
+        if (this.templateForm.templateType === 1) {
+          this.editingQuestion.svyLibTemplateTargetoptions =
+            this.currentOptions.map((opt) => ({
+              ...opt,
+              optioncontent: opt.targetvalue,
+              isabnormal: opt.isabnormal,
+            }));
+        } else if (this.templateForm.templateType === 2) {
+          this.editingQuestion.ivrLibaScriptTargetoptionList =
+            this.currentOptions;
+        }
+
+        // 瑙﹀彂閰嶇疆鍙樻洿妫�鏌�
+        this.handleConfigChange(this.editingQuestion);
+
+        this.$message.success("閫夐」閰嶇疆淇濆瓨鎴愬姛");
+        this.optionDialogVisible = false;
+      } catch (error) {
+        console.error("淇濆瓨閫夐」澶辫触:", error);
+        this.$message.error("淇濆瓨閫夐」澶辫触");
+      }
+    },
+
+    /** 淇敼淇濆瓨鍗曚釜棰樼洰閰嶇疆鏂规硶锛屾坊鍔犲紓甯搁�夐」妫�鏌� */
+    async saveSingleConfig(question) {
+      // 妫�鏌ユ槸鍚︽湁寮傚父閫夐」
+      if (!this.checkHasAbnormalOptions(question)) {
+        this.$confirm("璇ラ鐩病鏈夎缃紓甯搁�夐」锛屾槸鍚﹀厛閰嶇疆閫夐」锛�", "鎻愮ず", {
+          confirmButtonText: "鍘婚厤缃�",
+          cancelButtonText: "鍙栨秷",
+          type: "warning",
+        })
+          .then(() => {
+            this.openOptionDialog(question);
+          })
+          .catch(() => {});
+        return;
+      }
+
+      // 鍘熸湁鐨勪繚瀛橀�昏緫...
+      if (!question.hasChanges) return;
+
+      const index = this.filteredQuestionList.findIndex(
+        (q) => q.id === question.id
+      );
+
+      if (index === -1) return;
+
+      const formRef = this.$refs.configForm && this.$refs.configForm[index];
+      if (!formRef) return;
+
+      const valid = await formRef.validate();
+      if (!valid) {
+        this.$message.warning("璇峰厛瀹屾垚蹇呭~椤�");
+        return;
+      }
+
+      // 缁х画鍘熸湁鐨勪繚瀛橀�昏緫...
+      question.saving = true;
+      question.saveStatus = null;
+
+      try {
+        // ... 鍘熸湁鐨勪繚瀛橀�昏緫涓嶅彉
+      } catch (error) {
+        // ... 閿欒澶勭悊涓嶅彉
+      } finally {
+        question.saving = false;
+      }
+    },
+
+    /** 鎵归噺淇濆瓨鏃朵篃瑕佹鏌� */
+    async handleBatchSave() {
+      if (!this.hasChanges || this.batchSaving) return;
+
+      // 妫�鏌ユ墍鏈夋湁鍙樻洿鐨勯鐩槸鍚﹂兘鏈夊紓甯搁�夐」
+      const changedQuestions = this.questionList.filter((q) => q.hasChanges);
+      const questionsWithoutAbnormal = changedQuestions.filter(
+        (q) => !this.checkHasAbnormalOptions(q)
+      );
+
+      if (questionsWithoutAbnormal.length > 0) {
+        this.$confirm(
+          `鏈� ${questionsWithoutAbnormal.length} 涓鐩病鏈夎缃紓甯搁�夐」锛岃鍏堥厤缃�夐」銆傛槸鍚︾户缁紵`,
+          "鎻愮ず",
+          {
+            confirmButtonText: "缁х画",
+            cancelButtonText: "鍘婚厤缃�",
+            type: "warning",
+          }
+        )
+          .then(() => {
+            // 缁х画鎵ц鎵归噺淇濆瓨
+            this.executeBatchSave(changedQuestions);
+          })
+          .catch(() => {
+            // 鍙互鍦ㄨ繖閲岃烦杞埌绗竴涓病鏈夊紓甯搁�夐」鐨勯鐩�
+            if (questionsWithoutAbnormal.length > 0) {
+              this.openOptionDialog(questionsWithoutAbnormal[0]);
+            }
+          });
+      } else {
+        this.executeBatchSave(changedQuestions);
+      }
+    },
+
+    /** 鎵ц鎵归噺淇濆瓨 */
+    async executeBatchSave(changedQuestions) {
+      this.$confirm("纭畾瑕佷繚瀛樻墍鏈変慨鏀硅繃鐨勯厤缃悧锛�", "鎵归噺淇濆瓨", {
+        confirmButtonText: "纭畾",
+        cancelButtonText: "鍙栨秷",
+        type: "warning",
+      })
+        .then(async () => {
+          this.batchSaving = true;
+
+          const results = [];
+          for (const question of changedQuestions) {
+            try {
+              // 杩欓噷璋冪敤淇敼鍚庣殑saveSingleConfig鏂规硶
+              await this.saveSingleConfig(question);
+              results.push({
+                id: question.id,
+                success:
+                  !question.hasChanges &&
+                  question.saveStatus?.type === "success",
+              });
+            } catch (error) {
+              results.push({
+                id: question.id,
+                success: false,
+              });
+            }
+          }
+
+          this.batchSaving = false;
+          // ... 鍚庣画澶勭悊涓嶅彉
+        })
+        .catch(() => {
+          this.batchSaving = false;
+        });
+    },
+
+    /** 鑾峰彇寮傚父閫夐」缁熻 */
+    getAbnormalStats(question) {
+      if (this.templateForm.templateType === 1) {
+        const options = question.svyLibTemplateTargetoptions || [];
+        return {
+          total: options.length,
+          abnormal: options.filter((opt) => opt.isabnormal === 1).length,
+          warning: options.filter((opt) => opt.isabnormal === 2).length,
+          normal: options.filter((opt) => opt.isabnormal === 0).length,
+        };
+      } else if (this.templateForm.templateType === 2) {
+        const options = question.ivrLibaScriptTargetoptionList || [];
+        return {
+          total: options.length,
+          abnormal: options.filter((opt) => opt.isabnormal === 1).length,
+          warning: options.filter((opt) => opt.isabnormal === 2).length,
+          normal: options.filter((opt) => opt.isabnormal === 0).length,
+        };
+      }
+      return { total: 0, abnormal: 0, warning: 0, normal: 0 };
+    },
+    /** 鎼滅储 */
+    handleQuery() {
+      // 浠呯瓫閫夋樉绀猴紝涓嶉渶瑕侀噸鏂板姞杞�
+    },
+
+    /** 閲嶇疆鎼滅储 */
+    resetQuery() {
+      this.queryParams = {
+        scriptTopic: "",
+        scriptContent: "",
+      };
+    },
+  },
+};
+</script>
+
+<style lang="scss" scoped>
+.satisfaction-exception-config {
+  min-height: 100%;
+  background-color: #f5f7fa;
+  padding: 20px;
+
+  .page-header {
+    margin-bottom: 20px;
+    padding: 20px;
+    background: linear-gradient(135deg, #409eff 0%, #66b1ff 100%);
+    border-radius: 8px;
+    color: white;
+
+    .header-content {
+      .page-title {
+        margin: 0 0 8px 0;
+        font-size: 20px;
+        font-weight: 600;
+      }
+
+      .page-description {
+        margin: 0;
+        opacity: 0.9;
+        font-size: 14px;
+      }
+    }
+  }
+
+  .template-section {
+    margin-bottom: 20px;
+
+    .template-header {
+      margin-bottom: 20px;
+
+      .template-title {
+        margin: 0 0 8px 0;
+        font-size: 16px;
+        font-weight: 600;
+        color: #303133;
+      }
+
+      .template-tip {
+        margin: 0;
+        color: #909399;
+        font-size: 13px;
+      }
+    }
+
+    .select-loading {
+      text-align: center;
+      padding: 10px;
+      color: #909399;
+
+      i {
+        margin-right: 8px;
+      }
+    }
+  }
+
+  .template-info-section {
+    margin-bottom: 20px;
+
+    .template-info {
+      display: flex;
+      justify-content: space-between;
+      align-items: center;
+      padding: 5px 0;
+
+      .info-left {
+        .template-name {
+          margin: 0 0 10px 0;
+          font-size: 18px;
+          font-weight: 600;
+          color: #303133;
+        }
+
+        .template-meta {
+          display: flex;
+          gap: 20px;
+          flex-wrap: wrap;
+
+          .meta-item {
+            display: flex;
+            align-items: center;
+            gap: 5px;
+            font-size: 13px;
+            color: #606266;
+
+            i {
+              font-size: 14px;
+            }
+          }
+        }
+      }
+    }
+  }
+
+  .search-section {
+    margin-bottom: 20px;
+
+    .search-container {
+      border-radius: 8px;
+
+      .el-form {
+        display: flex;
+        flex-wrap: wrap;
+        gap: 16px;
+        align-items: center;
+      }
+    }
+  }
+
+  .config-content {
+    .batch-actions-card {
+      margin-bottom: 20px;
+
+      .batch-actions {
+        display: flex;
+        align-items: center;
+        gap: 20px;
+        padding: 8px 0;
+
+        .change-count {
+          color: #e6a23c;
+          font-size: 14px;
+          font-weight: 500;
+        }
+
+        .total-count {
+          margin-left: auto;
+          color: #909399;
+          font-size: 14px;
+        }
+      }
+    }
+
+    .loading-wrapper {
+      display: flex;
+      justify-content: center;
+      align-items: center;
+      min-height: 400px;
+
+      .loading-spinner {
+        text-align: center;
+        color: #409eff;
+
+        i {
+          font-size: 24px;
+          margin-right: 8px;
+        }
+
+        span {
+          font-size: 16px;
+        }
+      }
+    }
+
+    .empty-wrapper {
+      min-height: 400px;
+      display: flex;
+      flex-direction: column;
+      align-items: center;
+      justify-content: center;
+
+      .empty-tip {
+        margin-top: 10px;
+        color: #909399;
+        font-size: 13px;
+        text-align: center;
+      }
+    }
+
+    .question-list {
+      display: flex;
+      flex-direction: column;
+      gap: 16px;
+    }
+
+    .question-item {
+      .question-card {
+        border-radius: 8px;
+        border: 1px solid #ebeef5;
+        transition: all 0.3s ease;
+
+        &.has-changes {
+          border-color: #409eff;
+          box-shadow: 0 2px 12px 0 rgba(64, 158, 255, 0.1);
+        }
+
+        &:hover {
+          box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
+        }
+
+        .card-header {
+          display: flex;
+          justify-content: space-between;
+          align-items: flex-start;
+          margin-bottom: 20px;
+          padding-bottom: 20px;
+          border-bottom: 1px solid #f0f0f0;
+
+          .header-left {
+            display: flex;
+            gap: 20px;
+            flex: 1;
+
+            .question-index {
+              display: flex;
+              flex-direction: column;
+              align-items: center;
+              min-width: 40px;
+
+              .index-number {
+                display: flex;
+                align-items: center;
+                justify-content: center;
+                width: 32px;
+                height: 32px;
+                background: #409eff;
+                color: white;
+                border-radius: 50%;
+                font-size: 14px;
+                font-weight: 600;
+                margin-bottom: 8px;
+              }
+
+              .index-line {
+                width: 2px;
+                height: 100%;
+                background: #e0e0e0;
+                border-radius: 1px;
+              }
+            }
+
+            .question-basic-info {
+              flex: 1;
+
+              .question-title-section {
+                margin-bottom: 12px;
+
+                .question-topic {
+                  margin: 0 0 8px 0;
+                  font-size: 16px;
+                  font-weight: 600;
+                  color: #303133;
+                  line-height: 1.4;
+                }
+
+                .question-tags {
+                  display: flex;
+                  gap: 8px;
+                  flex-wrap: wrap;
+                }
+              }
+
+              .question-content-section {
+                display: flex;
+                align-items: flex-start;
+                gap: 8px;
+
+                .content-label {
+                  color: #606266;
+                  font-size: 13px;
+                  font-weight: 500;
+                  min-width: 80px;
+                }
+
+                .content-text {
+                  color: #303133;
+                  font-size: 13px;
+                  line-height: 1.6;
+                  flex: 1;
+                }
+              }
+            }
+          }
+
+          .header-right {
+            display: flex;
+            flex-direction: column;
+            align-items: flex-end;
+            gap: 8px;
+
+            .option-status {
+              .status-tag {
+                cursor: default;
+
+                i {
+                  margin-right: 4px;
+                }
+              }
+            }
+          }
+        }
+
+        .config-section {
+          .config-title {
+            display: flex;
+            align-items: center;
+            gap: 8px;
+            margin-bottom: 20px;
+            padding: 8px 12px;
+            background: #f8f9fa;
+            border-radius: 4px;
+
+            i {
+              color: #409eff;
+              font-size: 16px;
+            }
+
+            span {
+              color: #303133;
+              font-weight: 600;
+              font-size: 14px;
+            }
+          }
+
+          .config-form {
+            .config-fields {
+              display: grid;
+              grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
+              gap: 20px;
+              margin-bottom: 20px;
+
+              .config-field {
+                .config-item {
+                  margin-bottom: 0;
+
+                  :deep(.el-form-item__label) {
+                    font-weight: 500;
+                    color: #606266;
+                    padding-right: 12px;
+                  }
+
+                  .config-tip {
+                    font-size: 12px;
+                    color: #909399;
+                    margin-top: 4px;
+                    line-height: 1.4;
+                  }
+                }
+              }
+            }
+
+            .current-config {
+              margin-bottom: 20px;
+              padding: 15px;
+              background: #f0f9ff;
+              border-radius: 6px;
+              border: 1px solid #d0ebff;
+
+              .config-preview {
+                .preview-item {
+                  display: flex;
+                  align-items: flex-start;
+                  margin-bottom: 8px;
+
+                  &:last-child {
+                    margin-bottom: 0;
+                  }
+
+                  .preview-label {
+                    font-size: 13px;
+                    color: #606266;
+                    font-weight: 500;
+                    min-width: 80px;
+                  }
+
+                  .preview-value {
+                    font-size: 13px;
+                    color: #303133;
+                    line-height: 1.5;
+                    flex: 1;
+                  }
+                }
+              }
+            }
+
+            .config-footer {
+              display: flex;
+              justify-content: space-between;
+              align-items: center;
+              padding-top: 20px;
+              border-top: 1px dashed #dcdfe6;
+
+              .save-status {
+                flex: 1;
+                margin-right: 20px;
+
+                .el-alert {
+                  padding: 8px 16px;
+                  border-radius: 4px;
+                }
+              }
+
+              .config-actions {
+                display: flex;
+                align-items: center;
+                gap: 12px;
+                flex-shrink: 0;
+
+                .el-button {
+                  min-width: 100px;
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+
+  .preview-wrapper {
+    .preview-header {
+      margin-bottom: 20px;
+
+      h4 {
+        margin: 0 0 12px 0;
+        color: #303133;
+        font-size: 18px;
+        font-weight: 600;
+      }
+
+      .preview-tags {
+        display: flex;
+        gap: 8px;
+        flex-wrap: wrap;
+      }
+    }
+
+    .preview-content {
+      .preview-question {
+        margin-bottom: 20px;
+        padding: 16px;
+        background: #f8f9fa;
+        border-radius: 4px;
+        color: #606266;
+        line-height: 1.6;
+      }
+
+      .preview-options {
+        .option-item {
+          display: block;
+          margin-bottom: 12px;
+          padding: 12px;
+          border-radius: 4px;
+          border: 1px solid #ebeef5;
+          transition: all 0.3s;
+
+          &:hover {
+            background: #f5f7fa;
+            border-color: #409eff;
+          }
+
+          &:last-child {
+            margin-bottom: 0;
+          }
+        }
+      }
+
+      .preview-textarea {
+        .el-textarea__inner {
+          resize: none;
+        }
+      }
+    }
+  }
+
+  .success-content {
+    text-align: center;
+    padding: 20px 0;
+
+    .success-icon {
+      color: #67c23a;
+      font-size: 48px;
+      margin-bottom: 20px;
+    }
+
+    .success-text {
+      font-size: 16px;
+      color: #606266;
+      margin: 0;
+    }
+  }
+}
+.option-config-wrapper {
+  .dialog-header {
+    margin-bottom: 20px;
+    padding-bottom: 15px;
+    border-bottom: 1px solid #ebeef5;
+
+    h4 {
+      margin: 0 0 8px 0;
+      color: #303133;
+      font-size: 16px;
+      font-weight: 600;
+    }
+
+    .dialog-subtitle {
+      margin: 0;
+      color: #606266;
+      font-size: 13px;
+      line-height: 1.4;
+    }
+  }
+
+  .option-list {
+    .option-item {
+      margin-bottom: 12px;
+      padding: 12px;
+      background: #f8f9fa;
+      border-radius: 4px;
+      border: 1px solid #ebeef5;
+
+      &:hover {
+        border-color: #dcdfe6;
+      }
+
+      .option-form {
+        .option-index {
+          display: flex;
+          align-items: center;
+          justify-content: center;
+          height: 100%;
+          color: #909399;
+          font-weight: 500;
+        }
+      }
+    }
+  }
+}
+@media (max-width: 768px) {
+  .satisfaction-exception-config {
+    padding: 12px;
+
+    .page-header {
+      padding: 16px;
+      margin-bottom: 16px;
+    }
+
+    .template-info {
+      flex-direction: column;
+      align-items: flex-start;
+      gap: 10px;
+    }
+
+    .search-card {
+      margin-bottom: 16px;
+    }
+
+    .config-content {
+      .batch-actions-card {
+        margin-bottom: 16px;
+      }
+
+      .question-item {
+        .question-card {
+          .card-header {
+            flex-direction: column;
+            gap: 12px;
+
+            .header-left {
+              flex-direction: column;
+              gap: 12px;
+
+              .question-index {
+                flex-direction: row;
+                align-items: center;
+                min-width: auto;
+
+                .index-number {
+                  margin-bottom: 0;
+                  margin-right: 12px;
+                }
+
+                .index-line {
+                  width: 100%;
+                  height: 2px;
+                }
+              }
+            }
+          }
+
+          .config-section {
+            .config-form {
+              .config-fields {
+                grid-template-columns: 1fr;
+                gap: 16px;
+              }
+
+              .current-config {
+                padding: 12px;
+              }
+
+              .config-footer {
+                flex-direction: column;
+                align-items: stretch;
+                gap: 12px;
+
+                .save-status {
+                  margin-right: 0;
+                  margin-bottom: 8px;
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+}
+</style>
diff --git a/src/views/Satisfaction/particulars/index.vue b/src/views/Satisfaction/particulars/index.vue
new file mode 100644
index 0000000..6ef8d94
--- /dev/null
+++ b/src/views/Satisfaction/particulars/index.vue
@@ -0,0 +1,889 @@
+<template>
+  <div class="Questionnairemanagement">
+    <!-- 涓婁晶鏍� -->
+    <div class="sidecolumn">
+      <div>
+        <el-steps simple :active="Editprogress">
+          <el-step
+            icon="el-icon-edit"
+            title="鍩虹淇℃伅"
+            description="閫夋嫨瀹f暀妯℃澘銆佸舰寮忕瓑鍩虹淇℃伅"
+          ></el-step>
+          <el-step
+            icon="el-icon-user"
+            title="瀹f暀瀵硅薄"
+            description="鍦ㄦ湰閮ㄩ�夋嫨瀹f暀鐥呬汉"
+          ></el-step>
+        </el-steps>
+      </div>
+    </div>
+    <!-- 涓嬩晶鏁版嵁 -->
+    <div class="leftvlue" style="margin: 0 20px">
+      <!-- 鍩烘湰淇℃伅 -->
+      <div v-if="Editprogress == 1">
+        <el-alert
+          title="閫夋嫨瀹f暀妯℃澘銆佸舰寮忕瓑鍩虹淇℃伅"
+          type="success"
+          effect="dark"
+        >
+        </el-alert>
+        <div class="leftvlue-jbxx">
+          <!-- 鍩虹淇℃伅 -->
+          <div class="examine-jic">
+            <div class="headline">
+              <div>鍩虹淇℃伅</div>
+            </div>
+            <div class="jic-value">
+              <el-form ref="form" :model="form" label-width="105px">
+                <el-form-item label="鍙戦�佹椂闂达細" v-if="currenttype != 2">
+                  <el-date-picker
+                    v-model="form.name"
+                    type="date"
+                    placeholder="閫夋嫨鏃ユ湡"
+                  >
+                  </el-date-picker>
+                </el-form-item>
+                <el-form-item label="鍙戦�佹椂闂存锛�" v-if="currenttype != 2">
+                  <el-checkbox-group v-model="checkList">
+                    <el-checkbox label="涓婂崍锛�8:30-11:30锛�"></el-checkbox>
+                    <el-checkbox label="涓嬪崍锛�14:30-16:30锛�"></el-checkbox>
+                    <el-checkbox label="澶滈棿锛�18:30-20:30锛�"></el-checkbox>
+                  </el-checkbox-group>
+                </el-form-item>
+                <el-form-item label="鏈嶅姟褰㈠紡">
+                  <el-checkbox-group v-model="checkList">
+                    <el-checkbox
+                      v-for="(item, index) in checkboxlist"
+                      :key="index"
+                      :label="item"
+                    ></el-checkbox>
+                  </el-checkbox-group>
+                </el-form-item>
+                <el-form-item label="缁勭粐褰㈠紡">
+                  <el-radio-group v-model="form.radio">
+                    <el-radio :label="3">鍗曚汉</el-radio>
+                    <el-radio :label="6">澶氫汉</el-radio>
+                  </el-radio-group>
+                </el-form-item>
+                <el-form-item label="璇煶妯℃澘" prop="region">
+                  <el-select v-model="form.region" placeholder="璇烽�夋嫨妯℃澘">
+                    <el-option label="涓�鍙锋ā鏉�" value="shanghai"></el-option>
+                    <el-option label="浜屽彿妯℃澘" value="beijing"></el-option>
+                  </el-select>
+                </el-form-item>
+              </el-form>
+            </div>
+          </div>
+          <div class="examine-jic">
+            <div class="headline">
+              <div>{{ title }}</div>
+            </div>
+            <div class="examine-jic">
+              <div class="jic-value">
+                <el-row :gutter="20">
+                  <!--鐢ㄦ埛鏁版嵁-->
+
+                  <el-form
+                    :model="topqueryParams"
+                    ref="queryForm"
+                    size="small"
+                    :inline="true"
+                    v-show="showSearch"
+                    label-width="98px"
+                  >
+                    <el-form-item label="鎵ц鐘舵��" prop="status">
+                      <el-select
+                        v-model="topqueryParams.topic"
+                        placeholder="璇烽�夋嫨"
+                      >
+                        <el-option
+                          v-for="item in taskoptions"
+                          :key="item.value"
+                          :label="item.label"
+                          :value="item.value"
+                        >
+                        </el-option>
+                      </el-select>
+                    </el-form-item>
+                    <el-form-item
+                      label="绉戝鍚嶇О"
+                      v-if="currenttype == 1 || currenttype == 3"
+                    >
+                      <el-input
+                        v-model="topqueryParams.name"
+                      ></el-input> </el-form-item
+                    ><el-form-item label="鐥呭尯鍚嶇О" v-if="currenttype == 2">
+                      <el-input v-model="topqueryParams.name"></el-input>
+                    </el-form-item>
+                    <el-form-item
+                      label="鎮h�呭鍚�"
+                      v-if="currenttype == 1 || currenttype == 2"
+                    >
+                      <el-input v-model="topqueryParams.name"></el-input>
+                    </el-form-item>
+                    <el-form-item
+                      label="涓绘不鍖荤敓"
+                      v-if="currenttype == 1 || currenttype == 2"
+                    >
+                      <el-input v-model="topqueryParams.name"></el-input>
+                    </el-form-item>
+                    <el-form-item
+                      label="绠″簥鎶ゅ+"
+                      v-if="currenttype == 1 || currenttype == 2"
+                    >
+                      <el-input v-model="topqueryParams.name"></el-input>
+                    </el-form-item>
+
+                    <el-form-item>
+                      <el-button
+                        type="primary"
+                        icon="el-icon-search"
+                        size="medium"
+                        @click="handleQuery"
+                        >鎼滅储</el-button
+                      >
+                      <el-button
+                        icon="el-icon-refresh"
+                        size="medium"
+                        @click="resetQuery"
+                        >閲嶇疆</el-button
+                      >
+                    </el-form-item>
+                  </el-form>
+                  <el-divider></el-divider>
+                  <!-- 閫夋嫨浠诲姟鍒楄〃 -->
+                  <SFtable
+                    @handleUpdate="handleUpdate"
+                    @handleSelectionChange="handleSelectionChange"
+                    :currentList="userList"
+                    :tableLabel="tableLabelxj"
+                    :controlsc="false"
+                    :multiplechoice="false"
+                  />
+                  <pagination
+                    v-show="total > 0"
+                    :total="total"
+                    :page.sync="topqueryParams.pageNum"
+                    :limit.sync="topqueryParams.pageSize"
+                    @pagination="getList"
+                  />
+                </el-row>
+              </div>
+            </div>
+          </div>
+        </div>
+        <el-button type="success" @click="submitForm('ruleForm')">{{
+          quote ? "绔嬪嵆鍒涘缓" : "浠诲姟璇︽儏璁剧疆"
+        }}</el-button>
+        <el-button @click="resetForm('ruleForm')">閲嶇疆</el-button>
+      </div>
+
+      <!-- 浠诲姟璇︽儏 -->
+      <div v-if="Editprogress == 2">
+        <el-alert title="鍦ㄦ湰闃舵閫夋嫨鐥呬汉" type="success" effect="dark">
+        </el-alert>
+        <div class="leftvlue-jbxx">
+          <div class="examine-jic">
+            <div class="headline">
+              <div>鎮h�呭垪琛�</div>
+            </div>
+            <div class="examine-jic">
+              <div class="jic-value">
+                <el-row :gutter="20">
+                  <!--鐢ㄦ埛鏁版嵁-->
+                  <el-form
+                    :model="topqueryParams"
+                    ref="queryForm"
+                    size="small"
+                    :inline="true"
+                    v-show="showSearch"
+                    label-width="98px"
+                  >
+                    <el-form-item label="鎮h�呭悕绉�">
+                      <el-input v-model="topqueryParams.name"></el-input>
+                    </el-form-item>
+
+                    <el-form-item label="鎮h�呰寖鍥�" prop="status">
+                      <el-select
+                        v-model="topqueryParams.searchscope"
+                        placeholder="璇烽�夋嫨"
+                      >
+                        <el-option
+                          v-for="item in source"
+                          :key="item.value"
+                          :label="item.label"
+                          :value="item.value"
+                        >
+                        </el-option>
+                      </el-select>
+                    </el-form-item>
+
+                    <el-form-item label="鎮h�呯姸鎬�" prop="status">
+                      <el-select
+                        v-model="topqueryParams.topic"
+                        placeholder="璇烽�夋嫨"
+                      >
+                        <el-option
+                          v-for="item in topicoptions"
+                          :key="item.value"
+                          :label="item.label"
+                          :value="item.value"
+                        >
+                        </el-option>
+                      </el-select>
+                    </el-form-item>
+                    <el-form-item label="闅忚缁撴灉" prop="status">
+                      <el-select
+                        v-model="topqueryParams.topic"
+                        placeholder="璇烽�夋嫨"
+                      >
+                        <el-option
+                          v-for="item in topicoptions"
+                          :key="item.value"
+                          :label="item.label"
+                          :value="item.value"
+                        >
+                        </el-option>
+                      </el-select>
+                    </el-form-item>
+                    <el-form-item label="鎮h�呯數璇�">
+                      <el-input v-model="topqueryParams.name"></el-input>
+                    </el-form-item>
+                    <el-form-item>
+                      <el-button
+                        type="primary"
+                        icon="el-icon-search"
+                        size="medium"
+                        @click="handleQuery"
+                        >鎼滅储</el-button
+                      >
+                      <el-button
+                        icon="el-icon-refresh"
+                        size="medium"
+                        @click="resetQuery"
+                        >閲嶇疆</el-button
+                      >
+                      <el-button
+                        icon="el-icon-upload2"
+                        size="medium"
+                        type="warning"
+                        >褰撳墠鎮h�呬竴閿彂閫�</el-button
+                      >
+                    </el-form-item>
+                  </el-form>
+                  <el-divider></el-divider>
+                  <el-row :gutter="10" class="mb8">
+                    <el-col :span="1.5">
+                      <el-select
+                        v-model="tasktopic"
+                        placeholder="璇烽�夋嫨鏂板绫诲瀷"
+                      >
+                        <el-option
+                          v-for="item in taskoptions"
+                          :key="item.value"
+                          :label="item.label"
+                          :value="item.value"
+                        >
+                        </el-option>
+                      </el-select>
+                    </el-col>
+                    <el-col :span="1.5">
+                      <el-button
+                        type="primary"
+                        plain
+                        icon="el-icon-plus"
+                        size="medium"
+                        :disabled="!tasktopic"
+                        @click="handleAddpatient"
+                        >鏂板</el-button
+                      >
+                    </el-col>
+
+                    <el-col :span="1.5">
+                      <el-button
+                        type="danger"
+                        plain
+                        icon="el-icon-delete"
+                        size="medium"
+                        :disabled="multiple"
+                        @click="handleDelete"
+                        >鍒犻櫎</el-button
+                      >
+                    </el-col>
+
+                    <!-- <el-col :span="1.5"> </el-col> -->
+                  </el-row>
+                  <!-- 閫変腑鎮h�呭垪琛� -->
+                  <SFtable
+                    @handleUpdate="handleUpdate"
+                    @handleSelectionChange="handleSelectionChange"
+                    :currentList="sonuserList"
+                    :tableLabel="tableLabelhz"
+                    :controlxz="false"
+                  />
+                  <pagination
+                    v-show="total > 0"
+                    :total="total"
+                    :page.sync="topqueryParams.pageNum"
+                    :limit.sync="topqueryParams.pageSize"
+                    @pagination="getList"
+                  />
+                </el-row>
+              </div>
+            </div>
+          </div>
+        </div>
+        <el-button type="primary" @click="laststep()">涓婁竴姝�</el-button>
+        <el-button type="success" @click="submitForm('ruleForm')"
+          >绔嬪嵆鍒涘缓</el-button
+        >
+        <el-button @click="resetForm('ruleForm')">閲嶇疆</el-button>
+      </div>
+    </div>
+    <!-- 娣诲姞鎮h�� -->
+    <el-dialog
+      title="閫夋嫨鎮h��"
+      :visible.sync="dialogVisiblepatient"
+      width="70%"
+      :before-close="handleClosehz"
+    >
+      <div class="examine-jic">
+        <div class="jic-value">
+          <el-row :gutter="20">
+            <!--鐢ㄦ埛鏁版嵁-->
+            <el-form
+              :model="patientqueryParams"
+              ref="queryForm"
+              size="small"
+              :inline="true"
+              v-show="showSearch"
+              label-width="98px"
+            >
+              <el-form-item label="鎮h�呭悕绉帮細">
+                <el-input v-model="patientqueryParams.name"></el-input>
+              </el-form-item>
+              <el-form-item label="鎮h�呰寖鍥�" prop="status">
+                <el-select
+                  v-model="patientqueryParams.topic"
+                  placeholder="璇烽�夋嫨"
+                >
+                  <el-option
+                    v-for="item in topicoptions"
+                    :key="item.value"
+                    :label="item.label"
+                    :value="item.value"
+                  >
+                  </el-option>
+                </el-select>
+              </el-form-item>
+              <el-form-item label="鍑洪櫌绉戝" prop="status">
+                <el-select
+                  v-model="patientqueryParams.topic"
+                  placeholder="璇烽�夋嫨"
+                >
+                  <el-option
+                    v-for="item in topicoptions"
+                    :key="item.value"
+                    :label="item.label"
+                    :value="item.value"
+                  >
+                  </el-option>
+                </el-select>
+              </el-form-item>
+
+              <el-form-item label="鍑洪櫌鐥呭尯" prop="status">
+                <el-select
+                  v-model="patientqueryParams.topic"
+                  placeholder="璇烽�夋嫨"
+                >
+                  <el-option
+                    v-for="item in topicoptions"
+                    :key="item.value"
+                    :label="item.label"
+                    :value="item.value"
+                  >
+                  </el-option>
+                </el-select>
+              </el-form-item>
+              <el-form-item>
+                <el-button
+                  type="primary"
+                  icon="el-icon-search"
+                  size="medium"
+                  @click="handleQuery"
+                  >鎼滅储</el-button
+                >
+                <el-button
+                  icon="el-icon-refresh"
+                  size="medium"
+                  @click="resetQuery"
+                  >鍙栨秷鍒涘缓</el-button
+                >
+              </el-form-item>
+            </el-form>
+            <!-- 閫夋嫨鎮h�呭垪琛� -->
+            <SFtable
+              @handleUpdate="handleUpdate"
+              @handleSelectionChange="handleSelectionChange"
+              :currentList="patientuserList"
+              :tableLabel="tableLabelhz"
+              :controlsc="false"
+            />
+          </el-row>
+          <pagination
+            v-show="patienttotal > 0"
+            :total="patienttotal"
+            :page.sync="patientqueryParams.pageNum"
+            :limit.sync="patientqueryParams.pageSize"
+            @pagination="handleAddpatient"
+          />
+        </div>
+      </div>
+      <span slot="footer" class="dialog-footer">
+        <el-button @click="dialogVisiblepatient = false">鍙� 娑�</el-button>
+        <el-button type="primary" @click="AddDispatchpatients"
+          >纭畾娣诲姞</el-button
+        >
+      </span>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import { messagelistpatient } from "@/api/patient/homepage";
+import SFtable from "@/components/SFtable"; //琛ㄦ牸缁勪欢
+
+export default {
+  name: "ServiceDetails",
+  data() {
+    return {
+      title: "瀹f暀鍐呭鍒楄〃",
+      currenttype: 1, //1瀹f暀2闂ㄨ瘖3鍑洪櫌4澶嶈瘖5浣撴6闂嵎
+      Editprogress: 1, //缂栬緫杩涘害
+      loading: false, // 閬僵灞�
+      patientloading: false, // 閬僵灞�
+      dialogVisiblepatient: false, //娣诲姞鎮h�呭脊妗�
+      checkboxlist: [],
+      tableLabel: [],
+      // 鎮h�呰〃鍗�
+      tableLabelhz: [
+        { label: "鎮h�呭悕绉�", width: "", prop: "name" },
+        { label: "鎬у埆", width: "", prop: "sex" },
+        { label: "骞撮緞", width: "", prop: "age" },
+        { label: "灏辫瘖绉戝", width: "", prop: "impTemplate" },
+        { label: "鍏ラ櫌鏃ユ湡", width: "", prop: "create_time" },
+        { label: "鍒涘缓浜�", width: "", prop: "update_by" },
+      ],
+      tableLabelxj: [
+        { label: "闂ㄨ瘖缂栧彿", width: "", prop: "name" },
+        { label: "濮撳悕", width: "", prop: "name" },
+        { label: "骞撮緞", width: "", prop: "age" },
+        { label: "鑱旂郴鐢佃瘽", width: "", prop: "telcode" },
+        { label: "灏辫瘖绉戝", width: "", prop: "impTemplate" },
+        { label: "璇婃柇", width: "", prop: "name" },
+        { label: "鍑洪櫌鏃堕棿", width: "", prop: "name" },
+        { label: "鍙戣捣鏃堕棿", width: "", prop: "create_time" },
+        { label: "鐘舵��", width: "", prop: "sex" },
+        { label: "閲嶅娆℃暟", width: "", prop: "update_by" },
+        { label: "浠诲姟鏉ユ簮", width: "", prop: "update_by" },
+        { label: "鍒涘缓浜�", width: "", prop: "update_by" },
+      ],
+      tableLabelmz: [
+        { label: "闂ㄨ瘖缂栧彿", width: "", prop: "name" },
+        { label: "濮撳悕", width: "", prop: "name" },
+        { label: "骞撮緞", width: "", prop: "age" },
+        { label: "鑱旂郴鐢佃瘽", width: "", prop: "telcode" },
+        { label: "灏辫瘖绉戝", width: "", prop: "impTemplate" },
+        { label: "璇婃柇", width: "", prop: "name" },
+        { label: "鍑洪櫌鏃堕棿", width: "", prop: "name" },
+        { label: "鍙戣捣鏃堕棿", width: "", prop: "create_time" },
+        { label: "鐘舵��", width: "", prop: "sex" },
+        { label: "閲嶅娆℃暟", width: "", prop: "update_by" },
+        { label: "浠诲姟鏉ユ簮", width: "", prop: "update_by" },
+        { label: "鍒涘缓浜�", width: "", prop: "update_by" },
+      ],
+      tableLabelcy: [
+        { label: "鍛樺伐缂栧彿", width: "", prop: "name" },
+        { label: "濮撳悕", width: "", prop: "name" },
+        { label: "骞撮緞", width: "", prop: "age" },
+        { label: "鑱旂郴鐢佃瘽", width: "", prop: "telcode" },
+        { label: "鎵�鍦ㄧ瀹�", width: "", prop: "impTemplate" },
+        { label: "瀹屾垚鏃堕棿", width: "", prop: "finishtime" },
+        { label: "鐘舵��", width: "", prop: "sex" },
+        { label: "閲嶅娆℃暟", width: "", prop: "update_by" },
+        { label: "浠诲姟鏉ユ簮", width: "", prop: "update_by" },
+        { label: "鍒涘缓浜�", width: "", prop: "update_by" },
+      ],
+
+      topqueryParams: {
+        pageNum: 1, //
+        pageSize: 10,
+        searchscope:2,
+      },
+      checkList: [],
+      deliverytopqueryParams: {
+        pageNum: 1, //
+        pageSize: 10,
+      },
+      patientqueryParams: {
+        pageNum: 1, //
+        pageSize: 10,
+      },
+      topicoptions: [],
+      showSearch: true, //
+      total: 0, //
+      sontotal: 0, //
+      patienttotal: 0, //
+      // 閫変腑鏁扮粍
+      ids: [],
+      // 闈炲崟涓鐢�
+      single: true,
+      // 闈炲涓鐢�
+      multiple: true,
+      // 鐢ㄦ埛琛ㄦ牸鏁版嵁
+      userList: [], //妯℃澘鍒楄〃
+      patientuserList: [], //閫夋嫨鎮h�呭垪琛�
+      sonuserList: [], //閫変腑鎮h�呭垪琛�
+      tasktopic: null, //鏂板绫诲瀷
+      form: {
+        name: "",
+        region: "",
+        date1: "",
+        date2: "",
+        delivery: false,
+        type: [],
+        resource: "",
+        desc: "",
+      },
+      source: [
+        {
+          value: 0,
+          label: "鎵�灞炴偅鑰�",
+        },
+        {
+          value: 1,
+          label: "绉戝鎮h��",
+        },
+        {
+          value: 2,
+          label: "鐥呭尯鎮h��",
+        },
+      ],
+      options: [
+        {
+          value: "閫夐」1",
+          label: "榛勯噾绯�",
+        },
+        {
+          value: "閫夐」2",
+          label: "鍙岀毊濂�",
+        },
+        {
+          value: "閫夐」5",
+          label: "鍖椾含鐑ら腑",
+        },
+      ],
+      taskoptions: [
+        {
+          value: "1",
+          label: "閫氱煡",
+        },
+        {
+          value: "2",
+          label: "闅忚",
+        },
+        {
+          value: "3",
+          label: "闂嵎",
+        },
+        {
+          value: "4",
+          label: "瀹f暀",
+        },
+      ],
+      quote: false,
+    };
+  },
+  components: { SFtable },
+
+  created() {
+    this.Addsubtask();
+    this.Getsubtask();
+    this.Acquisitiontype();
+  },
+
+  methods: {
+    // 鑾峰彇褰撳墠绫诲瀷
+    Acquisitiontype() {
+      this.currenttype = this.$route.query.type;
+      console.log(this.currenttype);
+      if (this.currenttype == 1) {
+        this.title = "闂ㄨ瘖鐥呬汉浠诲姟";
+        this.tableLabel = this.tableLabelxj;
+        this.checkboxlist = [
+          "褰撻潰",
+          "澶氬獟浣�",
+          "绾歌川",
+          "鐢佃瘽",
+          "鐭俊",
+          "寰俊鍏紬鍙�",
+          "寰俊灏忕▼搴�",
+          "閽夐拤",
+        ];
+      } else if (this.currenttype == 2) {
+        this.title = "鍑洪櫌鐥呬汉浠诲姟";
+        this.tableLabel = this.tableLabelmz;
+        this.checkboxlist = ["褰撻潰", "绾歌川", "鐢佃瘽", "鐭俊", "寰俊鍏紬鍙�"];
+      } else if (this.currenttype == 3) {
+        this.title = "鍖诲姟浜哄憳浠诲姟";
+        this.tableLabel = this.tableLabelcy;
+        this.checkboxlist = ["褰撻潰", "绾歌川", "鐢佃瘽", "鐭俊", "寰俊鍏紬鍙�"];
+      }
+    },
+    // 涓嬩竴姝�
+    submitForm(formName) {
+      if (this.Editprogress <= 3) {
+        return this.Editprogress++;
+      }
+      // 鎻愪氦
+      // this.$refs[formName].validate((valid, object) => {
+      //   if (valid) {
+      //     alert("submit!");
+      //   } else {
+      //     console.log("error submit!!", object);
+      //     return false;
+      //   }
+      // });
+    },
+    // 瀛愪换鍔′簩绾у脊妗�
+    handleAddpatient(row) {
+      console.log(row, "瀛愮粍浠舵暟鎹�");
+      messagelistpatient(this.patientqueryParams).then((response) => {
+        console.log(response);
+        this.patientuserList = response.rows;
+        this.patienttotal = response.total;
+        this.loading = false;
+      });
+      this.dialogVisiblepatient = true;
+    },
+    handleUpdate() {},
+    handleDelete() {},
+    handleExport() {},
+    // 澶氶�夋閫変腑鏁版嵁
+    handleSelectionChange(selection) {
+      this.ids = null;
+      this.ids = selection.map((item) => item.patid).join(",");
+      // let result = this.ids.join(",");
+      this.multiple = !selection.length;
+      console.log(this.ids);
+    },
+    getList() {},
+    handleQuery() {},
+    resetQuery() {},
+    handleClosehz() {
+      this.dialogVisiblepatient = false;
+    },
+    // 涓婁竴姝�
+    laststep() {
+      this.Editprogress--;
+    },
+    // 鎻愪氦琛ㄥ崟
+    resetForm(formName) {
+      this.$refs[formName].resetFields();
+    },
+    // 棰勮妯℃澘
+    PreviewTemplate() {},
+    Acknowledgereference() {
+      this.quote = true;
+    },
+    // 鏂板瀛愪换鍔�
+    Addsubtask() {
+      this.topqueryParams.pguid = 2;
+      // addsvr_prjtask(this.topqueryParams).then((res) => {
+      //   console.log(res);
+      // });
+    },
+    // 鏂板娲鹃�佹偅鑰�
+    AddDispatchpatients() {
+      let objictpint = {};
+      objictpint.patientes = this.ids;
+      objictpint.pguid = 2;
+      // Addpatienttask(objictpint).then((res) => {
+      //   console.log(res);
+      // });
+      this.dialogVisiblepatient = false;
+    },
+
+    // 鏌ヨ瀛愪换鍔″垪琛�
+    Getsubtask() {
+      this.topqueryParams.pguid = 2;
+      console.log(this.topqueryParams);
+      messagelistpatient(this.topqueryParams).then((res) => {
+        this.userList = res.rows;
+        this.total = res.total;
+        console.log(this.userList);
+      });
+    },
+    /** 鏌ヨ鎮h�呭垪琛� */
+  },
+};
+</script>
+
+<style lang="scss" scoped>
+.Questionnairemanagement {
+}
+.leftvlue-jbxx {
+  margin-top: 10px;
+}
+.sidecolumn {
+  width: 100%;
+  // min-height: 12vh;
+  margin: 20px;
+  margin-bottom: 0;
+  padding: 20px;
+  background: #edf1f7;
+  border: 1px solid #dcdfe6;
+  -webkit-box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.12),
+    0 0 6px 0 rgba(0, 0, 0, 0.04);
+}
+.leftvlue {
+  //   display: flex;
+  //   flex: 1;
+  width: 100%;
+  margin-top: 20px;
+  //   margin: 20px;
+  padding: 30px;
+  background: #ffff;
+  border: 1px solid #dcdfe6;
+  -webkit-box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.12),
+    0 0 6px 0 rgba(0, 0, 0, 0.04);
+}
+.examine-jic {
+  .headline {
+    font-size: 24px;
+    border-left: 5px solid #41a1be;
+    padding-left: 5px;
+    margin-bottom: 10px;
+    display: flex;
+    justify-content: space-between;
+    .Add-details {
+      font-size: 18px;
+      color: #02a7f0;
+      cursor: pointer;
+    }
+  }
+  .jic-value {
+    font-size: 20px;
+    border-top: 1px solid #a7abac;
+    padding: 10px;
+    margin-bottom: 10px;
+    .details-jic {
+      padding: 10px 15px;
+      border: 1px solid #dcdfe6;
+      -webkit-box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.12),
+        0 0 6px 0 rgba(0, 0, 0, 0.04);
+      .details-title {
+        display: flex;
+        justify-content: space-between;
+        margin-bottom: 10px;
+        div:nth-child(2) {
+          color: #02a7f0;
+          cursor: pointer;
+        }
+      }
+      .details-renw {
+        background: #e4ebfc;
+        padding: 15px 5px;
+        border-radius: 5px;
+        margin-bottom: 20px;
+      }
+    }
+  }
+}
+// .leftvlue-jbxx {
+//   margin-bottom: 50px;
+//   font-size: 20px;
+//   span {
+//     position: absolute;
+//     right: 80px;
+//   }
+//   .demo-cascader {
+//     margin-right: 20px;
+//   }
+//   .PreviewTemplate {
+//     color: #02a7f0;
+//     cursor: pointer;
+//     font-size: 20px;
+//     margin: 0 20px;
+//   }
+// }
+.jic-value {
+  font-size: 20px;
+  border-top: 1px solid #a7abac;
+  padding: 10px;
+  margin-bottom: 10px;
+  .details-jic {
+    padding: 10px 15px;
+    border: 1px solid #dcdfe6;
+    -webkit-box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.12),
+      0 0 6px 0 rgba(0, 0, 0, 0.04);
+    .details-title {
+      display: flex;
+      justify-content: space-between;
+      margin-bottom: 10px;
+      div:nth-child(2) {
+        color: #02a7f0;
+        cursor: pointer;
+      }
+    }
+    .details-renw {
+      background: #e4ebfc;
+      padding: 15px 5px;
+      border-radius: 5px;
+      margin-bottom: 20px;
+    }
+  }
+}
+::v-deep .addtopic-input {
+  input {
+    background: #02a7f0;
+    color: #edf1f7;
+    width: 150px;
+  }
+}
+::v-deep.el-step.is-vertical .el-step__title {
+  font-size: 25px;
+}
+::v-deep.el-row {
+  margin-bottom: 10px;
+}
+// ::v-deep.el-input--medium {
+//   font-size: 24px !important;
+// }
+::v-deep.ruleFormaa.el-select {
+  display: inline-block;
+  position: relative;
+  width: 700px;
+}
+.el-select__tags {
+  font-size: 20px;
+  max-width: 888px !important;
+}
+::v-deep.el-radio__inner {
+  width: 22px;
+  height: 22px;
+}
+// ::v-deep.topic-dev.el-radio__label {
+//   font-size: 24px;
+// }
+::v-deep.el-radio-group {
+  span {
+    font-size: 24px;
+  }
+}
+::v-deep.el-checkbox-group {
+  span {
+    font-size: 24px;
+  }
+}
+</style>
diff --git a/src/views/Satisfaction/sfstatistics/IndicatorStatistics.vue b/src/views/Satisfaction/sfstatistics/IndicatorStatistics.vue
new file mode 100644
index 0000000..53f5355
--- /dev/null
+++ b/src/views/Satisfaction/sfstatistics/IndicatorStatistics.vue
@@ -0,0 +1,66 @@
+<!-- StatisticsMain.vue -->
+<template>
+  <div class="statistics-main">
+    <el-tabs v-model="activeTab" @tab-click="handleTabChange">
+      <el-tab-pane label="婊℃剰搴︾粺璁�" name="followup">
+        <followup-statistics
+          v-if="activeTab === 'followup'"
+          ref="followupRef"
+        />
+      </el-tab-pane>
+      <el-tab-pane label="澶嶈瘖閫氱煡缁熻" name="visitStatistics">
+        <visit-Statistics
+          v-if="activeTab === 'visitStatistics'"
+          ref="visitStatisticsRef"
+        />
+      </el-tab-pane>
+
+    </el-tabs>
+  </div>
+</template>
+
+<script>
+import FollowupStatistics from "./components/FollowupStatistics.vue";
+import visitStatistics from "./components/visitStatistics.vue";
+import SatisfactionStatistics from "./components/SatisfactionStatistics.vue";
+
+export default {
+  name: "StatisticsMain",
+  components: {
+    FollowupStatistics,
+    SatisfactionStatistics,
+    visitStatistics,
+  },
+  data() {
+    return {
+      activeTab: "followup",
+    };
+  },
+  methods: {
+    handleTabChange(tab) {
+      console.log("鍒囨崲鍒�:", tab.name);
+    },
+  },
+};
+</script>
+
+<style lang="scss" scoped>
+.statistics-main {
+  padding: 20px;
+  background: #fff;
+  min-height: calc(100vh - 84px);
+
+  ::v-deep .el-tabs__header {
+    margin-bottom: 20px;
+  }
+
+  ::v-deep .el-tabs__item {
+    font-size: 16px;
+    font-weight: 500;
+  }
+
+  ::v-deep .el-tabs__nav-wrap::after {
+    height: 1px;
+  }
+}
+</style>
diff --git a/src/views/Satisfaction/sfstatistics/components/FollowupStatistics.vue b/src/views/Satisfaction/sfstatistics/components/FollowupStatistics.vue
new file mode 100644
index 0000000..8de4434
--- /dev/null
+++ b/src/views/Satisfaction/sfstatistics/components/FollowupStatistics.vue
@@ -0,0 +1,1030 @@
+<template>
+  <div class="followup-statistics">
+    <div class="query-section">
+      <el-form
+        :model="queryParams"
+        ref="queryForm"
+        size="medium"
+        :inline="true"
+        label-width="100px"
+        class="query-form"
+      >
+        <el-form-item label="缁熻绫诲瀷" prop="statisticaltype">
+          <el-select
+            v-model="queryParams.statisticaltype"
+            placeholder="璇烽�夋嫨缁熻绫诲瀷"
+            clearable
+            @change="handleStatisticalTypeChange"
+          >
+            <el-option
+              v-for="item in Statisticallist"
+              :key="item.value"
+              :label="item.label"
+              :value="item.value"
+            />
+          </el-select>
+        </el-form-item>
+
+        <!-- 鐥呭尯閫夋嫨 -->
+        <el-form-item
+          v-if="queryParams.statisticaltype == 1"
+          label="鐥呭尯"
+          prop="leavehospitaldistrictcodes"
+        >
+          <el-select
+            v-model="queryParams.leavehospitaldistrictcodes"
+            placeholder="璇烽�夋嫨鐥呭尯"
+            multiple
+            collapse-tags
+            filterable
+            clearable
+            style="width: 300px"
+          >
+            <el-option
+              v-for="item in flatArrayhospit"
+              :key="item.value"
+              :label="item.label"
+              :value="item.value"
+            />
+          </el-select>
+        </el-form-item>
+
+        <!-- 绉戝閫夋嫨 -->
+        <el-form-item
+          v-if="queryParams.statisticaltype == 2"
+          label="绉戝"
+          prop="deptcodes"
+        >
+          <el-select
+            v-model="queryParams.deptcodes"
+            placeholder="璇烽�夋嫨绉戝"
+            multiple
+            collapse-tags
+            filterable
+            clearable
+            style="width: 300px"
+          >
+            <el-option
+              v-for="item in flatArraydept"
+              :key="item.value"
+              :label="item.label"
+              :value="item.value"
+            />
+          </el-select>
+        </el-form-item>
+
+        <el-form-item label="鏈嶅姟绫诲瀷" prop="serviceType">
+          <el-select
+            v-model="queryParams.serviceType"
+            placeholder="璇烽�夋嫨鏈嶅姟绫诲瀷"
+            multiple
+            collapse-tags
+            clearable
+            style="width: 300px"
+          >
+            <el-option
+              v-for="item in options"
+              :key="item.value"
+              :label="item.label"
+              :value="item.value"
+            />
+          </el-select>
+        </el-form-item>
+
+        <el-form-item label="闅忚鏃堕棿" prop="dateRange">
+          <el-date-picker
+            v-model="queryParams.dateRange"
+            type="daterange"
+            range-separator="鑷�"
+            start-placeholder="寮�濮嬫棩鏈�"
+            end-placeholder="缁撴潫鏃ユ湡"
+            value-format="yyyy-MM-dd"
+            :picker-options="pickerOptions"
+            style="width: 380px"
+          />
+        </el-form-item>
+
+        <el-form-item>
+          <el-button
+            type="primary"
+            icon="el-icon-search"
+            @click="handleQuery"
+            :loading="loading"
+          >
+            鎼滅储
+          </el-button>
+          <el-button icon="el-icon-refresh" @click="resetQuery">
+            閲嶇疆
+          </el-button>
+          <el-button
+            type="warning"
+            icon="el-icon-download"
+            @click="handleExport"
+            :disabled="!userList.length"
+          >
+            瀵煎嚭
+          </el-button>
+        </el-form-item>
+      </el-form>
+    </div>
+
+    <div class="table-section">
+      <el-table
+        v-loading="loading"
+        :data="userList"
+        :border="true"
+        style="width: 100%"
+        @selection-change="handleSelectionChange"
+        :row-key="getRowKey"
+      >
+        <!-- 鐥呭尯鍒� -->
+        <el-table-column
+          v-if="queryParams.statisticaltype == 1"
+          label="鍑洪櫌鐥呭尯"
+          align="center"
+          sortable
+          key="leavehospitaldistrictname"
+          prop="leavehospitaldistrictname"
+          :show-overflow-tooltip="true"
+          :sort-method="sortChineseNumber"
+          min-width="120"
+        />
+
+        <!-- 绉戝鍒� -->
+        <el-table-column
+          v-if="queryParams.statisticaltype == 2"
+          label="绉戝"
+          align="center"
+          key="deptname"
+          prop="deptname"
+          :show-overflow-tooltip="true"
+          min-width="120"
+        />
+
+        <el-table-column
+          label="鍑洪櫌浜烘"
+          align="center"
+          key="dischargeCount"
+          prop="dischargeCount"
+          min-width="100"
+        />
+
+        <el-table-column
+          label="鏃犻渶闅忚浜烘"
+          align="center"
+          key="nonFollowUp"
+          prop="nonFollowUp"
+          min-width="120"
+        />
+
+        <el-table-column
+          label="搴旈殢璁夸汉娆�"
+          align="center"
+          key="followUpNeeded"
+          prop="followUpNeeded"
+          min-width="120"
+        />
+
+        <el-table-column
+          label="闅忚鐜�"
+          align="center"
+          key="followUpRate"
+          prop="followUpRate"
+          min-width="100"
+        >
+          <template slot-scope="scope">
+            <span
+              v-if="
+                scope.row.followUpRate !== null &&
+                scope.row.followUpRate !== undefined
+              "
+            >
+              {{ scope.row.followUpRate }}
+            </span>
+            <span v-else>-</span>
+          </template>
+        </el-table-column>
+
+        <el-table-column
+          label="鍙婃椂鐜�"
+          align="center"
+          key="rate"
+          prop="rate"
+          min-width="100"
+        >
+          <template slot-scope="scope">
+            <el-button
+              v-if="scope.row.rate !== null && scope.row.rate !== undefined"
+              type="text"
+              @click="handleSeedetails(scope.row)"
+            >
+              {{ formatPercent(scope.row.rate) }}
+            </el-button>
+            <span v-else style="color: #909399">-</span>
+          </template>
+        </el-table-column>
+
+        <el-table-column
+          label="婊℃剰搴﹂鐩�婚噺"
+          align="center"
+          key="joyAllCount"
+          prop="joyAllCount"
+          min-width="140"
+        />
+
+        <el-table-column
+          label="婊℃剰搴﹀~鎶ラ噺"
+          align="center"
+          key="joyCount"
+          prop="joyCount"
+          min-width="120"
+        />
+
+        <el-table-column
+          label="瀹屾垚姣旂巼"
+          align="center"
+          key="joyTotal"
+          prop="joyTotal"
+          min-width="100"
+        >
+          <template slot-scope="scope">
+            <span
+              v-if="
+                scope.row.joyTotal !== null && scope.row.joyTotal !== undefined
+              "
+            >
+              {{ formatPercent(scope.row.joyTotal) }}
+            </span>
+            <span v-else>-</span>
+          </template>
+        </el-table-column>
+
+        <el-table-column label="鎿嶄綔" align="center" fixed="right" width="120">
+          <template slot-scope="scope">
+            <el-button type="text" @click="getinfo(scope.row)">
+              <i class="el-icon-s-order" style="margin-right: 4px"></i>
+              鏌ョ湅璇︽儏
+            </el-button>
+          </template>
+        </el-table-column>
+      </el-table>
+    </div>
+
+    <!-- 鍒嗛〉 -->
+    <div class="pagination-section" v-if="total > 0">
+      <el-pagination
+        background
+        layout="total, sizes, prev, pager, next, jumper"
+        :current-page="queryParams.pageNum"
+        :page-size="queryParams.pageSize"
+        :page-sizes="[10, 20, 30, 50]"
+        :total="total"
+        @size-change="handleSizeChange"
+        @current-change="handlePageChange"
+      />
+    </div>
+
+    <!-- 鏈強鏃堕殢璁胯鎯呭璇濇 -->
+    <el-dialog
+      title="鏈強鏃堕殢璁挎偅鑰呮湇鍔�"
+      :visible.sync="SeedetailsVisible"
+      width="80%"
+      :close-on-click-modal="false"
+    >
+      <SeedetailsDialog
+        v-if="SeedetailsVisible"
+        :row-data="currentRow"
+        :query-params="queryParams"
+        @close="SeedetailsVisible = false"
+      />
+    </el-dialog>
+
+    <!-- 婊℃剰搴﹁鎯呭璇濇 -->
+    <el-dialog
+      :visible.sync="topicVisible"
+      width="60%"
+      :close-on-click-modal="false"
+    >
+      <template #title>
+        <div style="display: flex; align-items: center">
+          <i
+            class="el-icon-s-data"
+            style="margin-right: 8px; color: #409eff"
+          ></i>
+          <span>{{ topicvalue.name }}</span>
+          <span style="margin-left: 10px; color: #666; font-size: 14px"
+            >婊℃剰搴︽寚鏍囪鎯�</span
+          >
+        </div>
+      </template>
+      <topic-dialog
+        v-if="topicVisible"
+        :row-data="currentRow"
+        :topicList="topiclist"
+        :query-params="queryParams"
+        @close="topicVisible = false"
+      />
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import {
+  getSfStatisticsJoy,
+  getSfStatisticsJoyInfo,
+  selectTimelyRate,
+} from "@/api/system/user";
+import ExcelJS from "exceljs";
+import { saveAs } from "file-saver";
+import SeedetailsDialog from "./components/SeedetailsDialog.vue";
+import TopicDialog from "./components/TopicDialog.vue";
+
+export default {
+  name: "FollowupStatistics",
+  components: {
+    SeedetailsDialog,
+    TopicDialog,
+  },
+  data() {
+    return {
+      // 鏌ヨ鍙傛暟
+      queryParams: {
+        statisticaltype: 1,
+        leavehospitaldistrictcodes: ["all"],
+        deptcodes: [],
+        serviceType: [2],
+        dateRange: [],
+        pageNum: 1,
+        pageSize: 20,
+      },
+
+      // 缁熻绫诲瀷鍒楄〃
+      Statisticallist: [
+        { label: "鐥呭尯缁熻", value: 1 },
+        { label: "绉戝缁熻", value: 2 },
+      ],
+
+      // 鐥呭尯鍒楄〃
+      flatArrayhospit: [],
+
+      // 绉戝鍒楄〃
+      flatArraydept: [],
+
+      // 鏈嶅姟绫诲瀷閫夐」
+      options: [],
+
+      // 琛ㄦ牸鏁版嵁
+      userList: [],
+
+      // 鎬绘潯鏁�
+      total: 0,
+
+      // 鍔犺浇鐘舵��
+      loading: false,
+
+      // 閫変腑鐨勮
+      ids: [],
+      single: true,
+      multiple: true,
+
+      // 褰撳墠鎿嶄綔鐨勮
+      currentRow: null,
+
+      // 瀵硅瘽妗嗘樉绀烘帶鍒�
+      SeedetailsVisible: false,
+      topicVisible: false,
+
+      // 婊℃剰搴﹁鎯呮暟鎹�
+      topiclist: [],
+      topicvalue: {
+        name: "",
+      },
+
+      // 鏃ユ湡閫夋嫨鍣ㄩ�夐」
+      pickerOptions: {
+        shortcuts: [
+          {
+            text: "鏈�杩戜竴鍛�",
+            onClick(picker) {
+              const end = new Date();
+              const start = new Date();
+              start.setTime(start.getTime() - 3600 * 1000 * 24 * 7);
+              picker.$emit("pick", [start, end]);
+            },
+          },
+          {
+            text: "鏈�杩戜竴涓湀",
+            onClick(picker) {
+              const end = new Date();
+              const start = new Date();
+              start.setTime(start.getTime() - 3600 * 1000 * 24 * 30);
+              picker.$emit("pick", [start, end]);
+            },
+          },
+          {
+            text: "鏈�杩戜笁涓湀",
+            onClick(picker) {
+              const end = new Date();
+              const start = new Date();
+              start.setTime(start.getTime() - 3600 * 1000 * 24 * 90);
+              picker.$emit("pick", [start, end]);
+            },
+          },
+        ],
+        disabledDate(time) {
+          return time.getTime() > Date.now();
+        },
+      },
+    };
+  },
+
+  created() {
+    this.initData();
+  },
+
+  methods: {
+    // 鍒濆鍖栨暟鎹�
+    async initData() {
+      await this.getDeptTree();
+      await this.getList();
+    },
+
+    // 鑾峰彇绉戝鏍�
+    getDeptTree() {
+      // 鑾峰彇鏈嶅姟绫诲瀷
+      this.options = this.$store.getters.tasktypes || [];
+
+      // 鑾峰彇绉戝鍒楄〃
+      this.flatArraydept = (this.$store.getters.belongDepts || []).map(
+        (dept) => {
+          return {
+            label: dept.deptName,
+            value: dept.deptCode,
+          };
+        }
+      );
+
+      // 鑾峰彇鐥呭尯鍒楄〃
+      this.flatArrayhospit = (this.$store.getters.belongWards || []).map(
+        (ward) => {
+          return {
+            label: ward.districtName,
+            value: ward.districtCode,
+          };
+        }
+      );
+
+      // 娣诲姞鍏ㄩ儴閫夐」
+      this.flatArraydept.push({ label: "鍏ㄩ儴", value: "all" });
+      this.flatArrayhospit.push({ label: "鍏ㄩ儴", value: "all" });
+    },
+
+    // 鑾峰彇缁熻鍒楄〃
+    async getList() {
+      this.loading = true;
+      try {
+        // 澶勭悊鏌ヨ鍙傛暟
+        const params = {
+          configKey: "joyCount",
+          ...this.queryParams,
+        };
+
+        // 澶勭悊鏃ユ湡鑼冨洿
+        if (
+          this.queryParams.dateRange &&
+          this.queryParams.dateRange.length === 2
+        ) {
+          params.startTime = this.queryParams.dateRange[0];
+          params.endTime = this.queryParams.dateRange[1];
+        }
+
+        // 澶勭悊鐥呭尯/绉戝閫夋嫨
+        if (params.statisticaltype == 1) {
+          // 鐥呭尯缁熻
+          if (params.leavehospitaldistrictcodes.includes("all")) {
+            // 濡傛灉閫夋嫨浜�"鍏ㄩ儴"锛屽垯绉婚櫎"all"鍊�
+            params.leavehospitaldistrictcodes =
+              params.leavehospitaldistrictcodes.filter(
+                (item) => item !== "all"
+              );
+            // 濡傛灉闇�瑕佷紶鎵�鏈夌梾鍖轰唬鐮侊紝鍙互浠巗tore涓幏鍙�
+            params.leavehospitaldistrictcodes = (
+              this.$store.getters.belongWards || []
+            ).map((ward) => ward.districtCode);
+          }
+        } else if (params.statisticaltype == 2) {
+          // 绉戝缁熻
+          if (params.deptcodes.includes("all")) {
+            // 濡傛灉閫夋嫨浜�"鍏ㄩ儴"锛屽垯绉婚櫎"all"鍊�
+            params.deptcodes = params.deptcodes.filter(
+              (item) => item !== "all"
+            );
+            // 濡傛灉闇�瑕佷紶鎵�鏈夌瀹や唬鐮侊紝鍙互浠巗tore涓幏鍙�
+            params.deptcodes = (this.$store.getters.belongDepts || []).map(
+              (dept) => dept.deptCode
+            );
+          }
+        }
+
+        const response = await getSfStatisticsJoy(params);
+        this.userList = this.customSort(response.data) || [];
+        this.total = response.total || 0;
+      } catch (error) {
+        console.error("鑾峰彇缁熻鍒楄〃澶辫触:", error);
+        this.$message.error("鑾峰彇鏁版嵁澶辫触");
+      } finally {
+        this.loading = false;
+      }
+    },
+    sortChineseNumber(aRow, bRow) {
+      const a = aRow.leavehospitaldistrictname;
+      const b = bRow.leavehospitaldistrictname;
+
+      // 涓枃鏁板瓧鍒伴樋鎷変集鏁板瓧鐨勬槧灏勶紙鎵╁睍鍒�45锛�
+      const chineseNumMap = {
+        涓�: 1,
+        浜�: 2,
+        涓�: 3,
+        鍥�: 4,
+        浜�: 5,
+        鍏�: 6,
+        涓�: 7,
+        鍏�: 8,
+        涔�: 9,
+        鍗�: 10,
+        鍗佷竴: 11,
+        鍗佷簩: 12,
+        鍗佷笁: 13,
+        鍗佸洓: 14,
+        鍗佷簲: 15,
+        鍗佸叚: 16,
+        鍗佷竷: 17,
+        鍗佸叓: 18,
+        鍗佷節: 19,
+        浜屽崄: 20,
+        浜屽崄涓�: 21,
+        浜屽崄浜�: 22,
+        浜屽崄涓�: 23,
+        浜屽崄鍥�: 24,
+        浜屽崄浜�: 25,
+        浜屽崄鍏�: 26,
+        浜屽崄涓�: 27,
+        浜屽崄鍏�: 28,
+        浜屽崄涔�: 29,
+        涓夊崄: 30,
+        涓夊崄涓�: 31,
+        涓夊崄浜�: 32,
+        涓夊崄涓�: 33,
+        涓夊崄鍥�: 34,
+        涓夊崄浜�: 35,
+        涓夊崄鍏�: 36,
+        涓夊崄涓�: 37,
+        涓夊崄鍏�: 38,
+        涓夊崄涔�: 39,
+        鍥涘崄: 40,
+        鍥涘崄涓�: 41,
+        鍥涘崄浜�: 42,
+        鍥涘崄涓�: 43,
+        鍥涘崄鍥�: 44,
+        鍥涘崄浜�: 45,
+      };
+
+      // 鎻愬彇涓枃鏁板瓧
+      const getNumberFromText = (text) => {
+        if (!text || typeof text !== "string") return -1;
+
+        // 鍖归厤涓枃鏁板瓧锛屾敮鎸佷竴鍒板洓鍗佷簲
+        const match = text.match(/^([涓�浜屼笁鍥涗簲鍏竷鍏節鍗乚+)/);
+
+        if (match && match[1]) {
+          const chineseNum = match[1];
+          return chineseNumMap[chineseNum] !== undefined
+            ? chineseNumMap[chineseNum]
+            : -1;
+        }
+
+        // 濡傛灉娌℃湁鍖归厤鍒颁腑鏂囨暟瀛楋紝灏濊瘯鍖归厤闃挎媺浼暟瀛�
+        const arabicMatch = text.match(/^(\d+)/);
+        if (arabicMatch && arabicMatch[1]) {
+          const num = parseInt(arabicMatch[1], 10);
+          return num >= 1 && num <= 45 ? num : -1;
+        }
+
+        return -1;
+      };
+
+      const numA = getNumberFromText(a);
+      const numB = getNumberFromText(b);
+
+      // 澶勭悊鏃犳硶瑙f瀽鐨勬儏鍐�
+      if (numA === -1 && numB === -1) {
+        return (a || "").localeCompare(b || "");
+      }
+      if (numA === -1) return 1;
+      if (numB === -1) return -1;
+
+      return numA - numB;
+    },
+    customSort(data) {
+      // 瀹氫箟鎮ㄦ湡鏈涚殑鐥呭尯椤哄簭锛堟墿灞曞埌鍥涘崄浜旓級
+      const order = [
+        "涓�",
+        "浜�",
+        "涓�",
+        "鍥�",
+        "浜�",
+        "鍏�",
+        "涓�",
+        "鍏�",
+        "涔�",
+        "鍗�",
+        "鍗佷竴",
+        "鍗佷簩",
+        "鍗佷笁",
+        "鍗佸洓",
+        "鍗佷簲",
+        "鍗佸叚",
+        "鍗佷竷",
+        "鍗佸叓",
+        "鍗佷節",
+        "浜屽崄",
+        "浜屽崄涓�",
+        "浜屽崄浜�",
+        "浜屽崄涓�",
+        "浜屽崄鍥�",
+        "浜屽崄浜�",
+        "浜屽崄鍏�",
+        "浜屽崄涓�",
+        "浜屽崄鍏�",
+        "浜屽崄涔�",
+        "涓夊崄",
+        "涓夊崄涓�",
+        "涓夊崄浜�",
+        "涓夊崄涓�",
+        "涓夊崄鍥�",
+        "涓夊崄浜�",
+        "涓夊崄鍏�",
+        "涓夊崄涓�",
+        "涓夊崄鍏�",
+        "涓夊崄涔�",
+        "鍥涘崄",
+        "鍥涘崄涓�",
+        "鍥涘崄浜�",
+        "鍥涘崄涓�",
+        "鍥涘崄鍥�",
+        "鍥涘崄浜�",
+      ];
+
+      return data.sort((a, b) => {
+        // 鎻愬彇鐥呭尯鍚嶇О涓殑涓枃鏁板瓧閮ㄥ垎
+        const getIndex = (name) => {
+          if (!name || typeof name !== "string") return -1;
+
+          // 鍖归厤涓枃鏁板瓧
+          const chineseMatch = name.match(/^([涓�浜屼笁鍥涗簲鍏竷鍏節鍗乚+)/);
+          if (chineseMatch && chineseMatch[1]) {
+            return order.indexOf(chineseMatch[1]);
+          }
+
+          // 鍖归厤闃挎媺浼暟瀛�
+          const arabicMatch = name.match(/^(\d+)/);
+          if (arabicMatch && arabicMatch[1]) {
+            const num = parseInt(arabicMatch[1], 10);
+            if (num >= 1 && num <= 45) {
+              return num - 1; // 鍥犱负鏁扮粍绱㈠紩浠�0寮�濮�
+            }
+          }
+
+          return -1;
+        };
+
+        const indexA = getIndex(a.leavehospitaldistrictname);
+        const indexB = getIndex(b.leavehospitaldistrictname);
+
+        // 鎺掑簭閫昏緫
+        if (indexA === -1 && indexB === -1) {
+          return (a.leavehospitaldistrictname || "").localeCompare(
+            b.leavehospitaldistrictname || ""
+          );
+        }
+        if (indexA === -1) return 1;
+        if (indexB === -1) return -1;
+        return indexA - indexB;
+      });
+    },
+    // 澶勭悊缁熻绫诲瀷鍙樺寲
+    handleStatisticalTypeChange(value) {
+      if (value === 1) {
+        this.queryParams.deptcodes = [];
+      } else {
+        this.queryParams.leavehospitaldistrictcodes = [];
+      }
+      this.queryParams.pageNum = 1;
+      this.getList();
+    },
+
+    // 澶勭悊鏌ヨ
+    handleQuery() {
+      this.queryParams.pageNum = 1;
+      this.getList();
+    },
+
+    // 閲嶇疆鏌ヨ
+    resetQuery() {
+      this.queryParams = {
+        statisticaltype: 1,
+        leavehospitaldistrictcodes: [],
+        deptcodes: [],
+        serviceType: [2],
+        dateRange: [],
+        pageNum: 1,
+        pageSize: 20,
+      };
+      this.getList();
+    },
+
+    // 澶勭悊鍒嗛〉澶у皬鍙樺寲
+    handleSizeChange(size) {
+      this.queryParams.pageSize = size;
+      this.queryParams.pageNum = 1;
+      this.getList();
+    },
+
+    // 澶勭悊椤电爜鍙樺寲
+    handlePageChange(page) {
+      this.queryParams.pageNum = page;
+      this.getList();
+    },
+
+    // 澶勭悊琛岄�夋嫨
+    handleSelectionChange(selection) {
+      this.ids = selection.map((item) => item.id);
+      this.single = selection.length !== 1;
+      this.multiple = !selection.length;
+    },
+
+    // 鑾峰彇琛宬ey
+    getRowKey(row) {
+      return row.statisticaltype === 1
+        ? row.leavehospitaldistrictcode
+        : row.deptcode;
+    },
+
+    // 鏍煎紡鍖栫櫨鍒嗘瘮
+    formatPercent(value) {
+      if (value === null || value === undefined) return "-";
+      const num = parseFloat(value);
+      if (isNaN(num)) return "-";
+      return `${(num * 100).toFixed(2)}%`;
+    },
+
+    // 鏌ョ湅鏈強鏃堕殢璁胯鎯�
+    handleSeedetails(row) {
+      this.currentRow = row;
+      this.SeedetailsVisible = true;
+    },
+
+    // 鏌ョ湅婊℃剰搴﹁鎯�
+    async getinfo(row) {
+      this.currentRow = row;
+
+      try {
+        // 澶勭悊鏌ヨ鍙傛暟
+        const params = {
+          configKey: "joyCount",
+          ...this.queryParams,
+        };
+
+        // 澶勭悊鏃ユ湡鑼冨洿
+        if (
+          this.queryParams.dateRange &&
+          this.queryParams.dateRange.length === 2
+        ) {
+          params.startTime = this.queryParams.dateRange[0];
+          params.endTime = this.queryParams.dateRange[1];
+        }
+
+        if (this.queryParams.statisticaltype == 1) {
+          this.topicvalue.name = row.leavehospitaldistrictname;
+          params.leavehospitaldistrictcodes = [row.leavehospitaldistrictcode];
+        } else {
+          this.topicvalue.name = row.deptname;
+          params.deptcodes = [row.deptcode];
+        }
+
+        const response = await getSfStatisticsJoyInfo(params);
+        this.topiclist = response.data || [];
+      this.topicVisible = true;
+
+      } catch (error) {
+        console.error("鑾峰彇婊℃剰搴﹁鎯呭け璐�:", error);
+        this.$message.error("鑾峰彇璇︽儏澶辫触");
+      }
+    },
+
+    // 瀵煎嚭鏁版嵁
+    async handleExport() {
+      if (!this.userList.length) {
+        this.$message.warning("娌℃湁鏁版嵁鍙鍑�");
+        return;
+      }
+
+      try {
+        this.loading = true;
+
+        // 鏋勫缓鏃ユ湡鑼冨洿瀛楃涓�
+        let dateRangeString = "";
+        let sheetNameSuffix = "";
+
+        if (
+          this.queryParams.dateRange &&
+          this.queryParams.dateRange.length === 2
+        ) {
+          const startDateFormatted = this.queryParams.dateRange[0];
+          const endDateFormatted = this.queryParams.dateRange[1];
+          dateRangeString = `${startDateFormatted}鑷�${endDateFormatted}`;
+          sheetNameSuffix = `${startDateFormatted}鑷�${endDateFormatted}`;
+        } else {
+          const now = new Date();
+          const currentMonth = now.getMonth() + 1;
+          dateRangeString = `${currentMonth}鏈坄;
+          sheetNameSuffix = `${currentMonth}鏈坄;
+        }
+
+        const excelName = `闅忚缁熻琛╛${dateRangeString}.xlsx`;
+        const worksheetName = `闅忚缁熻_${sheetNameSuffix}`;
+
+        // 鍒涘缓Excel宸ヤ綔绨�
+        const workbook = new ExcelJS.Workbook();
+        const worksheet = workbook.addWorksheet(worksheetName);
+
+        // 瀹氫箟鏍峰紡
+        const titleStyle = {
+          font: { name: "寰蒋闆呴粦", size: 16, bold: true },
+          fill: {
+            type: "pattern",
+            pattern: "solid",
+            fgColor: { argb: "FFE6F3FF" },
+          },
+          alignment: { vertical: "middle", horizontal: "center" },
+          border: {
+            top: { style: "thin", color: { argb: "FFD0D0D0" } },
+            left: { style: "thin", color: { argb: "FFD0D0D0" } },
+            bottom: { style: "thin", color: { argb: "FFD0D0D0" } },
+            right: { style: "thin", color: { argb: "FFD0D0D0" } },
+          },
+        };
+
+        const headerStyle = {
+          font: { name: "寰蒋闆呴粦", size: 11, bold: true },
+          fill: {
+            type: "pattern",
+            pattern: "solid",
+            fgColor: { argb: "FFF5F7FA" },
+          },
+          alignment: { vertical: "middle", horizontal: "center" },
+          border: {
+            top: { style: "thin", color: { argb: "FFD0D0D0" } },
+            left: { style: "thin", color: { argb: "FFD0D0D0" } },
+            bottom: { style: "thin", color: { argb: "FFD0D0D0" } },
+            right: { style: "thin", color: { argb: "FFD0D0D0" } },
+          },
+        };
+
+        const cellStyle = {
+          font: { name: "瀹嬩綋", size: 10 },
+          alignment: { vertical: "middle", horizontal: "center" },
+          border: {
+            top: { style: "thin", color: { argb: "FFD0D0D0" } },
+            left: { style: "thin", color: { argb: "FFD0D0D0" } },
+            bottom: { style: "thin", color: { argb: "FFD0D0D0" } },
+            right: { style: "thin", color: { argb: "FFD0D0D0" } },
+          },
+        };
+
+        // 娣诲姞鎬绘爣棰�
+        worksheet.mergeCells(1, 1, 1, 10);
+        const titleCell = worksheet.getCell(1, 1);
+        titleCell.value = `闅忚缁熻琛紙${sheetNameSuffix}锛塦;
+        titleCell.style = titleStyle;
+        worksheet.getRow(1).height = 35;
+
+        // 娣诲姞琛ㄥご
+        const headers = [
+          this.queryParams.statisticaltype == 1 ? "鍑洪櫌鐥呭尯" : "绉戝",
+          "鍑洪櫌浜烘",
+          "鏃犻渶闅忚浜烘",
+          "搴旈殢璁夸汉娆�",
+          "闅忚鐜�",
+          "鍙婃椂鐜�",
+          "婊℃剰搴﹂鐩�婚噺",
+          "婊℃剰搴﹀~鎶ラ噺",
+          "瀹屾垚姣旂巼",
+        ];
+
+        const headerRow = worksheet.addRow(headers);
+        headerRow.eachCell((cell) => {
+          cell.style = headerStyle;
+        });
+        headerRow.height = 25;
+
+        // 娣诲姞鏁版嵁琛�
+        this.userList.forEach((item) => {
+          const dataRow = worksheet.addRow([
+            this.queryParams.statisticaltype == 1
+              ? item.leavehospitaldistrictname
+              : item.deptname,
+            item.dischargeCount || 0,
+            item.nonFollowUp || 0,
+            item.followUpNeeded || 0,
+            item.followUpRate || "0%",
+            item.rate ? this.formatPercent(item.rate) : "0%",
+            item.joyAllCount || 0,
+            item.joyCount || 0,
+            item.joyTotal ? this.formatPercent(item.joyTotal) : "0%",
+          ]);
+
+          dataRow.eachCell((cell) => {
+            cell.style = cellStyle;
+          });
+          dataRow.height = 22;
+        });
+
+        // 璁剧疆鍒楀
+        worksheet.columns = [
+          { width: 20 },
+          { width: 12 },
+          { width: 12 },
+          { width: 12 },
+          { width: 12 },
+          { width: 12 },
+          { width: 15 },
+          { width: 15 },
+          { width: 12 },
+        ];
+
+        // 鐢熸垚骞朵笅杞芥枃浠�
+        const buffer = await workbook.xlsx.writeBuffer();
+        const blob = new Blob([buffer], {
+          type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
+        });
+
+        saveAs(blob, excelName);
+        this.$message.success("瀵煎嚭鎴愬姛");
+      } catch (error) {
+        console.error("瀵煎嚭澶辫触:", error);
+        this.$message.error(`瀵煎嚭澶辫触: ${error.message}`);
+      } finally {
+        this.loading = false;
+      }
+    },
+  },
+};
+</script>
+
+<style lang="scss" scoped>
+.followup-statistics {
+  .query-section {
+    background: #fff;
+    padding: 20px;
+    border-radius: 4px;
+    margin-bottom: 20px;
+
+    .query-form {
+      display: flex;
+      flex-wrap: wrap;
+
+      ::v-deep .el-form-item {
+        margin-bottom: 20px;
+
+        &:not(:last-child) {
+          margin-right: 20px;
+        }
+      }
+    }
+  }
+
+  .table-section {
+    background: #fff;
+    padding: 20px;
+    border-radius: 4px;
+    margin-bottom: 20px;
+
+    ::v-deep .el-table {
+      th {
+        background-color: #f8f9fa;
+        font-weight: 600;
+        color: #333;
+      }
+    }
+  }
+
+  .pagination-section {
+    display: flex;
+    justify-content: flex-end;
+    background: #fff;
+    padding: 20px;
+    border-radius: 4px;
+  }
+}
+</style>
diff --git a/src/views/Satisfaction/sfstatistics/components/SatisfactionStatistics.vue b/src/views/Satisfaction/sfstatistics/components/SatisfactionStatistics.vue
new file mode 100644
index 0000000..c1d3a0a
--- /dev/null
+++ b/src/views/Satisfaction/sfstatistics/components/SatisfactionStatistics.vue
@@ -0,0 +1,1809 @@
+<template>
+  <div class="satisfaction-statistics">
+    <!-- 鏌ヨ鏉′欢鍖哄煙 -->
+    <div class="query-section">
+      <el-card shadow="never">
+        <el-form
+          :model="queryParams"
+          ref="queryForm"
+          size="medium"
+          :inline="true"
+          label-width="100px"
+          class="query-form"
+        >
+          <el-form-item label="缁熻绫诲瀷" prop="patientSource">
+            <el-select
+              v-model="queryParams.type"
+              placeholder="璇烽�夋嫨缁熻绫诲瀷"
+              clearable
+              style="width: 100%"
+            >
+              <el-option label="闂嵎绫诲瀷" :value="2" />
+              <el-option label="璇煶绫诲瀷" :value="1" />
+              <el-option label="鍏ㄩ儴" :value="null" />
+            </el-select>
+          </el-form-item>
+
+          <el-form-item label="绉戝" prop="deptCode">
+            <el-select
+              v-model="queryParams.deptCode"
+              placeholder="璇烽�夋嫨绉戝"
+              clearable
+              filterable
+              style="width: 200px"
+              @change="handleDeptChange"
+            >
+              <el-option
+                v-for="dept in deptList"
+                :key="dept.value"
+                :label="dept.label"
+                :value="dept.value"
+              />
+            </el-select>
+          </el-form-item>
+
+          <el-form-item label="鐥呭尯" prop="wardCode">
+            <el-select
+              v-model="queryParams.wardCode"
+              placeholder="璇烽�夋嫨鐥呭尯"
+              clearable
+              filterable
+              style="width: 200px"
+              @change="handleWardChange"
+            >
+              <el-option
+                v-for="ward in wardList"
+                :key="ward.value"
+                :label="ward.label"
+                :value="ward.value"
+              />
+            </el-select>
+          </el-form-item>
+
+          <el-form-item label="缁熻鏃堕棿" prop="dateRange">
+            <el-date-picker
+              v-model="queryParams.dateRange"
+              type="daterange"
+              range-separator="鑷�"
+              start-placeholder="寮�濮嬫棩鏈�"
+              end-placeholder="缁撴潫鏃ユ湡"
+              value-format="yyyy-MM-dd"
+              :picker-options="pickerOptions"
+              style="width: 380px"
+            />
+          </el-form-item>
+
+          <el-form-item>
+            <el-button
+              type="primary"
+              icon="el-icon-search"
+              @click="handleSearch"
+              :loading="loading"
+            >
+              鏌ヨ
+            </el-button>
+            <el-button icon="el-icon-refresh" @click="handleReset">
+              閲嶇疆
+            </el-button>
+          </el-form-item>
+        </el-form>
+      </el-card>
+    </div>
+
+    <!-- 婊℃剰搴︾被鍨嬬粺璁″浘琛� -->
+    <div class="chart-section">
+      <el-card shadow="never">
+        <div class="chart-container">
+          <div class="chart-header">
+            <h3 class="chart-title">婊℃剰搴︾被鍨嬪~鎶ユ瘮渚嬬粺璁�</h3>
+            <div class="statistic-info">
+              <div class="statistic-item">
+                <span class="statistic-label">鍙戦�侀棶鍗锋�婚噺锛�</span>
+                <span class="statistic-value">{{
+                  totalSendCount.toLocaleString()
+                }}</span>
+              </div>
+              <div class="statistic-item">
+                <span class="statistic-label">鍥炴敹闂嵎鎬婚噺锛�</span>
+                <span class="statistic-value">{{
+                  totalReceiveCount.toLocaleString()
+                }}</span>
+              </div>
+              <div class="statistic-item">
+                <span class="statistic-label">鎬讳綋鍥炴敹鐜囷細</span>
+                <span class="statistic-value">{{
+                  formatPercent(overallRecoveryRate)
+                }}</span>
+              </div>
+            </div>
+          </div>
+          <div
+            id="satisfactionBarChart"
+            style="width: 100%; height: 400px"
+          ></div>
+        </div>
+      </el-card>
+    </div>
+
+    <!-- Tab鏍囩椤� -->
+    <div class="tab-section">
+      <el-card shadow="never">
+        <el-tabs v-model="activeTab" @tab-click="handleTabClick">
+          <el-tab-pane label="棰樼洰鏄庣粏缁熻" name="questionDetail">
+            <!-- 棰樼洰鏄庣粏琛ㄦ牸 -->
+            <div class="detail-table-section">
+              <el-table
+                v-loading="detailLoading"
+                :data="questionDetailData"
+                :border="true"
+                style="width: 100%"
+                row-class-name="question-row"
+              >
+                <el-table-column type="expand" width="60">
+                  <template slot-scope="{ row }">
+                    <div class="option-detail">
+                      <el-table
+                        :data="row.options"
+                        :border="true"
+                        style="width: 100%"
+                        class="inner-table"
+                      >
+                        <el-table-column
+                          label="閫夐」"
+                          prop="optionText"
+                          align="center"
+                          min-width="200"
+                        />
+                        <el-table-column
+                          label="閫夋嫨浜烘暟"
+                          prop="chosenQuantity"
+                          align="center"
+                          min-width="120"
+                        />
+                        <el-table-column
+                          label="閫夋嫨姣斾緥"
+                          prop="chosenPercentage"
+                          align="center"
+                          min-width="120"
+                        >
+                          <template slot-scope="{ row: option }">
+                            {{ formatPercent(option.chosenPercentage) }}
+                          </template>
+                        </el-table-column>
+                      </el-table>
+                    </div>
+                  </template>
+                </el-table-column>
+
+                <el-table-column
+                  label="搴忓彿"
+                  type="index"
+                  align="center"
+                  width="60"
+                />
+
+                <el-table-column
+                  label="棰樼洰"
+                  prop="scriptContent"
+                  align="center"
+                  min-width="300"
+                >
+                  <template slot-scope="{ row }">
+                    <span>{{ row.scriptContent }}</span>
+                    <el-tag
+                      :type="row.scriptType === 1 ? 'primary' : 'success'"
+                      size="mini"
+                      style="margin-left: 5px"
+                    >
+                      {{ row.scriptType === 1 ? "鍗曢�夐" : "澶氶�夐" }}
+                    </el-tag>
+                  </template>
+                </el-table-column>
+
+                <el-table-column
+                  label="骞冲潎寰楀垎"
+                  prop="averageScore"
+                  align="center"
+                  width="120"
+                >
+                  <template slot-scope="{ row }">
+                    <span class="score-text">{{
+                      row.averageScore.toFixed(1)
+                    }}</span>
+                  </template>
+                </el-table-column>
+
+                <el-table-column
+                  label="鏈�楂樺緱鍒�"
+                  prop="maxScore"
+                  align="center"
+                  width="120"
+                >
+                  <template slot-scope="{ row }">
+                    <span class="score-text">{{
+                      row.maxScore.toFixed(1)
+                    }}</span>
+                  </template>
+                </el-table-column>
+
+                <el-table-column
+                  label="鏈�浣庡緱鍒�"
+                  prop="minScore"
+                  align="center"
+                  width="120"
+                >
+                  <template slot-scope="{ row }">
+                    <span class="score-text">{{
+                      row.minScore.toFixed(1)
+                    }}</span>
+                  </template>
+                </el-table-column>
+
+                <el-table-column
+                  label="绛旈浜烘暟"
+                  prop="answerCount"
+                  align="center"
+                  width="100"
+                />
+
+                <el-table-column
+                  label="鏈瓟棰樹汉鏁�"
+                  prop="unanswerCount"
+                  align="center"
+                  width="100"
+                >
+                  <template slot-scope="{ row }">
+                    {{ row.noAnswerPerson }}
+                  </template>
+                </el-table-column>
+
+                <el-table-column
+                  label="绛旈鐜�"
+                  prop="answerRate"
+                  align="center"
+                  width="100"
+                >
+                  <template slot-scope="{ row }">
+                    {{ formatPercent(row.answerRate) }}
+                  </template>
+                </el-table-column>
+              </el-table>
+
+              <!-- 缁煎悎寰楀垎琛� -->
+              <div class="summary-row">
+                <div class="summary-content">
+                  <div class="summary-item">
+                    <span class="label">鎬荤瓟棰樹汉鏁帮細</span>
+                    <span class="value">{{ totalAnswerCount }}</span>
+                  </div>
+                  <div class="summary-item">
+                    <span class="label">鎬荤瓟棰樼巼锛�</span>
+                    <span class="value">{{
+                      formatPercent(totalAnswerRate)
+                    }}</span>
+                  </div>
+                </div>
+              </div>
+
+              <!-- 鍒嗛〉 -->
+              <div
+                class="pagination-section"
+                v-if="questionDetailData.length > 0"
+              >
+                <el-pagination
+                  background
+                  layout="total, sizes, prev, pager, next, jumper"
+                  :current-page="detailQueryParams.pageNum"
+                  :page-size="detailQueryParams.pageSize"
+                  :page-sizes="[10, 20, 30]"
+                  :total="detailTotal"
+                  @size-change="handleDetailSizeChange"
+                  @current-change="handleDetailPageChange"
+                />
+              </div>
+            </div>
+          </el-tab-pane>
+
+          <el-tab-pane label="鍚勭被鍨嬬粺璁℃槑缁�" name="typeDetail">
+            <!-- 鍚勭被鍨嬬粺璁℃槑缁嗚〃鏍� -->
+            <div class="type-detail-section">
+              <el-table
+                v-loading="typeDetailLoading"
+                :data="typeDetailData"
+                :border="true"
+                style="width: 100%"
+                class="type-detail-table"
+              >
+                <el-table-column
+                  label="搴忓彿"
+                  type="index"
+                  align="center"
+                  width="60"
+                />
+
+                <el-table-column
+                  label="婊℃剰搴︾被鍨�"
+                  prop="typeName"
+                  align="center"
+                  min-width="150"
+                >
+                  <template slot-scope="{ row }">
+                    <div class="type-name-cell">
+                      <span class="type-name">{{ row.typeName }}</span>
+                      <el-tag
+                        v-if="row.isSpecial"
+                        type="warning"
+                        size="mini"
+                        style="margin-left: 5px"
+                      >
+                        鐗规畩
+                      </el-tag>
+                    </div>
+                  </template>
+                </el-table-column>
+
+                <el-table-column
+                  label="鍙戦�侀棶鍗锋暟"
+                  prop="sendCount"
+                  align="center"
+                  width="120"
+                >
+                  <template slot-scope="{ row }">
+                    <span class="number-text">{{
+                      row.sendCount.toLocaleString()
+                    }}</span>
+                  </template>
+                </el-table-column>
+
+                <el-table-column
+                  label="鍥炴敹闂嵎鏁�"
+                  prop="receiveCount"
+                  align="center"
+                  width="120"
+                >
+                  <template slot-scope="{ row }">
+                    <span class="number-text">{{
+                      row.receiveCount.toLocaleString()
+                    }}</span>
+                  </template>
+                </el-table-column>
+
+                <el-table-column
+                  label="鍥炴敹鐜�"
+                  prop="recoveryRate"
+                  align="center"
+                  width="120"
+                >
+                  <template slot-scope="{ row }">
+                    <span
+                      class="rate-text"
+                      :class="getRateClass(row.recoveryRate)"
+                    >
+                      {{ formatPercent(row.recoveryRate) }}
+                    </span>
+                  </template>
+                </el-table-column>
+
+                <el-table-column
+                  label="骞冲潎鍒�"
+                  prop="averageScore"
+                  align="center"
+                  width="120"
+                >
+                  <template slot-scope="{ row }">
+                    <span class="score-text">{{
+                      row.averageScore.toFixed(1)
+                    }}</span>
+                  </template>
+                </el-table-column>
+
+                <el-table-column
+                  label="婊℃剰搴︾瓑绾�"
+                  prop="satisfactionLevel"
+                  align="center"
+                  width="120"
+                >
+                  <template slot-scope="{ row }">
+                    <el-tag
+                      :type="getLevelTagType(row.satisfactionLevel)"
+                      effect="dark"
+                      size="small"
+                    >
+                      {{ row.satisfactionLevel }}
+                    </el-tag>
+                  </template>
+                </el-table-column>
+
+                <el-table-column
+                  label="瓒嬪娍"
+                  prop="trend"
+                  align="center"
+                  width="120"
+                >
+                  <template slot-scope="{ row }">
+                    <div class="trend-cell">
+                      <i
+                        v-if="row.trend === 'up'"
+                        class="el-icon-top trend-up"
+                        :style="{ color: '#67C23A' }"
+                      />
+                      <i
+                        v-else-if="row.trend === 'down'"
+                        class="el-icon-bottom trend-down"
+                        :style="{ color: '#F56C6C' }"
+                      />
+                      <i
+                        v-else
+                        class="el-icon-minus trend-stable"
+                        :style="{ color: '#909399' }"
+                      />
+                      <span class="trend-text">{{
+                        row.trend === "up"
+                          ? "涓婂崌"
+                          : row.trend === "down"
+                          ? "涓嬮檷"
+                          : "绋冲畾"
+                      }}</span>
+                    </div>
+                  </template>
+                </el-table-column>
+
+                <el-table-column
+                  label="鎿嶄綔"
+                  align="center"
+                  width="120"
+                  fixed="right"
+                >
+                  <template slot-scope="{ row }">
+                    <el-button
+                      type="text"
+                      size="small"
+                      @click="handleTypeDetail(row)"
+                    >
+                      璇︽儏
+                    </el-button>
+                    <el-button
+                      type="text"
+                      size="small"
+                      @click="handleExportData(row)"
+                    >
+                      瀵煎嚭
+                    </el-button>
+                  </template>
+                </el-table-column>
+              </el-table>
+
+              <!-- 绫诲瀷缁熻姹囨�� -->
+              <div class="type-summary-row">
+                <div class="type-summary-content">
+                  <div class="type-summary-item">
+                    <span class="label">绫诲瀷鎬绘暟锛�</span>
+                    <span class="value">{{ typeDetailData.length }}</span>
+                  </div>
+                  <div class="type-summary-item">
+                    <span class="label">骞冲潎鍥炴敹鐜囷細</span>
+                    <span class="value">{{
+                      formatPercent(averageRecoveryRate)
+                    }}</span>
+                  </div>
+                  <div class="type-summary-item">
+                    <span class="label">绫诲瀷骞冲潎鍒嗭細</span>
+                    <span class="value">{{ averageTypeScore.toFixed(1) }}</span>
+                  </div>
+                  <div class="type-summary-item">
+                    <span class="label">楂樻弧鎰忓害绫诲瀷锛�</span>
+                    <span class="value high-count"
+                      >{{ highSatisfactionCount }} 涓�</span
+                    >
+                  </div>
+                </div>
+              </div>
+            </div>
+          </el-tab-pane>
+        </el-tabs>
+      </el-card>
+    </div>
+  </div>
+</template>
+
+<script>
+import * as echarts from "echarts";
+import { statistics, satisfactionGraph } from "@/api/system/user";
+import store from "@/store";
+
+export default {
+  name: "SatisfactionStatistics",
+  data() {
+    return {
+      // 鏌ヨ鍙傛暟
+      queryParams: {
+        type: 2,
+        patientSource: "",
+        deptCode: "",
+        wardCode: "",
+        dateRange: [],
+      },
+
+      // 褰撳墠婵�娲荤殑tab
+      activeTab: "questionDetail",
+
+      // 鎮h�呮潵婧愰�夐」
+      patientSourceList: [
+        { value: "1", label: "闂ㄨ瘖" },
+        { value: "2", label: "浣忛櫌" },
+        { value: "3", label: "鎬ヨ瘖" },
+        { value: "4", label: "鍑洪櫌" },
+      ],
+
+      // 绉戝鍒楄〃
+      deptList: [],
+
+      // 鐥呭尯鍒楄〃
+      wardList: [],
+
+      // 鍥捐〃瀹炰緥
+      barChart: null,
+
+      // 鍔犺浇鐘舵��
+      loading: false,
+      detailLoading: false,
+      typeDetailLoading: false,
+
+      // 棰樼洰鏄庣粏鏁版嵁
+      questionDetailData: [],
+
+      // 棰樼洰鏄庣粏鏌ヨ鍙傛暟
+      detailQueryParams: {
+        pageNum: 1,
+        pageSize: 10,
+      },
+
+      // 棰樼洰鏄庣粏鎬绘暟
+      detailTotal: 0,
+
+      // 缁煎悎寰楀垎
+      totalScore: 0,
+      totalAnswerCount: 0,
+      totalAnswerRate: 0,
+
+      // 鍚勭被鍨嬬粺璁℃槑缁嗘暟鎹�
+      typeDetailData: [],
+
+      // 鏌辩姸鍥炬暟鎹�
+      chartData: [],
+
+      // 缁熻淇℃伅
+      totalSendCount: 0,
+      totalReceiveCount: 0,
+      overallRecoveryRate: 0,
+
+      // 绫诲瀷缁熻姹囨��
+      averageRecoveryRate: 0,
+      averageTypeScore: 0,
+      highSatisfactionCount: 0,
+
+      // 鏃ユ湡閫夋嫨鍣ㄩ�夐」
+      pickerOptions: {
+        shortcuts: [
+          {
+            text: "鏈�杩戜竴鍛�",
+            onClick(picker) {
+              const end = new Date();
+              const start = new Date();
+              start.setTime(start.getTime() - 3600 * 1000 * 24 * 7);
+              picker.$emit("pick", [start, end]);
+            },
+          },
+          {
+            text: "鏈�杩戜竴涓湀",
+            onClick(picker) {
+              const end = new Date();
+              const start = new Date();
+              start.setTime(start.getTime() - 3600 * 1000 * 24 * 30);
+              picker.$emit("pick", [start, end]);
+            },
+          },
+          {
+            text: "鏈�杩戜笁涓湀",
+            onClick(picker) {
+              const end = new Date();
+              const start = new Date();
+              start.setTime(start.getTime() - 3600 * 1000 * 24 * 90);
+              picker.$emit("pick", [start, end]);
+            },
+          },
+        ],
+        disabledDate(time) {
+          return time.getTime() > Date.now();
+        },
+      },
+
+      // 婊℃剰搴︾被鍨嬫暟鎹�
+      satisfactionTypes: [
+        { id: 401, name: "鍑洪櫌婊℃剰搴�", color: "#36B37E" },
+        { id: 402, name: "浣忛櫌婊℃剰搴�", color: "#4CAF50" },
+        { id: 403, name: "闂ㄨ瘖婊℃剰搴�", color: "#409EFF" },
+        { id: 404, name: "甯哥敤婊℃剰搴�", color: "#FF9D4D" },
+      ],
+
+      // 鏂板锛氶粯璁ゆ湇鍔$被鍨嬫暟缁�
+      defaultServiceTypes: ["6", "14", "15", "16"],
+
+      // 鏂板锛氬熀纭�妯℃澘闂ID闆嗗悎
+      scriptIds: [],
+
+      // 鏂板锛氭ā鏉縄D
+      templateId: null,
+    };
+  },
+
+  computed: {
+    // 璁$畻鏌ヨ寮�濮嬫椂闂�
+    startTime() {
+      if (this.queryParams.dateRange && this.queryParams.dateRange[0]) {
+        return this.queryParams.dateRange[0];
+      }
+      // 榛樿鏈�杩�7澶�
+      const date = new Date();
+      date.setDate(date.getDate() - 7);
+      return this.formatDate(date);
+    },
+
+    // 璁$畻鏌ヨ缁撴潫鏃堕棿
+    endTime() {
+      if (this.queryParams.dateRange && this.queryParams.dateRange[1]) {
+        return this.queryParams.dateRange[1];
+      }
+      // 榛樿浠婂ぉ
+      return this.formatDate(new Date());
+    },
+
+    // 璁$畻绉戝缂栫爜鏁扮粍
+    deptCodes() {
+      if (this.queryParams.deptCode) {
+        return [this.queryParams.deptCode];
+      }
+      return this.deptList.map((dept) => dept.value);
+    },
+
+    // 璁$畻鐥呭尯缂栫爜鏁扮粍
+    hospitalDistrictCodes() {
+      if (this.queryParams.wardCode) {
+        return [this.queryParams.wardCode];
+      }
+      return this.wardList.map((ward) => ward.value);
+    },
+  },
+
+  mounted() {
+    this.initData();
+  },
+
+  beforeDestroy() {
+    if (this.barChart) {
+      this.barChart.dispose();
+      this.barChart = null;
+    }
+  },
+
+  methods: {
+    // 鏍煎紡鍖栨棩鏈�
+    formatDate(date) {
+      const year = date.getFullYear();
+      const month = String(date.getMonth() + 1).padStart(2, "0");
+      const day = String(date.getDate()).padStart(2, "0");
+      return `${year}-${month}-${day}`;
+    },
+
+    // 鍒濆鍖栨暟鎹�
+    async initData() {
+      await this.getDeptList();
+      await this.getWardList();
+      this.initChart();
+      await this.loadData();
+    },
+
+    // 鑾峰彇绉戝鍒楄〃
+    getDeptList() {
+      return new Promise((resolve) => {
+        this.deptList = (this.$store.getters.belongDepts || []).map((dept) => {
+          return {
+            label: dept.deptName,
+            value: dept.deptCode,
+          };
+        });
+        resolve();
+      });
+    },
+
+    // 鑾峰彇鐥呭尯鍒楄〃
+    getWardList() {
+      return new Promise((resolve) => {
+        this.wardList = (this.$store.getters.belongWards || []).map((ward) => {
+          return {
+            label: ward.districtName,
+            value: ward.districtCode,
+          };
+        });
+        resolve();
+      });
+    },
+
+    // 鍔犺浇鏁版嵁
+    async loadData() {
+      await Promise.all([
+        this.loadChartData(),
+        this.loadQuestionDetailData(),
+        this.loadTypeDetailData(),
+      ]);
+    },
+
+    // 鍔犺浇鍥捐〃鏁版嵁
+    async loadChartData() {
+      this.loading = true;
+      try {
+        const params = {
+          type: this.queryParams.type,
+          startTime: this.startTime,
+          endTime: this.endTime,
+          deptcodes: this.deptCodes,
+          hospitaldistrictcodes: this.hospitalDistrictCodes,
+          templateid: this.templateId,
+        };
+
+        const response = await satisfactionGraph(params);
+
+        if (response.code === 200) {
+          this.processChartData(response);
+        } else {
+          this.$message.error(response.msg || "鑾峰彇鍥捐〃鏁版嵁澶辫触");
+          // 浣跨敤mock鏁版嵁
+          await this.generateMockChartData();
+        }
+      } catch (error) {
+        console.error("鑾峰彇鍥捐〃鏁版嵁鍑洪敊:", error);
+        this.$message.error("鑾峰彇鍥捐〃鏁版嵁澶辫触");
+        // 閿欒鏃朵娇鐢╩ock鏁版嵁
+        await this.generateMockChartData();
+      } finally {
+        this.loading = false;
+      }
+    },
+
+    // 澶勭悊鍥捐〃鏁版嵁
+    processChartData(apiData) {
+      if (!apiData || !apiData.rows || Object.keys(apiData.rows).length === 0) {
+        this.chartData = [];
+        this.totalSendCount = 0;
+        this.totalReceiveCount = 0;
+        this.overallRecoveryRate = 0;
+        this.renderChart([]);
+        return;
+      }
+
+      const chartData = [];
+      let totalSend = 0;
+      let totalReceive = 0;
+      let index = 0;
+
+      // 澶勭悊鎺ュ彛杩斿洖鐨勬弧鎰忓害绫诲瀷缁熻
+      Object.entries(apiData.rows).forEach(([typeName, typeStat]) => {
+        const sendCount = typeStat.subidAll || 0;
+        const receiveCount = typeStat.fillCountAll || 0;
+        const recoveryRate = typeStat.receiveRate || 0;
+
+        chartData.push({
+          name: typeName,
+          value: recoveryRate * 100, // 杞崲涓虹櫨鍒嗘瘮
+          sendCount: sendCount,
+          receiveCount: receiveCount,
+          averageScore: typeStat.averageScore || 0,
+          itemStyle: { color: this.getChartColor(index) },
+        });
+
+        totalSend += sendCount;
+        totalReceive += receiveCount;
+        index++;
+      });
+
+      this.totalSendCount = totalSend;
+      this.totalReceiveCount = totalReceive;
+      this.overallRecoveryRate = totalSend > 0 ? totalReceive / totalSend : 0;
+      this.chartData = chartData;
+
+      this.renderChart(chartData);
+    },
+
+    // 鍔犺浇棰樼洰鏄庣粏鏁版嵁
+    async loadQuestionDetailData() {
+      this.detailLoading = true;
+      try {
+        const params = {
+          type: this.queryParams.type,
+          startTime: this.startTime,
+          endTime: this.endTime,
+          scriptids: this.scriptIds,
+          templateid: this.templateId,
+        };
+
+        const response = await statistics(params);
+
+        if (response.code === 200) {
+          this.processQuestionDetailData(response.rows);
+        } else {
+          this.$message.error(response.msg || "鑾峰彇棰樼洰鏄庣粏鏁版嵁澶辫触");
+          const mockData = await this.generateMockQuestionDetail();
+          this.questionDetailData = mockData.list;
+          this.detailTotal = mockData.total;
+          this.calculateSummary(mockData);
+        }
+      } catch (error) {
+        console.error("鑾峰彇棰樼洰鏄庣粏鏁版嵁鍑洪敊:", error);
+        this.$message.error("鑾峰彇棰樼洰鏄庣粏鏁版嵁澶辫触");
+        const mockData = await this.generateMockQuestionDetail();
+        this.questionDetailData = mockData.list;
+        this.detailTotal = mockData.total;
+        this.calculateSummary(mockData);
+      } finally {
+        this.detailLoading = false;
+      }
+    },
+
+    // 澶勭悊鎺ュ彛杩斿洖鐨勯鐩槑缁嗘暟鎹�
+    processQuestionDetailData(apiData) {
+      if (!apiData || !apiData.patSatisfactionDetailEntities) {
+        this.questionDetailData = [];
+        this.detailTotal = 0;
+        this.totalAnswerCount = 0;
+        this.totalAnswerRate = 0;
+        return;
+      }
+
+      const detailData = apiData.patSatisfactionDetailEntities.map((item) => {
+        const options = [];
+        if (item.matchedtextStats) {
+          Object.keys(item.matchedtextStats).forEach((key) => {
+            const stat = item.matchedtextStats[key];
+            options.push({
+              optionText: key,
+              chosenQuantity: stat.count || 0,
+              chosenPercentage: (stat.ratio || 0) / 100,
+            });
+          });
+        }
+
+        return {
+          scriptContent: item.scriptContent || "",
+          scriptType: 1,
+          answerPerson: item.answerPerson || 0,
+          noAnswerPerson: item.noAnswerPerson || 0,
+          answerCount: item.answerPerson || 0,
+          averageScore: item.averageScore || 0,
+          maxScore: item.maxScore || 0,
+          minScore: item.minScore || 0,
+          answerRate: item.answerRate || 0,
+          totalCount: (item.answerPerson || 0) + (item.noAnswerPerson || 0),
+          options: options,
+        };
+      });
+
+      const startIndex =
+        (this.detailQueryParams.pageNum - 1) * this.detailQueryParams.pageSize;
+      const endIndex = startIndex + this.detailQueryParams.pageSize;
+      const paginatedData = detailData.slice(startIndex, endIndex);
+
+      this.questionDetailData = paginatedData;
+      this.detailTotal = detailData.length;
+      this.totalAnswerCount = apiData.totalPerson || 0;
+      this.totalAnswerRate = apiData.totalAnswerRate || 0;
+    },
+
+    // 鍔犺浇绫诲瀷鏄庣粏鏁版嵁
+    async loadTypeDetailData() {
+      this.typeDetailLoading = true;
+      try {
+        const params = {
+          type: this.queryParams.type,
+          startTime: this.startTime,
+          endTime: this.endTime,
+          deptcodes: this.deptCodes,
+          hospitaldistrictcodes: this.hospitalDistrictCodes,
+          templateid: this.templateId,
+        };
+
+        const response = await satisfactionGraph(params);
+
+        if (response.code === 200) {
+          this.processTypeDetailData(response.data);
+        } else {
+          this.$message.error(response.msg || "鑾峰彇绫诲瀷鏄庣粏鏁版嵁澶辫触");
+          const mockData = await this.generateMockTypeDetail();
+          this.typeDetailData = mockData;
+          this.calculateTypeSummary(mockData);
+        }
+      } catch (error) {
+        console.error("鑾峰彇绫诲瀷鏄庣粏鏁版嵁鍑洪敊:", error);
+        this.$message.error("鑾峰彇绫诲瀷鏄庣粏鏁版嵁澶辫触");
+        const mockData = await this.generateMockTypeDetail();
+        this.typeDetailData = mockData;
+        this.calculateTypeSummary(mockData);
+      } finally {
+        this.typeDetailLoading = false;
+      }
+    },
+
+    // 澶勭悊绫诲瀷鏄庣粏鏁版嵁
+    processTypeDetailData(apiData) {
+      if (!apiData || !apiData.rows || Object.keys(apiData.rows).length === 0) {
+        this.typeDetailData = [];
+        this.calculateTypeSummary([]);
+        return;
+      }
+
+      const typeDetail = [];
+      Object.entries(apiData.rows).forEach(([typeName, typeStat], index) => {
+        const sendCount = typeStat.subidAll || 0;
+        const receiveCount = typeStat.fillCountAll || 0;
+        const recoveryRate = typeStat.receiveRate || 0;
+        const averageScore = typeStat.averageScore || 0;
+
+        typeDetail.push({
+          id: index + 1,
+          typeName: typeName,
+          isSpecial: false, // 鏍规嵁瀹為檯鎯呭喌鍒ゆ柇
+          sendCount: sendCount,
+          receiveCount: receiveCount,
+          recoveryRate: recoveryRate,
+          averageScore: averageScore,
+          maxScore: 5, // 榛樿鍊�
+          minScore: 0, // 榛樿鍊�
+          satisfactionLevel: this.getSatisfactionLevel(averageScore),
+          trend: "stable", // 榛樿绋冲畾
+        });
+      });
+
+      this.typeDetailData = typeDetail;
+      this.calculateTypeSummary(typeDetail);
+    },
+
+    // 鏍规嵁骞冲潎鍒嗚幏鍙栨弧鎰忓害绛夌骇
+    getSatisfactionLevel(score) {
+      if (score >= 4.5) return "浼樼";
+      if (score >= 4.0) return "鑹ソ";
+      if (score >= 3.0) return "涓�鑸�";
+      if (score >= 2.0) return "杈冨樊";
+      return "宸�";
+    },
+
+    // 鑾峰彇瓒嬪娍
+    getTrend(trend) {
+      if (trend > 0.1) return "up";
+      if (trend < -0.1) return "down";
+      return "stable";
+    },
+
+    // 璁$畻缁煎悎寰楀垎
+    calculateSummary(data) {
+      let totalScore = 0;
+      let totalAnswerCount = 0;
+      let totalCount = 0;
+
+      data.list.forEach((item) => {
+        totalScore += item.averageScore;
+        totalAnswerCount += item.answerCount;
+        totalCount += item.totalCount;
+      });
+
+      this.totalScore =
+        data.list.length > 0 ? totalScore / data.list.length : 0;
+      this.totalAnswerCount = totalAnswerCount;
+      this.totalAnswerRate = totalCount > 0 ? totalAnswerCount / totalCount : 0;
+    },
+
+    // 璁$畻绫诲瀷缁熻姹囨��
+    calculateTypeSummary(data) {
+      if (data.length === 0) {
+        this.averageRecoveryRate = 0;
+        this.averageTypeScore = 0;
+        this.highSatisfactionCount = 0;
+        return;
+      }
+
+      let totalRecoveryRate = 0;
+      let totalTypeScore = 0;
+      let highCount = 0;
+
+      data.forEach((item) => {
+        totalRecoveryRate += item.recoveryRate;
+        totalTypeScore += item.averageScore;
+        if (
+          item.satisfactionLevel === "浼樼" ||
+          item.satisfactionLevel === "鑹ソ"
+        ) {
+          highCount++;
+        }
+      });
+
+      this.averageRecoveryRate = totalRecoveryRate / data.length;
+      this.averageTypeScore = totalTypeScore / data.length;
+      this.highSatisfactionCount = highCount;
+    },
+
+    // 鍒濆鍖栧浘琛�
+    initChart() {
+      const chartDom = document.getElementById("satisfactionBarChart");
+      if (!chartDom) return;
+
+      this.barChart = echarts.init(chartDom);
+      window.addEventListener("resize", this.handleChartResize);
+    },
+
+    // 娓叉煋鍥捐〃
+    renderChart(chartData) {
+      if (!this.barChart) return;
+ if (!chartData || chartData.length === 0) {
+    const emptyOption = {
+      title: {
+        text: "鏆傛棤鏁版嵁",
+        left: "center",
+        top: "center",
+        textStyle: {
+          color: "#999",
+          fontSize: 16,
+          fontWeight: "normal"
+        }
+      },
+      xAxis: { show: false },
+      yAxis: { show: false }
+    };
+    this.barChart.setOption(emptyOption);
+    return;
+  }
+      const option = {
+        title: {
+          text: "",
+          left: "center",
+        },
+        tooltip: {
+          trigger: "axis",
+          axisPointer: {
+            type: "shadow",
+          },
+          formatter: (params) => {
+            const data = params[0];
+            return `
+              <div style="margin-bottom: 5px; font-weight: bold; color: #333;">
+                ${data.name}
+              </div>
+              <div style="margin: 2px 0;">
+                <span style="display:inline-block;width:10px;height:10px;border-radius:2px;background:${
+                  data.color
+                };margin-right:5px;"></span>
+                濉姤姣斾緥: <strong>${data.value.toFixed(1)}%</strong>
+              </div>
+              <div style="margin: 2px 0;">
+                <span style="display:inline-block;width:10px;height:10px;border-radius:2px;background:#eee;margin-right:5px;"></span>
+                鍙戦�侀棶鍗�: <strong>${data.data.sendCount.toLocaleString()}</strong>
+              </div>
+              <div style="margin: 2px 0;">
+                <span style="display:inline-block;width:10px;height:10px;border-radius:2px;background:#eee;margin-right:5px;"></span>
+                鍥炴敹闂嵎: <strong>${data.data.receiveCount.toLocaleString()}</strong>
+              </div>
+            `;
+          },
+        },
+        grid: {
+          left: "3%",
+          right: "4%",
+          bottom: "3%",
+          top: 60,
+          containLabel: true,
+        },
+        xAxis: {
+          type: "category",
+          data: chartData.map((item) => item.name),
+          axisLabel: {
+            interval: 0,
+            rotate: 0,
+            fontSize: 12,
+            color: "#666",
+          },
+          axisLine: {
+            lineStyle: {
+              color: "#DCDFE6",
+            },
+          },
+          axisTick: {
+            alignWithLabel: true,
+          },
+        },
+        yAxis: {
+          type: "value",
+          name: "濉姤姣斾緥 (%)",
+          min: 0,
+          max: 100,
+          axisLabel: {
+            formatter: "{value}%",
+            color: "#666",
+          },
+          axisLine: {
+            lineStyle: {
+              color: "#DCDFE6",
+            },
+          },
+          splitLine: {
+            lineStyle: {
+              type: "dashed",
+              color: "#E4E7ED",
+            },
+          },
+        },
+        series: [
+          {
+            name: "濉姤姣斾緥",
+            type: "bar",
+            barWidth: 40,
+            data: chartData,
+            itemStyle: {
+              color: (params) => {
+                return params.data.itemStyle.color;
+              },
+            },
+            label: {
+              show: true,
+              position: "top",
+              formatter: "{c}%",
+              fontSize: 12,
+              color: "#333",
+            },
+          },
+        ],
+      };
+
+      this.barChart.setOption(option);
+    },
+
+    // 鐢熸垚Mock鍥捐〃鏁版嵁
+    generateMockChartData() {
+      return new Promise((resolve) => {
+        setTimeout(() => {
+          const data = this.satisfactionTypes.map((type, index) => ({
+            name: type.name,
+            recoveryRate: Math.random() * 0.3 + 0.6,
+            sendCount: Math.floor(Math.random() * 3000) + 1500,
+            receiveCount: 0,
+            color: type.color,
+          }));
+
+          data.forEach((item) => {
+            item.receiveCount = Math.floor(item.sendCount * item.recoveryRate);
+          });
+
+          this.totalSendCount = data.reduce(
+            (sum, item) => sum + item.sendCount,
+            0
+          );
+          this.totalReceiveCount = data.reduce(
+            (sum, item) => sum + item.receiveCount,
+            0
+          );
+          this.overallRecoveryRate =
+            this.totalSendCount > 0
+              ? this.totalReceiveCount / this.totalSendCount
+              : 0;
+
+          const chartData = data.map((item) => ({
+            name: item.name,
+            value: item.recoveryRate * 100,
+            sendCount: item.sendCount,
+            receiveCount: item.receiveCount,
+            itemStyle: { color: item.color },
+          }));
+
+          this.chartData = chartData;
+          this.renderChart(chartData);
+          resolve();
+        }, 300);
+      });
+    },
+
+    // 鐢熸垚Mock棰樼洰璇︽儏鏁版嵁
+    generateMockQuestionDetail() {
+      return new Promise((resolve) => {
+        setTimeout(() => {
+          const questions = [
+            {
+              scriptContent: "鎮ㄥ鏈灏卞尰鐨勬暣浣撴弧鎰忕▼搴︼紵",
+              scriptType: 1,
+              answerPerson: 120,
+              noAnswerPerson: 30,
+              answerCount: 120,
+              totalCount: 150,
+              averageScore: 4.2,
+              maxScore: 5.0,
+              minScore: 1.0,
+              answerRate: 0.8,
+              options: [
+                {
+                  optionText: "闈炲父婊℃剰",
+                  chosenQuantity: 60,
+                  chosenPercentage: 0.5,
+                },
+                {
+                  optionText: "婊℃剰",
+                  chosenQuantity: 36,
+                  chosenPercentage: 0.3,
+                },
+                {
+                  optionText: "涓�鑸�",
+                  chosenQuantity: 18,
+                  chosenPercentage: 0.15,
+                },
+                {
+                  optionText: "涓嶆弧鎰�",
+                  chosenQuantity: 6,
+                  chosenPercentage: 0.05,
+                },
+              ],
+            },
+            {
+              scriptContent: "鎮ㄥ鍖绘姢浜哄憳鐨勬湇鍔℃�佸害鏄惁婊℃剰锛�",
+              scriptType: 1,
+              answerPerson: 145,
+              noAnswerPerson: 11,
+              answerCount: 145,
+              totalCount: 156,
+              averageScore: 4.5,
+              maxScore: 5,
+              minScore: 3,
+              answerRate: 0.93,
+              options: [
+                {
+                  optionText: "闈炲父婊℃剰",
+                  chosenQuantity: 89,
+                  chosenPercentage: 0.61,
+                },
+                {
+                  optionText: "婊℃剰",
+                  chosenQuantity: 45,
+                  chosenPercentage: 0.31,
+                },
+                {
+                  optionText: "涓�鑸�",
+                  chosenQuantity: 8,
+                  chosenPercentage: 0.06,
+                },
+                {
+                  optionText: "涓嶆弧鎰�",
+                  chosenQuantity: 2,
+                  chosenPercentage: 0.01,
+                },
+                {
+                  optionText: "闈炲父涓嶆弧鎰�",
+                  chosenQuantity: 1,
+                  chosenPercentage: 0.01,
+                },
+              ],
+            },
+          ];
+
+          const startIndex =
+            (this.detailQueryParams.pageNum - 1) *
+            this.detailQueryParams.pageSize;
+          const endIndex = startIndex + this.detailQueryParams.pageSize;
+          const paginatedData = questions.slice(startIndex, endIndex);
+
+          resolve({
+            list: paginatedData,
+            total: questions.length,
+          });
+        }, 300);
+      });
+    },
+
+    // 鐢熸垚Mock绫诲瀷鏄庣粏鏁版嵁
+    generateMockTypeDetail() {
+      return new Promise((resolve) => {
+        setTimeout(() => {
+          const types = [
+            {
+              id: 401,
+              typeName: "鍑洪櫌婊℃剰搴�",
+              isSpecial: false,
+              sendCount: 2850,
+              receiveCount: 2680,
+              recoveryRate: 0.94,
+              averageScore: 4.8,
+              maxScore: 5,
+              minScore: 3.8,
+              satisfactionLevel: "浼樼",
+              trend: "up",
+            },
+            {
+              id: 402,
+              typeName: "浣忛櫌婊℃剰搴�",
+              isSpecial: false,
+              sendCount: 2620,
+              receiveCount: 2405,
+              recoveryRate: 0.918,
+              averageScore: 4.6,
+              maxScore: 5,
+              minScore: 3.5,
+              satisfactionLevel: "浼樼",
+              trend: "stable",
+            },
+            {
+              id: 403,
+              typeName: "闂ㄨ瘖婊℃剰搴�",
+              isSpecial: false,
+              sendCount: 3780,
+              receiveCount: 3220,
+              recoveryRate: 0.852,
+              averageScore: 4.3,
+              maxScore: 5,
+              minScore: 2.5,
+              satisfactionLevel: "鑹ソ",
+              trend: "up",
+            },
+            {
+              id: 404,
+              typeName: "甯哥敤婊℃剰搴�",
+              isSpecial: true,
+              sendCount: 1950,
+              receiveCount: 1780,
+              recoveryRate: 0.913,
+              averageScore: 4.5,
+              maxScore: 5,
+              minScore: 3.2,
+              satisfactionLevel: "鑹ソ",
+              trend: "stable",
+            },
+          ];
+
+          resolve(types);
+        }, 300);
+      });
+    },
+
+    // 鑾峰彇鍥捐〃棰滆壊
+    getChartColor(index) {
+      const colors = [
+        "#36B37E",
+        "#4CAF50",
+        "#409EFF",
+        "#FF9D4D",
+        "#9B8DFF",
+        "#FF6B6B",
+      ];
+      return colors[index % colors.length];
+    },
+
+    // 澶勭悊鍥捐〃鍝嶅簲寮�
+    handleChartResize() {
+      if (this.barChart) {
+        this.barChart.resize();
+      }
+    },
+
+    // 澶勭悊鏌ヨ
+    handleSearch() {
+      this.detailQueryParams.pageNum = 1;
+      this.loadData();
+      // 寮哄埗閲嶆柊娓叉煋鍥捐〃
+      setTimeout(() => {
+        if (this.chartData.length === 0) {
+          this.renderChart([]);
+        }
+      }, 100);
+    },
+
+    // 澶勭悊閲嶇疆
+    handleReset() {
+      this.$refs.queryForm.resetFields();
+      this.queryParams.dateRange = [];
+      this.detailQueryParams.pageNum = 1;
+      this.loadData();
+    },
+
+    // 澶勭悊Tab鍒囨崲
+    handleTabClick(tab) {
+      if (tab.name === "typeDetail" && this.typeDetailData.length === 0) {
+        this.loadTypeDetailData();
+      }
+    },
+
+    // 澶勭悊鏄庣粏鍒嗛〉澶у皬鍙樺寲
+    handleDetailSizeChange(size) {
+      this.detailQueryParams.pageSize = size;
+      this.detailQueryParams.pageNum = 1;
+      this.loadQuestionDetailData();
+    },
+
+    // 澶勭悊鏄庣粏椤电爜鍙樺寲
+    handleDetailPageChange(page) {
+      this.detailQueryParams.pageNum = page;
+      this.loadQuestionDetailData();
+    },
+
+    // 澶勭悊绫诲瀷璇︽儏
+    handleTypeDetail(row) {
+      this.$message.info(`鏌ョ湅绫诲瀷璇︽儏锛�${row.typeName}`);
+    },
+
+    // 澶勭悊瀵煎嚭鏁版嵁
+    handleExportData(row) {
+      this.$message.success(`姝e湪瀵煎嚭 ${row.typeName} 鏁版嵁...`);
+    },
+
+    // 鏍煎紡鍖栫櫨鍒嗘瘮
+    formatPercent(value) {
+   if (value === null || value === undefined) return "-";
+  const num = parseFloat(value);
+  if (isNaN(num)) return "-";
+  // 濡傛灉鍊煎皬浜�1锛岃涓烘槸灏忔暟姣斾緥锛岄渶瑕佷箻浠�100
+  const percentValue = num < 1 ? num * 100 : num;
+  return `${percentValue.toFixed(2)}%`;
+    },
+
+    // 鑾峰彇鍥炴敹鐜囨牱寮忕被
+    getRateClass(rate) {
+      if (rate >= 0.9) return "rate-high";
+      if (rate >= 0.8) return "rate-medium";
+      return "rate-low";
+    },
+
+    // 鑾峰彇婊℃剰搴︾瓑绾ф爣绛剧被鍨�
+    getLevelTagType(level) {
+      const levelMap = {
+        浼樼: "success",
+        鑹ソ: "primary",
+        涓�鑸�: "warning",
+        杈冨樊: "danger",
+        宸�: "info",
+      };
+      return levelMap[level] || "info";
+    },
+
+    // 澶勭悊绉戝閫夋嫨鍙樺寲
+    handleDeptChange() {
+      this.loadData();
+    },
+
+    // 澶勭悊鐥呭尯閫夋嫨鍙樺寲
+    handleWardChange() {
+      this.loadData();
+    },
+  },
+};
+</script>
+
+<style lang="scss" scoped>
+.satisfaction-statistics {
+  padding: 20px;
+  background-color: #f5f7fa;
+  min-height: 100vh;
+
+  .query-section {
+    margin-bottom: 20px;
+
+    .query-form {
+      display: flex;
+      flex-wrap: wrap;
+      align-items: center;
+
+      ::v-deep .el-form-item {
+        margin-bottom: 0;
+        margin-right: 20px;
+
+        &:last-child {
+          margin-right: 0;
+        }
+      }
+    }
+  }
+
+  .chart-section {
+    margin-bottom: 20px;
+
+    .chart-container {
+      .chart-header {
+        display: flex;
+        justify-content: space-between;
+        align-items: center;
+        margin-bottom: 20px;
+        padding-bottom: 15px;
+        border-bottom: 1px solid #f0f0f0;
+
+        .chart-title {
+          margin: 0;
+          font-size: 16px;
+          font-weight: 600;
+          color: #303133;
+        }
+
+        .statistic-info {
+          display: flex;
+          gap: 30px;
+          align-items: center;
+
+          .statistic-item {
+            display: flex;
+            align-items: center;
+            gap: 8px;
+
+            .statistic-label {
+              font-size: 14px;
+              color: #606266;
+            }
+
+            .statistic-value {
+              font-size: 18px;
+              font-weight: 600;
+              color: #409eff;
+            }
+          }
+        }
+      }
+    }
+  }
+
+  .tab-section {
+    ::v-deep .el-tabs__header {
+      margin-bottom: 0;
+    }
+
+    ::v-deep .el-tabs__content {
+      padding: 20px 0 0 0;
+    }
+  }
+
+  .detail-table-section {
+    .option-detail {
+      padding: 15px;
+      background: #f8f9fa;
+      border-radius: 4px;
+      margin: 10px 0;
+    }
+
+    ::v-deep .el-table {
+      th {
+        background-color: #f8f9fa;
+        font-weight: 600;
+        color: #333;
+        padding: 12px 0;
+      }
+
+      td {
+        padding: 12px 0;
+      }
+
+      .question-row {
+        td {
+          background-color: #fff;
+        }
+
+        &:hover {
+          td {
+            background-color: #f5f7fa;
+          }
+        }
+      }
+    }
+
+    .score-text {
+      font-weight: 600;
+      color: #1890ff;
+      font-size: 16px;
+    }
+
+    .summary-row {
+      margin-top: 20px;
+      padding: 20px;
+      background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%);
+      border-radius: 8px;
+      border: 1px solid #dee2e6;
+
+      .summary-content {
+        display: flex;
+        justify-content: space-around;
+        align-items: center;
+
+        .summary-item {
+          text-align: center;
+
+          .label {
+            font-size: 16px;
+            color: #606266;
+            margin-right: 8px;
+          }
+
+          .value {
+            font-size: 24px;
+            font-weight: 600;
+            color: #409eff;
+          }
+        }
+      }
+    }
+
+    .pagination-section {
+      display: flex;
+      justify-content: center;
+      padding: 20px 0 0 0;
+    }
+  }
+
+  .type-detail-section {
+    .type-detail-table {
+      ::v-deep .el-table__header-wrapper {
+        th {
+          background-color: #f0f7ff;
+          font-weight: 600;
+          color: #333;
+        }
+      }
+
+      .type-name-cell {
+        display: flex;
+        align-items: center;
+        justify-content: center;
+
+        .type-name {
+          font-weight: 500;
+        }
+      }
+
+      .number-text {
+        font-weight: 600;
+        color: #333;
+      }
+
+      .rate-text {
+        font-weight: 600;
+        font-size: 14px;
+
+        &.rate-high {
+          color: #67c23a;
+        }
+
+        &.rate-medium {
+          color: #e6a23c;
+        }
+
+        &.rate-low {
+          color: #f56c6c;
+        }
+      }
+
+      .score-text {
+        font-weight: 600;
+        color: #409eff;
+        font-size: 15px;
+      }
+
+      .trend-cell {
+        display: flex;
+        align-items: center;
+        justify-content: center;
+        gap: 5px;
+
+        .trend-up,
+        .trend-down,
+        .trend-stable {
+          font-size: 16px;
+        }
+
+        .trend-text {
+          font-size: 13px;
+          color: #666;
+        }
+      }
+    }
+
+    .type-summary-row {
+      margin-top: 20px;
+      padding: 20px;
+      background: linear-gradient(135deg, #f0f9ff 0%, #e6f7ff 100%);
+      border-radius: 8px;
+      border: 1px solid #d0ebff;
+
+      .type-summary-content {
+        display: flex;
+        justify-content: space-around;
+        align-items: center;
+        flex-wrap: wrap;
+        gap: 20px;
+
+        .type-summary-item {
+          text-align: center;
+          min-width: 150px;
+
+          .label {
+            font-size: 14px;
+            color: #606266;
+            margin-right: 8px;
+          }
+
+          .value {
+            font-size: 20px;
+            font-weight: 600;
+            color: #409eff;
+          }
+
+          .high-count {
+            color: #67c23a;
+          }
+        }
+      }
+    }
+  }
+
+  // 鍐呭眰琛ㄦ牸鏍峰紡
+  .inner-table {
+    ::v-deep .el-table__header-wrapper {
+      th {
+        background-color: #f0f7ff !important;
+        color: #333;
+        font-weight: 600;
+      }
+    }
+
+    ::v-deep .el-table__body-wrapper {
+      tr {
+        background-color: #fff;
+
+        &:hover {
+          background-color: #f5f7fa;
+        }
+      }
+    }
+  }
+}
+
+@media (max-width: 768px) {
+  .satisfaction-statistics {
+    padding: 10px;
+
+    .query-section {
+      .query-form {
+        ::v-deep .el-form-item {
+          width: 100%;
+          margin-right: 0;
+          margin-bottom: 10px;
+        }
+      }
+    }
+
+    .chart-section {
+      .chart-container {
+        .chart-header {
+          flex-direction: column;
+          align-items: flex-start;
+          gap: 15px;
+
+          .statistic-info {
+            width: 100%;
+            justify-content: space-between;
+            flex-wrap: wrap;
+            gap: 10px;
+          }
+        }
+      }
+    }
+
+    .detail-table-section {
+      .summary-content {
+        flex-direction: column;
+        gap: 15px;
+      }
+    }
+
+    .type-detail-section {
+      .type-summary-content {
+        flex-direction: column;
+        gap: 15px;
+      }
+    }
+  }
+}
+</style>
diff --git a/src/views/Satisfaction/sfstatistics/components/components/SeedetailsDialog.vue b/src/views/Satisfaction/sfstatistics/components/components/SeedetailsDialog.vue
new file mode 100644
index 0000000..ce29cd3
--- /dev/null
+++ b/src/views/Satisfaction/sfstatistics/components/components/SeedetailsDialog.vue
@@ -0,0 +1,401 @@
+<template>
+  <div class="seedetails-dialog">
+    <div class="examine-jic">
+      <div class="jic-value">
+        <!-- 鏌ヨ琛ㄥ崟 -->
+        <el-form
+          :model="patientqueryParams"
+          ref="patientQueryForm"
+          size="small"
+          :inline="true"
+          class="detail-query-form"
+        >
+          <el-form-item label="鎮h�咃細" prop="name">
+            <el-input
+              v-model="patientqueryParams.name"
+              placeholder="璇疯緭鍏ユ偅鑰呭鍚�"
+              clearable
+              @keyup.enter.native="handleSearch"
+              style="width: 180px"
+            />
+          </el-form-item>
+
+          <el-form-item label="鎮h�呰瘖鏂細" prop="leavediagname">
+            <el-input
+              v-model="patientqueryParams.leavediagname"
+              placeholder="璇疯緭鍏ユ偅鑰呰瘖鏂�"
+              clearable
+              @keyup.enter.native="handleSearch"
+              style="width: 200px"
+            />
+          </el-form-item>
+
+          <el-form-item>
+            <el-button
+              type="primary"
+              icon="el-icon-search"
+              @click="handleSearch"
+              :loading="loading"
+            >
+              鎼滅储
+            </el-button>
+            <el-button icon="el-icon-refresh" @click="handleReset">
+              閲嶇疆
+            </el-button>
+          </el-form-item>
+        </el-form>
+
+        <!-- 鎮h�呭垪琛ㄨ〃鏍� -->
+        <el-table
+          v-loading="loading"
+          :data="logsheetlist"
+          style="width: 100%"
+          :border="true"
+          class="patient-table"
+        >
+          <el-table-column
+            prop="sendname"
+            label="濮撳悕"
+            align="center"
+            width="100"
+          />
+
+          <el-table-column
+            prop="taskName"
+            label="浠诲姟鍚嶇О"
+            align="center"
+            width="200"
+            show-overflow-tooltip
+          />
+
+          <el-table-column
+            prop="sendstate"
+            label="浠诲姟鐘舵��"
+            align="center"
+            width="120"
+          >
+            <template slot-scope="{ row }">
+              <div v-if="row.sendstate == 1">
+                <el-tag type="primary" size="small">琛ㄥ崟宸查鍙�</el-tag>
+              </div>
+              <div v-if="row.sendstate == 2">
+                <el-tag type="primary" size="small">寰呴殢璁�</el-tag>
+              </div>
+              <div v-if="row.sendstate == 3">
+                <el-tag type="success" size="small">琛ㄥ崟宸插彂閫�</el-tag>
+              </div>
+              <div v-if="row.sendstate == 4">
+                <el-tag type="info" size="small">涓嶆墽琛�</el-tag>
+              </div>
+              <div v-if="row.sendstate == 5">
+                <el-tag type="danger" size="small">鍙戦�佸け璐�</el-tag>
+              </div>
+              <div v-if="row.sendstate == 6">
+                <el-tag type="success" size="small">宸插畬鎴�</el-tag>
+              </div>
+            </template>
+          </el-table-column>
+
+          <el-table-column
+            prop="visitTime"
+            label="搴旈殢璁挎椂闂�"
+            align="center"
+            width="180"
+            show-overflow-tooltip
+          />
+
+          <el-table-column
+            prop="finishtime"
+            label="闅忚瀹屾垚鏃堕棿"
+            align="center"
+            width="180"
+            show-overflow-tooltip
+          >
+            <template slot-scope="{ row }">
+              <span v-if="row.finishtime">{{ row.finishtime }}</span>
+              <span v-else style="color: #f56c6c">鏈畬鎴�</span>
+            </template>
+          </el-table-column>
+
+          <el-table-column
+            label="鍑洪櫌鏃ユ湡"
+            width="120"
+            align="center"
+            key="endtime"
+            prop="endtime"
+          >
+            <template slot-scope="{ row }">
+              <span v-if="row.endtime">{{ formatTime(row.endtime) }}</span>
+              <span v-else>-</span>
+            </template>
+          </el-table-column>
+
+          <el-table-column
+            label="璐d换鎶ゅ+"
+            width="120"
+            align="center"
+            key="nurseName"
+            prop="nurseName"
+          />
+
+          <el-table-column
+            label="涓绘不鍖荤敓"
+            width="120"
+            align="center"
+            key="drname"
+            prop="drname"
+          />
+
+          <el-table-column
+            label="缁撴灉鐘舵��"
+            align="center"
+            key="excep"
+            prop="excep"
+            width="120"
+          >
+            <template slot-scope="{ row }">
+              <dict-tag
+                :options="dict.type.sys_yujing"
+                :value="row.excep"
+                size="small"
+              />
+            </template>
+          </el-table-column>
+
+          <el-table-column
+            label="澶勭悊鎰忚"
+            align="center"
+            key="suggest"
+            prop="suggest"
+            width="120"
+          >
+            <template slot-scope="{ row }">
+              <dict-tag
+                :options="dict.type.sys_suggest"
+                :value="row.suggest"
+                size="small"
+              />
+            </template>
+          </el-table-column>
+
+          <el-table-column
+            prop="templatename"
+            label="鏈嶅姟妯℃澘"
+            width="150"
+            align="center"
+            show-overflow-tooltip
+          />
+
+          <el-table-column
+            prop="remark"
+            label="鏈嶅姟璁板綍"
+            width="150"
+            align="center"
+            show-overflow-tooltip
+          />
+
+          <el-table-column
+            prop="bankcardno"
+            label="鍛煎彨鐘舵��"
+            width="120"
+            align="center"
+          />
+
+          <el-table-column
+            label="鎿嶄綔"
+            fixed="right"
+            align="center"
+            width="100"
+          >
+            <template slot-scope="{ row }">
+              <el-button
+                type="text"
+                size="small"
+                @click="handleViewDetail(row)"
+              >
+                <i class="el-icon-view"></i> 鏌ョ湅
+              </el-button>
+            </template>
+          </el-table-column>
+        </el-table>
+
+        <!-- 鍒嗛〉 -->
+        <div class="pagination" v-if="patienttotal > 0">
+          <el-pagination
+            background
+            layout="total, sizes, prev, pager, next, jumper"
+            :current-page="patientqueryParams.pn"
+            :page-size="patientqueryParams.ps"
+            :page-sizes="[10, 20, 30]"
+            :total="patienttotal"
+            @size-change="handleSizeChange"
+            @current-change="handlePageChange"
+          />
+        </div>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+import { selectTimelyRate } from "@/api/system/user";
+
+export default {
+  name: 'SeedetailsDialog',
+  dicts: ['sys_yujing', 'sys_suggest'],
+  props: {
+    rowData: {
+      type: Object,
+      default: () => ({})
+    },
+    queryParams: {
+      type: Object,
+      default: () => ({})
+    }
+  },
+  data() {
+    return {
+      // 鏌ヨ鍙傛暟
+      patientqueryParams: {
+        pn: 1,
+        ps: 10,
+        name: '',
+        leavediagname: ''
+      },
+
+      // 鍔犺浇鐘舵��
+      loading: false,
+
+      // 鎮h�呭垪琛�
+      logsheetlist: [],
+
+      // 鎬绘潯鏁�
+      patienttotal: 0
+    };
+  },
+
+  mounted() {
+    this.loadData();
+  },
+
+  methods: {
+    // 鍔犺浇鏁版嵁
+    async loadData() {
+      this.loading = true;
+      try {
+        const params = {
+          ...this.patientqueryParams,
+          deptcode: this.rowData.deptcode || '',
+          starttime: this.queryParams.dateRange?.[0] ? this.parseTime(this.queryParams.dateRange[0]) : '',
+          endtime: this.queryParams.dateRange?.[1] ? this.parseTime(this.queryParams.dateRange[1]) : ''
+        };
+
+        const response = await selectTimelyRate(params);
+        this.logsheetlist = response.data?.detail || [];
+        this.patienttotal = response.data?.total || 0;
+      } catch (error) {
+        console.error('鑾峰彇鏈強鏃堕殢璁胯鎯呭け璐�:', error);
+        this.$message.error('鑾峰彇鏁版嵁澶辫触');
+      } finally {
+        this.loading = false;
+      }
+    },
+
+    // 澶勭悊鎼滅储
+    handleSearch() {
+      this.patientqueryParams.pn = 1;
+      this.loadData();
+    },
+
+    // 澶勭悊閲嶇疆
+    handleReset() {
+      this.patientqueryParams = {
+        pn: 1,
+        ps: 10,
+        name: '',
+        leavediagname: ''
+      };
+      this.loadData();
+    },
+
+    // 澶勭悊鍒嗛〉澶у皬鍙樺寲
+    handleSizeChange(size) {
+      this.patientqueryParams.ps = size;
+      this.patientqueryParams.pn = 1;
+      this.loadData();
+    },
+
+    // 澶勭悊椤电爜鍙樺寲
+    handlePageChange(page) {
+      this.patientqueryParams.pn = page;
+      this.loadData();
+    },
+
+    // 鏍煎紡鍖栨椂闂�
+    formatTime(time) {
+      if (!time) return '-';
+      return time;
+    },
+
+    // 瑙f瀽鏃堕棿
+    parseTime(time) {
+      if (!time) return '';
+      return time;
+    },
+
+    // 鏌ョ湅璇︽儏
+    handleViewDetail(row) {
+      this.$emit('close');
+
+      let type = "";
+      if (row.preachformson && row.preachformson.includes("3")) {
+        type = 1;
+      }
+
+      setTimeout(() => {
+        this.$router.push({
+          path: "/followvisit/record/detailpage/",
+          query: {
+            taskid: row.taskid,
+            patid: row.patid,
+            id: row.id,
+            Voicetype: type
+          }
+        });
+      }, 300);
+    }
+  }
+};
+</script>
+
+<style lang="scss" scoped>
+.seedetails-dialog {
+  .detail-query-form {
+    margin-bottom: 20px;
+    padding-bottom: 20px;
+    border-bottom: 1px solid #f0f0f0;
+
+    ::v-deep .el-form-item {
+      margin-bottom: 0;
+      margin-right: 20px;
+    }
+  }
+
+  .patient-table {
+    margin-bottom: 20px;
+
+    ::v-deep .el-table__header-wrapper th {
+      background-color: #f8f9fa;
+      font-weight: 600;
+      color: #333;
+    }
+  }
+
+  .pagination {
+    display: flex;
+    justify-content: flex-end;
+    padding-top: 20px;
+    border-top: 1px solid #f0f0f0;
+  }
+}
+</style>
diff --git a/src/views/Satisfaction/sfstatistics/components/components/TopicDialog.vue b/src/views/Satisfaction/sfstatistics/components/components/TopicDialog.vue
new file mode 100644
index 0000000..46e59de
--- /dev/null
+++ b/src/views/Satisfaction/sfstatistics/components/components/TopicDialog.vue
@@ -0,0 +1,208 @@
+<template>
+  <div class="topic-dialog">
+    <div class="topicdia">
+      <div style="overflow-x: hidden; overflow-y: auto; max-height: 65vh">
+        <!-- 淇敼杩欓噷锛氫娇鐢� processedTopicList 鑰屼笉鏄� topicList -->
+        <div
+          v-for="(item, index) in processedTopicList"
+          :key="item.scriptid"
+          class="ttaabbcc"
+        >
+          <div class="describe">
+            绗瑊{ index + 1 }}棰橈細 {{ item.scriptContent }}
+            <span>[{{ item.scriptType == 1 ? "鍗曢�夐" : "澶氶�夐" }}]</span>
+          </div>
+          <div>
+            <el-table :data="item.details" style="width: 100%">
+              <el-table-column
+                prop="optionText"
+                label="闂閫夐」"
+                align="center"
+                min-width="200"
+              />
+              <el-table-column
+                prop="chosenQuantity"
+                label="閫夋嫨浜烘暟"
+                align="center"
+                min-width="120"
+              >
+                <template slot-scope="{ row }">
+                  {{ row.chosenQuantity || 0 }}
+                </template>
+              </el-table-column>
+              <el-table-column
+                prop="chosenPercentage"
+                label="姣斾緥"
+                align="center"
+                min-width="120"
+              >
+                <template slot-scope="{ row }">
+                  <span
+                    v-if="
+                      row.chosenPercentage !== null &&
+                      row.chosenPercentage !== undefined
+                    "
+                  >
+                    {{ (Number(row.chosenPercentage) * 100).toFixed(2) }}%
+                  </span>
+                  <span v-else>-</span>
+                </template>
+              </el-table-column>
+            </el-table>
+          </div>
+        </div>
+      </div>
+    </div>
+
+    <!-- 濡傛灉娌℃湁鏁版嵁 -->
+    <div
+      v-if="!processedTopicList.length"
+      class="no-data"
+      style="text-align: center; padding: 50px 0"
+    >
+      <el-empty description="鏆傛棤鏁版嵁"></el-empty>
+    </div>
+
+    <div
+      slot="footer"
+      class="dialog-footer"
+      style="text-align: center; padding-top: 20px"
+    >
+      <el-button @click="handleClose">鍏� 闂�</el-button>
+    </div>
+  </div>
+</template>
+
+<script>
+export default {
+  name: "TopicDialog",
+  props: {
+    rowData: {
+      type: Object,
+      default: () => ({}),
+    },
+    queryParams: {
+      type: Object,
+      default: () => ({}),
+    },
+    topicList: {
+      type: [Array, Object],
+      default: () => ({}),
+    },
+  },
+  data() {
+    return {
+      processedTopicList: [], // 澶勭悊鍚庣殑鏁版嵁
+    };
+  },
+  watch: {
+    // 鐩戝惉鐖剁粍浠朵紶閫掔殑鏁版嵁鍙樺寲
+    topicList: {
+      immediate: true,
+      handler(newVal) {
+        console.log("TopicDialog鎺ユ敹鍒扮埗缁勪欢鏁版嵁:", newVal);
+        this.processTopicList(newVal);
+      },
+    },
+  },
+  mounted() {
+    console.log("TopicDialog mounted, props:", this.$props);
+  },
+  methods: {
+    // 澶勭悊topicList鏁版嵁
+    processTopicList(data) {
+      console.log("寮�濮嬪鐞嗘暟鎹�:", data);
+
+      if (!data || typeof data !== "object") {
+        this.processedTopicList = [];
+        return;
+      }
+
+      // 灏嗗璞¤浆鎹负鏁扮粍
+      const result = [];
+
+      Object.keys(data).forEach((key) => {
+        const item = data[key];
+        if (item && item.scriptContent) {
+          // 娣辨嫹璐漣tem锛岄伩鍏嶄慨鏀瑰師鏁版嵁
+          const processedItem = JSON.parse(JSON.stringify(item));
+
+          // 杩囨护details锛屽彧淇濈暀鏈夐�夐」鏂囨湰鐨�
+          if (processedItem.details && Array.isArray(processedItem.details)) {
+            processedItem.details = processedItem.details.filter(
+              (detail) => detail && detail.optionText
+            );
+          }
+
+          result.push(processedItem);
+        }
+      });
+
+      console.log("澶勭悊鍚庣殑鏁版嵁:", result);
+      this.processedTopicList = result;
+    },
+
+    // 鏍煎紡鍖栫櫨鍒嗘瘮
+    formatPercent(value) {
+      if (value === null || value === undefined) return "-";
+      const num = parseFloat(value);
+      if (isNaN(num)) return "-";
+      return `${num.toFixed(2)}%`; // 娉ㄦ剰锛氫綘鐨勬暟鎹腑鐧惧垎姣斿凡缁忔槸0-100鐨勫舰寮�
+    },
+
+    // 鍏抽棴瀵硅瘽妗�
+    handleClose() {
+      this.$emit("close");
+    },
+  },
+};
+</script>
+
+<style lang="scss" scoped>
+.topic-dialog {
+  .topicdia {
+    font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
+      "Helvetica Neue", Arial, sans-serif;
+    color: #333;
+  }
+
+  .ttaabbcc {
+    background: #fafafa;
+    border-radius: 6px;
+    padding: 16px;
+    margin-bottom: 20px;
+    border-left: 4px solid #4794c5;
+  }
+
+  .describe {
+    font-size: 15px;
+    line-height: 1.6;
+    margin-bottom: 12px;
+    color: #1f2d3d;
+  }
+
+  .describe span {
+    font-size: 13px;
+    color: #999;
+    font-style: italic;
+    margin-left: 8px;
+  }
+
+  ::v-deep .el-table {
+    border-radius: 4px;
+    overflow: hidden;
+    font-size: 14px;
+  }
+
+  ::v-deep .el-table th {
+    background-color: #f1f5f9;
+    color: #333;
+    font-weight: 600;
+  }
+
+  ::v-deep .el-table td {
+    border-bottom: 1px solid #f0f0f0;
+    padding: 12px 0;
+  }
+}
+</style>
diff --git a/src/views/Satisfaction/sfstatistics/components/visitStatistics.vue b/src/views/Satisfaction/sfstatistics/components/visitStatistics.vue
new file mode 100644
index 0000000..1b77e5a
--- /dev/null
+++ b/src/views/Satisfaction/sfstatistics/components/visitStatistics.vue
@@ -0,0 +1,1030 @@
+<template>
+  <div class="followup-statistics">
+    <div class="query-section">
+      <el-form
+        :model="queryParams"
+        ref="queryForm"
+        size="medium"
+        :inline="true"
+        label-width="100px"
+        class="query-form"
+      >
+        <el-form-item label="缁熻绫诲瀷" prop="statisticaltype">
+          <el-select
+            v-model="queryParams.statisticaltype"
+            placeholder="璇烽�夋嫨缁熻绫诲瀷"
+            clearable
+            @change="handleStatisticalTypeChange"
+          >
+            <el-option
+              v-for="item in Statisticallist"
+              :key="item.value"
+              :label="item.label"
+              :value="item.value"
+            />
+          </el-select>
+        </el-form-item>
+
+        <!-- 鐥呭尯閫夋嫨 -->
+        <el-form-item
+          v-if="queryParams.statisticaltype == 1"
+          label="鐥呭尯"
+          prop="leavehospitaldistrictcodes"
+        >
+          <el-select
+            v-model="queryParams.leavehospitaldistrictcodes"
+            placeholder="璇烽�夋嫨鐥呭尯"
+            multiple
+            collapse-tags
+            filterable
+            clearable
+            style="width: 300px"
+          >
+            <el-option
+              v-for="item in flatArrayhospit"
+              :key="item.value"
+              :label="item.label"
+              :value="item.value"
+            />
+          </el-select>
+        </el-form-item>
+
+        <!-- 绉戝閫夋嫨 -->
+        <el-form-item
+          v-if="queryParams.statisticaltype == 2"
+          label="绉戝"
+          prop="deptcodes"
+        >
+          <el-select
+            v-model="queryParams.deptcodes"
+            placeholder="璇烽�夋嫨绉戝"
+            multiple
+            collapse-tags
+            filterable
+            clearable
+            style="width: 300px"
+          >
+            <el-option
+              v-for="item in flatArraydept"
+              :key="item.value"
+              :label="item.label"
+              :value="item.value"
+            />
+          </el-select>
+        </el-form-item>
+
+        <el-form-item label="鏈嶅姟绫诲瀷" prop="serviceType">
+          <el-select
+            v-model="queryParams.serviceType"
+            placeholder="璇烽�夋嫨鏈嶅姟绫诲瀷"
+            multiple
+            collapse-tags
+            clearable
+            style="width: 300px"
+          >
+            <el-option
+              v-for="item in options"
+              :key="item.value"
+              :label="item.label"
+              :value="item.value"
+            />
+          </el-select>
+        </el-form-item>
+
+        <el-form-item label="闅忚鏃堕棿" prop="dateRange">
+          <el-date-picker
+            v-model="queryParams.dateRange"
+            type="daterange"
+            range-separator="鑷�"
+            start-placeholder="寮�濮嬫棩鏈�"
+            end-placeholder="缁撴潫鏃ユ湡"
+            value-format="yyyy-MM-dd"
+            :picker-options="pickerOptions"
+            style="width: 380px"
+          />
+        </el-form-item>
+
+        <el-form-item>
+          <el-button
+            type="primary"
+            icon="el-icon-search"
+            @click="handleQuery"
+            :loading="loading"
+          >
+            鎼滅储
+          </el-button>
+          <el-button icon="el-icon-refresh" @click="resetQuery">
+            閲嶇疆
+          </el-button>
+          <el-button
+            type="warning"
+            icon="el-icon-download"
+            @click="handleExport"
+            :disabled="!userList.length"
+          >
+            瀵煎嚭
+          </el-button>
+        </el-form-item>
+      </el-form>
+    </div>
+
+    <div class="table-section">
+      <el-table
+        v-loading="loading"
+        :data="userList"
+        :border="true"
+        style="width: 100%"
+        @selection-change="handleSelectionChange"
+        :row-key="getRowKey"
+      >
+        <!-- 鐥呭尯鍒� -->
+        <el-table-column
+          v-if="queryParams.statisticaltype == 1"
+          label="鍑洪櫌鐥呭尯"
+          align="center"
+          sortable
+          key="leavehospitaldistrictname"
+          prop="leavehospitaldistrictname"
+          :show-overflow-tooltip="true"
+          :sort-method="sortChineseNumber"
+          min-width="120"
+        />
+
+        <!-- 绉戝鍒� -->
+        <el-table-column
+          v-if="queryParams.statisticaltype == 2"
+          label="绉戝"
+          align="center"
+          key="deptname"
+          prop="deptname"
+          :show-overflow-tooltip="true"
+          min-width="120"
+        />
+
+        <el-table-column
+          label="鍑洪櫌浜烘"
+          align="center"
+          key="dischargeCount"
+          prop="dischargeCount"
+          min-width="100"
+        />
+
+        <el-table-column
+          label="鏃犻渶闅忚浜烘"
+          align="center"
+          key="nonFollowUp"
+          prop="nonFollowUp"
+          min-width="120"
+        />
+
+        <el-table-column
+          label="搴旈殢璁夸汉娆�"
+          align="center"
+          key="followUpNeeded"
+          prop="followUpNeeded"
+          min-width="120"
+        />
+
+        <el-table-column
+          label="闅忚鐜�"
+          align="center"
+          key="followUpRate"
+          prop="followUpRate"
+          min-width="100"
+        >
+          <template slot-scope="scope">
+            <span
+              v-if="
+                scope.row.followUpRate !== null &&
+                scope.row.followUpRate !== undefined
+              "
+            >
+              {{ scope.row.followUpRate }}
+            </span>
+            <span v-else>-</span>
+          </template>
+        </el-table-column>
+
+        <el-table-column
+          label="鍙婃椂鐜�"
+          align="center"
+          key="rate"
+          prop="rate"
+          min-width="100"
+        >
+          <template slot-scope="scope">
+            <el-button
+              v-if="scope.row.rate !== null && scope.row.rate !== undefined"
+              type="text"
+              @click="handleSeedetails(scope.row)"
+            >
+              {{ formatPercent(scope.row.rate) }}
+            </el-button>
+            <span v-else style="color: #909399">-</span>
+          </template>
+        </el-table-column>
+
+        <el-table-column
+          label="澶嶈瘖閫氱煡棰樼洰鎬婚噺"
+          align="center"
+          key="joyAllCount"
+          prop="joyAllCount"
+          min-width="140"
+        />
+
+        <el-table-column
+          label="澶嶈瘖閫氱煡濉姤閲�"
+          align="center"
+          key="joyCount"
+          prop="joyCount"
+          min-width="120"
+        />
+
+        <el-table-column
+          label="瀹屾垚姣旂巼"
+          align="center"
+          key="joyTotal"
+          prop="joyTotal"
+          min-width="100"
+        >
+          <template slot-scope="scope">
+            <span
+              v-if="
+                scope.row.joyTotal !== null && scope.row.joyTotal !== undefined
+              "
+            >
+              {{ formatPercent(scope.row.joyTotal) }}
+            </span>
+            <span v-else>-</span>
+          </template>
+        </el-table-column>
+
+        <el-table-column label="鎿嶄綔" align="center" fixed="right" width="120">
+          <template slot-scope="scope">
+            <el-button type="text" @click="getinfo(scope.row)">
+              <i class="el-icon-s-order" style="margin-right: 4px"></i>
+              鏌ョ湅璇︽儏
+            </el-button>
+          </template>
+        </el-table-column>
+      </el-table>
+    </div>
+
+    <!-- 鍒嗛〉 -->
+    <div class="pagination-section" v-if="total > 0">
+      <el-pagination
+        background
+        layout="total, sizes, prev, pager, next, jumper"
+        :current-page="queryParams.pageNum"
+        :page-size="queryParams.pageSize"
+        :page-sizes="[10, 20, 30, 50]"
+        :total="total"
+        @size-change="handleSizeChange"
+        @current-change="handlePageChange"
+      />
+    </div>
+
+    <!-- 鏈強鏃堕殢璁胯鎯呭璇濇 -->
+    <el-dialog
+      title="鏈強鏃堕殢璁挎偅鑰呮湇鍔�"
+      :visible.sync="SeedetailsVisible"
+      width="80%"
+      :close-on-click-modal="false"
+    >
+      <SeedetailsDialog
+        v-if="SeedetailsVisible"
+        :row-data="currentRow"
+        :query-params="queryParams"
+        @close="SeedetailsVisible = false"
+      />
+    </el-dialog>
+
+    <!-- 澶嶈瘖閫氱煡璇︽儏瀵硅瘽妗� -->
+    <el-dialog
+      :visible.sync="topicVisible"
+      width="60%"
+      :close-on-click-modal="false"
+    >
+      <template #title>
+        <div style="display: flex; align-items: center">
+          <i
+            class="el-icon-s-data"
+            style="margin-right: 8px; color: #409eff"
+          ></i>
+          <span>{{ topicvalue.name }}</span>
+          <span style="margin-left: 10px; color: #666; font-size: 14px"
+            >澶嶈瘖閫氱煡鎸囨爣璇︽儏</span
+          >
+        </div>
+      </template>
+      <topic-dialog
+        v-if="topicVisible"
+        :row-data="currentRow"
+        :topicList="topiclist"
+        :query-params="queryParams"
+        @close="topicVisible = false"
+      />
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import {
+  getSfStatisticsJoy,
+  getSfStatisticsJoyInfo,
+  selectTimelyRate,
+} from "@/api/system/user";
+import ExcelJS from "exceljs";
+import { saveAs } from "file-saver";
+import SeedetailsDialog from "./components/SeedetailsDialog.vue";
+import TopicDialog from "./components/TopicDialog.vue";
+
+export default {
+  name: "FollowupStatistics",
+  components: {
+    SeedetailsDialog,
+    TopicDialog,
+  },
+  data() {
+    return {
+      // 鏌ヨ鍙傛暟
+      queryParams: {
+        statisticaltype: 1,
+        leavehospitaldistrictcodes: ["all"],
+        deptcodes: [],
+        serviceType: [2],
+        dateRange: [],
+        pageNum: 1,
+        pageSize: 20,
+      },
+
+      // 缁熻绫诲瀷鍒楄〃
+      Statisticallist: [
+        { label: "鐥呭尯缁熻", value: 1 },
+        { label: "绉戝缁熻", value: 2 },
+      ],
+
+      // 鐥呭尯鍒楄〃
+      flatArrayhospit: [],
+
+      // 绉戝鍒楄〃
+      flatArraydept: [],
+
+      // 鏈嶅姟绫诲瀷閫夐」
+      options: [],
+
+      // 琛ㄦ牸鏁版嵁
+      userList: [],
+
+      // 鎬绘潯鏁�
+      total: 0,
+
+      // 鍔犺浇鐘舵��
+      loading: false,
+
+      // 閫変腑鐨勮
+      ids: [],
+      single: true,
+      multiple: true,
+
+      // 褰撳墠鎿嶄綔鐨勮
+      currentRow: null,
+
+      // 瀵硅瘽妗嗘樉绀烘帶鍒�
+      SeedetailsVisible: false,
+      topicVisible: false,
+
+      // 澶嶈瘖閫氱煡璇︽儏鏁版嵁
+      topiclist: [],
+      topicvalue: {
+        name: "",
+      },
+
+      // 鏃ユ湡閫夋嫨鍣ㄩ�夐」
+      pickerOptions: {
+        shortcuts: [
+          {
+            text: "鏈�杩戜竴鍛�",
+            onClick(picker) {
+              const end = new Date();
+              const start = new Date();
+              start.setTime(start.getTime() - 3600 * 1000 * 24 * 7);
+              picker.$emit("pick", [start, end]);
+            },
+          },
+          {
+            text: "鏈�杩戜竴涓湀",
+            onClick(picker) {
+              const end = new Date();
+              const start = new Date();
+              start.setTime(start.getTime() - 3600 * 1000 * 24 * 30);
+              picker.$emit("pick", [start, end]);
+            },
+          },
+          {
+            text: "鏈�杩戜笁涓湀",
+            onClick(picker) {
+              const end = new Date();
+              const start = new Date();
+              start.setTime(start.getTime() - 3600 * 1000 * 24 * 90);
+              picker.$emit("pick", [start, end]);
+            },
+          },
+        ],
+        disabledDate(time) {
+          return time.getTime() > Date.now();
+        },
+      },
+    };
+  },
+
+  created() {
+    this.initData();
+  },
+
+  methods: {
+    // 鍒濆鍖栨暟鎹�
+    async initData() {
+      await this.getDeptTree();
+      await this.getList();
+    },
+
+    // 鑾峰彇绉戝鏍�
+    getDeptTree() {
+      // 鑾峰彇鏈嶅姟绫诲瀷
+      this.options = this.$store.getters.tasktypes || [];
+
+      // 鑾峰彇绉戝鍒楄〃
+      this.flatArraydept = (this.$store.getters.belongDepts || []).map(
+        (dept) => {
+          return {
+            label: dept.deptName,
+            value: dept.deptCode,
+          };
+        }
+      );
+
+      // 鑾峰彇鐥呭尯鍒楄〃
+      this.flatArrayhospit = (this.$store.getters.belongWards || []).map(
+        (ward) => {
+          return {
+            label: ward.districtName,
+            value: ward.districtCode,
+          };
+        }
+      );
+
+      // 娣诲姞鍏ㄩ儴閫夐」
+      this.flatArraydept.push({ label: "鍏ㄩ儴", value: "all" });
+      this.flatArrayhospit.push({ label: "鍏ㄩ儴", value: "all" });
+    },
+
+    // 鑾峰彇缁熻鍒楄〃
+    async getList() {
+      this.loading = true;
+      try {
+        // 澶勭悊鏌ヨ鍙傛暟
+        const params = {
+          configKey: "returnVisitCount",
+          ...this.queryParams,
+        };
+
+        // 澶勭悊鏃ユ湡鑼冨洿
+        if (
+          this.queryParams.dateRange &&
+          this.queryParams.dateRange.length === 2
+        ) {
+          params.startTime = this.queryParams.dateRange[0];
+          params.endTime = this.queryParams.dateRange[1];
+        }
+
+        // 澶勭悊鐥呭尯/绉戝閫夋嫨
+        if (params.statisticaltype == 1) {
+          // 鐥呭尯缁熻
+          if (params.leavehospitaldistrictcodes.includes("all")) {
+            // 濡傛灉閫夋嫨浜�"鍏ㄩ儴"锛屽垯绉婚櫎"all"鍊�
+            params.leavehospitaldistrictcodes =
+              params.leavehospitaldistrictcodes.filter(
+                (item) => item !== "all"
+              );
+            // 濡傛灉闇�瑕佷紶鎵�鏈夌梾鍖轰唬鐮侊紝鍙互浠巗tore涓幏鍙�
+            params.leavehospitaldistrictcodes = (
+              this.$store.getters.belongWards || []
+            ).map((ward) => ward.districtCode);
+          }
+        } else if (params.statisticaltype == 2) {
+          // 绉戝缁熻
+          if (params.deptcodes.includes("all")) {
+            // 濡傛灉閫夋嫨浜�"鍏ㄩ儴"锛屽垯绉婚櫎"all"鍊�
+            params.deptcodes = params.deptcodes.filter(
+              (item) => item !== "all"
+            );
+            // 濡傛灉闇�瑕佷紶鎵�鏈夌瀹や唬鐮侊紝鍙互浠巗tore涓幏鍙�
+            params.deptcodes = (this.$store.getters.belongDepts || []).map(
+              (dept) => dept.deptCode
+            );
+          }
+        }
+
+        const response = await getSfStatisticsJoy(params);
+        this.userList = this.customSort(response.data) || [];
+        this.total = response.total || 0;
+      } catch (error) {
+        console.error("鑾峰彇缁熻鍒楄〃澶辫触:", error);
+        this.$message.error("鑾峰彇鏁版嵁澶辫触");
+      } finally {
+        this.loading = false;
+      }
+    },
+    sortChineseNumber(aRow, bRow) {
+      const a = aRow.leavehospitaldistrictname;
+      const b = bRow.leavehospitaldistrictname;
+
+      // 涓枃鏁板瓧鍒伴樋鎷変集鏁板瓧鐨勬槧灏勶紙鎵╁睍鍒�45锛�
+      const chineseNumMap = {
+        涓�: 1,
+        浜�: 2,
+        涓�: 3,
+        鍥�: 4,
+        浜�: 5,
+        鍏�: 6,
+        涓�: 7,
+        鍏�: 8,
+        涔�: 9,
+        鍗�: 10,
+        鍗佷竴: 11,
+        鍗佷簩: 12,
+        鍗佷笁: 13,
+        鍗佸洓: 14,
+        鍗佷簲: 15,
+        鍗佸叚: 16,
+        鍗佷竷: 17,
+        鍗佸叓: 18,
+        鍗佷節: 19,
+        浜屽崄: 20,
+        浜屽崄涓�: 21,
+        浜屽崄浜�: 22,
+        浜屽崄涓�: 23,
+        浜屽崄鍥�: 24,
+        浜屽崄浜�: 25,
+        浜屽崄鍏�: 26,
+        浜屽崄涓�: 27,
+        浜屽崄鍏�: 28,
+        浜屽崄涔�: 29,
+        涓夊崄: 30,
+        涓夊崄涓�: 31,
+        涓夊崄浜�: 32,
+        涓夊崄涓�: 33,
+        涓夊崄鍥�: 34,
+        涓夊崄浜�: 35,
+        涓夊崄鍏�: 36,
+        涓夊崄涓�: 37,
+        涓夊崄鍏�: 38,
+        涓夊崄涔�: 39,
+        鍥涘崄: 40,
+        鍥涘崄涓�: 41,
+        鍥涘崄浜�: 42,
+        鍥涘崄涓�: 43,
+        鍥涘崄鍥�: 44,
+        鍥涘崄浜�: 45,
+      };
+
+      // 鎻愬彇涓枃鏁板瓧
+      const getNumberFromText = (text) => {
+        if (!text || typeof text !== "string") return -1;
+
+        // 鍖归厤涓枃鏁板瓧锛屾敮鎸佷竴鍒板洓鍗佷簲
+        const match = text.match(/^([涓�浜屼笁鍥涗簲鍏竷鍏節鍗乚+)/);
+
+        if (match && match[1]) {
+          const chineseNum = match[1];
+          return chineseNumMap[chineseNum] !== undefined
+            ? chineseNumMap[chineseNum]
+            : -1;
+        }
+
+        // 濡傛灉娌℃湁鍖归厤鍒颁腑鏂囨暟瀛楋紝灏濊瘯鍖归厤闃挎媺浼暟瀛�
+        const arabicMatch = text.match(/^(\d+)/);
+        if (arabicMatch && arabicMatch[1]) {
+          const num = parseInt(arabicMatch[1], 10);
+          return num >= 1 && num <= 45 ? num : -1;
+        }
+
+        return -1;
+      };
+
+      const numA = getNumberFromText(a);
+      const numB = getNumberFromText(b);
+
+      // 澶勭悊鏃犳硶瑙f瀽鐨勬儏鍐�
+      if (numA === -1 && numB === -1) {
+        return (a || "").localeCompare(b || "");
+      }
+      if (numA === -1) return 1;
+      if (numB === -1) return -1;
+
+      return numA - numB;
+    },
+    customSort(data) {
+      // 瀹氫箟鎮ㄦ湡鏈涚殑鐥呭尯椤哄簭锛堟墿灞曞埌鍥涘崄浜旓級
+      const order = [
+        "涓�",
+        "浜�",
+        "涓�",
+        "鍥�",
+        "浜�",
+        "鍏�",
+        "涓�",
+        "鍏�",
+        "涔�",
+        "鍗�",
+        "鍗佷竴",
+        "鍗佷簩",
+        "鍗佷笁",
+        "鍗佸洓",
+        "鍗佷簲",
+        "鍗佸叚",
+        "鍗佷竷",
+        "鍗佸叓",
+        "鍗佷節",
+        "浜屽崄",
+        "浜屽崄涓�",
+        "浜屽崄浜�",
+        "浜屽崄涓�",
+        "浜屽崄鍥�",
+        "浜屽崄浜�",
+        "浜屽崄鍏�",
+        "浜屽崄涓�",
+        "浜屽崄鍏�",
+        "浜屽崄涔�",
+        "涓夊崄",
+        "涓夊崄涓�",
+        "涓夊崄浜�",
+        "涓夊崄涓�",
+        "涓夊崄鍥�",
+        "涓夊崄浜�",
+        "涓夊崄鍏�",
+        "涓夊崄涓�",
+        "涓夊崄鍏�",
+        "涓夊崄涔�",
+        "鍥涘崄",
+        "鍥涘崄涓�",
+        "鍥涘崄浜�",
+        "鍥涘崄涓�",
+        "鍥涘崄鍥�",
+        "鍥涘崄浜�",
+      ];
+
+      return data.sort((a, b) => {
+        // 鎻愬彇鐥呭尯鍚嶇О涓殑涓枃鏁板瓧閮ㄥ垎
+        const getIndex = (name) => {
+          if (!name || typeof name !== "string") return -1;
+
+          // 鍖归厤涓枃鏁板瓧
+          const chineseMatch = name.match(/^([涓�浜屼笁鍥涗簲鍏竷鍏節鍗乚+)/);
+          if (chineseMatch && chineseMatch[1]) {
+            return order.indexOf(chineseMatch[1]);
+          }
+
+          // 鍖归厤闃挎媺浼暟瀛�
+          const arabicMatch = name.match(/^(\d+)/);
+          if (arabicMatch && arabicMatch[1]) {
+            const num = parseInt(arabicMatch[1], 10);
+            if (num >= 1 && num <= 45) {
+              return num - 1; // 鍥犱负鏁扮粍绱㈠紩浠�0寮�濮�
+            }
+          }
+
+          return -1;
+        };
+
+        const indexA = getIndex(a.leavehospitaldistrictname);
+        const indexB = getIndex(b.leavehospitaldistrictname);
+
+        // 鎺掑簭閫昏緫
+        if (indexA === -1 && indexB === -1) {
+          return (a.leavehospitaldistrictname || "").localeCompare(
+            b.leavehospitaldistrictname || ""
+          );
+        }
+        if (indexA === -1) return 1;
+        if (indexB === -1) return -1;
+        return indexA - indexB;
+      });
+    },
+    // 澶勭悊缁熻绫诲瀷鍙樺寲
+    handleStatisticalTypeChange(value) {
+      if (value === 1) {
+        this.queryParams.deptcodes = [];
+      } else {
+        this.queryParams.leavehospitaldistrictcodes = [];
+      }
+      this.queryParams.pageNum = 1;
+      this.getList();
+    },
+
+    // 澶勭悊鏌ヨ
+    handleQuery() {
+      this.queryParams.pageNum = 1;
+      this.getList();
+    },
+
+    // 閲嶇疆鏌ヨ
+    resetQuery() {
+      this.queryParams = {
+        statisticaltype: 1,
+        leavehospitaldistrictcodes: [],
+        deptcodes: [],
+        serviceType: [2],
+        dateRange: [],
+        pageNum: 1,
+        pageSize: 20,
+      };
+      this.getList();
+    },
+
+    // 澶勭悊鍒嗛〉澶у皬鍙樺寲
+    handleSizeChange(size) {
+      this.queryParams.pageSize = size;
+      this.queryParams.pageNum = 1;
+      this.getList();
+    },
+
+    // 澶勭悊椤电爜鍙樺寲
+    handlePageChange(page) {
+      this.queryParams.pageNum = page;
+      this.getList();
+    },
+
+    // 澶勭悊琛岄�夋嫨
+    handleSelectionChange(selection) {
+      this.ids = selection.map((item) => item.id);
+      this.single = selection.length !== 1;
+      this.multiple = !selection.length;
+    },
+
+    // 鑾峰彇琛宬ey
+    getRowKey(row) {
+      return row.statisticaltype === 1
+        ? row.leavehospitaldistrictcode
+        : row.deptcode;
+    },
+
+    // 鏍煎紡鍖栫櫨鍒嗘瘮
+    formatPercent(value) {
+      if (value === null || value === undefined) return "-";
+      const num = parseFloat(value);
+      if (isNaN(num)) return "-";
+      return `${(num * 100).toFixed(2)}%`;
+    },
+
+    // 鏌ョ湅鏈強鏃堕殢璁胯鎯�
+    handleSeedetails(row) {
+      this.currentRow = row;
+      this.SeedetailsVisible = true;
+    },
+
+    // 鏌ョ湅澶嶈瘖閫氱煡璇︽儏
+    async getinfo(row) {
+      this.currentRow = row;
+
+      try {
+        // 澶勭悊鏌ヨ鍙傛暟
+        const params = {
+          configKey: "returnVisitCount",
+          ...this.queryParams,
+        };
+
+        // 澶勭悊鏃ユ湡鑼冨洿
+        if (
+          this.queryParams.dateRange &&
+          this.queryParams.dateRange.length === 2
+        ) {
+          params.startTime = this.queryParams.dateRange[0];
+          params.endTime = this.queryParams.dateRange[1];
+        }
+
+        if (this.queryParams.statisticaltype == 1) {
+          this.topicvalue.name = row.leavehospitaldistrictname;
+          params.leavehospitaldistrictcodes = [row.leavehospitaldistrictcode];
+        } else {
+          this.topicvalue.name = row.deptname;
+          params.deptcodes = [row.deptcode];
+        }
+
+        const response = await getSfStatisticsJoyInfo(params);
+        this.topiclist = response.data || [];
+        console.log(this.topiclist);
+        this.topicVisible = true;
+      } catch (error) {
+        console.error("鑾峰彇澶嶈瘖閫氱煡璇︽儏澶辫触:", error);
+        this.$message.error("鑾峰彇璇︽儏澶辫触");
+      }
+    },
+
+    // 瀵煎嚭鏁版嵁
+    async handleExport() {
+      if (!this.userList.length) {
+        this.$message.warning("娌℃湁鏁版嵁鍙鍑�");
+        return;
+      }
+
+      try {
+        this.loading = true;
+
+        // 鏋勫缓鏃ユ湡鑼冨洿瀛楃涓�
+        let dateRangeString = "";
+        let sheetNameSuffix = "";
+
+        if (
+          this.queryParams.dateRange &&
+          this.queryParams.dateRange.length === 2
+        ) {
+          const startDateFormatted = this.queryParams.dateRange[0];
+          const endDateFormatted = this.queryParams.dateRange[1];
+          dateRangeString = `${startDateFormatted}鑷�${endDateFormatted}`;
+          sheetNameSuffix = `${startDateFormatted}鑷�${endDateFormatted}`;
+        } else {
+          const now = new Date();
+          const currentMonth = now.getMonth() + 1;
+          dateRangeString = `${currentMonth}鏈坄;
+          sheetNameSuffix = `${currentMonth}鏈坄;
+        }
+
+        const excelName = `闅忚缁熻琛╛${dateRangeString}.xlsx`;
+        const worksheetName = `闅忚缁熻_${sheetNameSuffix}`;
+
+        // 鍒涘缓Excel宸ヤ綔绨�
+        const workbook = new ExcelJS.Workbook();
+        const worksheet = workbook.addWorksheet(worksheetName);
+
+        // 瀹氫箟鏍峰紡
+        const titleStyle = {
+          font: { name: "寰蒋闆呴粦", size: 16, bold: true },
+          fill: {
+            type: "pattern",
+            pattern: "solid",
+            fgColor: { argb: "FFE6F3FF" },
+          },
+          alignment: { vertical: "middle", horizontal: "center" },
+          border: {
+            top: { style: "thin", color: { argb: "FFD0D0D0" } },
+            left: { style: "thin", color: { argb: "FFD0D0D0" } },
+            bottom: { style: "thin", color: { argb: "FFD0D0D0" } },
+            right: { style: "thin", color: { argb: "FFD0D0D0" } },
+          },
+        };
+
+        const headerStyle = {
+          font: { name: "寰蒋闆呴粦", size: 11, bold: true },
+          fill: {
+            type: "pattern",
+            pattern: "solid",
+            fgColor: { argb: "FFF5F7FA" },
+          },
+          alignment: { vertical: "middle", horizontal: "center" },
+          border: {
+            top: { style: "thin", color: { argb: "FFD0D0D0" } },
+            left: { style: "thin", color: { argb: "FFD0D0D0" } },
+            bottom: { style: "thin", color: { argb: "FFD0D0D0" } },
+            right: { style: "thin", color: { argb: "FFD0D0D0" } },
+          },
+        };
+
+        const cellStyle = {
+          font: { name: "瀹嬩綋", size: 10 },
+          alignment: { vertical: "middle", horizontal: "center" },
+          border: {
+            top: { style: "thin", color: { argb: "FFD0D0D0" } },
+            left: { style: "thin", color: { argb: "FFD0D0D0" } },
+            bottom: { style: "thin", color: { argb: "FFD0D0D0" } },
+            right: { style: "thin", color: { argb: "FFD0D0D0" } },
+          },
+        };
+
+        // 娣诲姞鎬绘爣棰�
+        worksheet.mergeCells(1, 1, 1, 10);
+        const titleCell = worksheet.getCell(1, 1);
+        titleCell.value = `闅忚缁熻琛紙${sheetNameSuffix}锛塦;
+        titleCell.style = titleStyle;
+        worksheet.getRow(1).height = 35;
+
+        // 娣诲姞琛ㄥご
+        const headers = [
+          this.queryParams.statisticaltype == 1 ? "鍑洪櫌鐥呭尯" : "绉戝",
+          "鍑洪櫌浜烘",
+          "鏃犻渶闅忚浜烘",
+          "搴旈殢璁夸汉娆�",
+          "闅忚鐜�",
+          "鍙婃椂鐜�",
+          "澶嶈瘖閫氱煡棰樼洰鎬婚噺",
+          "澶嶈瘖閫氱煡濉姤閲�",
+          "瀹屾垚姣旂巼",
+        ];
+
+        const headerRow = worksheet.addRow(headers);
+        headerRow.eachCell((cell) => {
+          cell.style = headerStyle;
+        });
+        headerRow.height = 25;
+
+        // 娣诲姞鏁版嵁琛�
+        this.userList.forEach((item) => {
+          const dataRow = worksheet.addRow([
+            this.queryParams.statisticaltype == 1
+              ? item.leavehospitaldistrictname
+              : item.deptname,
+            item.dischargeCount || 0,
+            item.nonFollowUp || 0,
+            item.followUpNeeded || 0,
+            item.followUpRate || "0%",
+            item.rate ? this.formatPercent(item.rate) : "0%",
+            item.joyAllCount || 0,
+            item.joyCount || 0,
+            item.joyTotal ? this.formatPercent(item.joyTotal) : "0%",
+          ]);
+
+          dataRow.eachCell((cell) => {
+            cell.style = cellStyle;
+          });
+          dataRow.height = 22;
+        });
+
+        // 璁剧疆鍒楀
+        worksheet.columns = [
+          { width: 20 },
+          { width: 12 },
+          { width: 12 },
+          { width: 12 },
+          { width: 12 },
+          { width: 12 },
+          { width: 15 },
+          { width: 15 },
+          { width: 12 },
+        ];
+
+        // 鐢熸垚骞朵笅杞芥枃浠�
+        const buffer = await workbook.xlsx.writeBuffer();
+        const blob = new Blob([buffer], {
+          type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
+        });
+
+        saveAs(blob, excelName);
+        this.$message.success("瀵煎嚭鎴愬姛");
+      } catch (error) {
+        console.error("瀵煎嚭澶辫触:", error);
+        this.$message.error(`瀵煎嚭澶辫触: ${error.message}`);
+      } finally {
+        this.loading = false;
+      }
+    },
+  },
+};
+</script>
+
+<style lang="scss" scoped>
+.followup-statistics {
+  .query-section {
+    background: #fff;
+    padding: 20px;
+    border-radius: 4px;
+    margin-bottom: 20px;
+
+    .query-form {
+      display: flex;
+      flex-wrap: wrap;
+
+      ::v-deep .el-form-item {
+        margin-bottom: 20px;
+
+        &:not(:last-child) {
+          margin-right: 20px;
+        }
+      }
+    }
+  }
+
+  .table-section {
+    background: #fff;
+    padding: 20px;
+    border-radius: 4px;
+    margin-bottom: 20px;
+
+    ::v-deep .el-table {
+      th {
+        background-color: #f8f9fa;
+        font-weight: 600;
+        color: #333;
+      }
+    }
+  }
+
+  .pagination-section {
+    display: flex;
+    justify-content: flex-end;
+    background: #fff;
+    padding: 20px;
+    border-radius: 4px;
+  }
+}
+</style>
diff --git a/src/views/Satisfaction/sfstatistics/index.vue b/src/views/Satisfaction/sfstatistics/index.vue
new file mode 100644
index 0000000..96bda01
--- /dev/null
+++ b/src/views/Satisfaction/sfstatistics/index.vue
@@ -0,0 +1,63 @@
+<!-- StatisticsMain.vue -->
+<template>
+  <div class="statistics-main">
+    <el-tabs v-model="activeTab" @tab-click="handleTabChange">
+      <el-tab-pane label="闅忚缁熻" name="followup">
+        <followup-statistics
+          v-if="activeTab === 'followup'"
+          ref="followupRef"
+        />
+      </el-tab-pane>
+      <el-tab-pane label="婊℃剰搴︾粺璁�" name="satisfaction">
+        <satisfaction-statistics
+          v-if="activeTab === 'satisfaction'"
+          ref="satisfactionRef"
+        />
+      </el-tab-pane>
+    </el-tabs>
+  </div>
+</template>
+
+<script>
+import FollowupStatistics from './components/FollowupStatistics.vue';
+import SatisfactionStatistics from './components/SatisfactionStatistics.vue';
+
+export default {
+  name: 'StatisticsMain',
+  components: {
+    FollowupStatistics,
+    SatisfactionStatistics
+  },
+  data() {
+    return {
+      activeTab: 'followup'
+    };
+  },
+  methods: {
+    handleTabChange(tab) {
+      console.log('鍒囨崲鍒�:', tab.name);
+    }
+  }
+};
+</script>
+
+<style lang="scss" scoped>
+.statistics-main {
+  padding: 20px;
+  background: #fff;
+  min-height: calc(100vh - 84px);
+
+  ::v-deep .el-tabs__header {
+    margin-bottom: 20px;
+  }
+
+  ::v-deep .el-tabs__item {
+    font-size: 16px;
+    font-weight: 500;
+  }
+
+  ::v-deep .el-tabs__nav-wrap::after {
+    height: 1px;
+  }
+}
+</style>
diff --git a/src/views/followvisit/Continue/ContinueFordetails.vue b/src/views/followvisit/Continue/ContinueFordetails.vue
new file mode 100644
index 0000000..c07bcef
--- /dev/null
+++ b/src/views/followvisit/Continue/ContinueFordetails.vue
@@ -0,0 +1,2389 @@
+<template>
+  <!-- 寤剁画鎶ょ悊椤甸潰 -->
+  <div class="ContinuityCarePage" id="app-container">
+    <!-- 绗竴閮ㄥ垎锛氭偅鑰呭熀纭�淇℃伅 -->
+    <div class="patient-info-section">
+      <div class="headline">
+        <div>鎮h�呭熀纭�淇℃伅</div>
+      </div>
+      <div class="patient-info-form">
+        <el-form
+          ref="patientForm"
+          :model="patientForm"
+          :rules="patientRules"
+          label-width="120px"
+        >
+          <el-row :gutter="20">
+            <el-col :span="8">
+              <el-form-item label="鎮h�呭鍚�" prop="name">
+                <el-input
+                  v-model="patientForm.name"
+                  placeholder="璇疯緭鍏ユ偅鑰呭鍚�"
+                  maxlength="30"
+                  clearable
+                ></el-input>
+              </el-form-item>
+            </el-col>
+            <el-col :span="8">
+              <el-form-item label="鎬у埆" prop="sex">
+                <el-select
+                  v-model="patientForm.sex"
+                  placeholder="璇烽�夋嫨"
+                  clearable
+                >
+                  <el-option label="鐢�" :value="1"></el-option>
+                  <el-option label="濂�" :value="2"></el-option>
+                </el-select>
+              </el-form-item>
+            </el-col>
+            <el-col :span="8">
+              <el-form-item label="骞撮緞" prop="age">
+                <el-input
+                  v-model="patientForm.age"
+                  placeholder="璇疯緭鍏ュ勾榫�"
+                  maxlength="3"
+                  clearable
+                ></el-input>
+              </el-form-item>
+            </el-col>
+          </el-row>
+
+          <el-row :gutter="20">
+            <el-col :span="8">
+              <el-form-item label="鑱旂郴鐢佃瘽" prop="telcode">
+                <el-input
+                  v-model="patientForm.telcode"
+                  placeholder="璇疯緭鍏ヨ仈绯荤數璇�"
+                  maxlength="20"
+                  clearable
+                ></el-input>
+              </el-form-item>
+            </el-col>
+            <el-col :span="8">
+              <el-form-item label="浣忛櫌鍙�" prop="hospitalNumber">
+                <el-input
+                  v-model="patientForm.hospitalNumber"
+                  placeholder="璇疯緭鍏ヤ綇闄㈠彿"
+                  maxlength="50"
+                  clearable
+                ></el-input>
+              </el-form-item>
+            </el-col>
+            <el-col :span="8">
+              <el-form-item label="鍑洪櫌鏃ユ湡" prop="dischargeDate">
+                <el-date-picker
+                  v-model="patientForm.dischargeDate"
+                  type="date"
+                  placeholder="閫夋嫨鍑洪櫌鏃ユ湡"
+                  value-format="yyyy-MM-dd"
+                  style="width: 100%"
+                >
+                </el-date-picker>
+              </el-form-item>
+            </el-col>
+          </el-row>
+
+          <el-row :gutter="20">
+            <el-col :span="12">
+              <el-form-item label="璇婃柇鍚嶇О" prop="diagnosis">
+                <el-input
+                  v-model="patientForm.diagnosis"
+                  placeholder="璇疯緭鍏ヨ瘖鏂悕绉�"
+                  maxlength="100"
+                  clearable
+                ></el-input>
+              </el-form-item>
+            </el-col>
+            <el-col :span="12">
+              <el-form-item label="璐d换鎶ゅ+" prop="nurseName">
+                <el-input
+                  v-model="patientForm.nurseName"
+                  placeholder="璇疯緭鍏ヨ矗浠绘姢澹�"
+                  maxlength="50"
+                  clearable
+                ></el-input>
+              </el-form-item>
+            </el-col>
+          </el-row>
+
+          <el-row :gutter="20">
+            <el-col :span="24">
+              <el-form-item label="灞呬綇鍦板潃" prop="address">
+                <el-input
+                  v-model="patientForm.address"
+                  placeholder="璇疯緭鍏ヨ缁嗗眳浣忓湴鍧�"
+                  maxlength="200"
+                  clearable
+                ></el-input>
+              </el-form-item>
+            </el-col>
+          </el-row>
+
+          <el-row :gutter="20">
+            <el-col :span="12">
+              <el-form-item label="浜插睘濮撳悕" prop="relativeName">
+                <el-input
+                  v-model="patientForm.relativeName"
+                  placeholder="璇疯緭鍏ヤ翰灞炲鍚�"
+                  maxlength="30"
+                  clearable
+                ></el-input>
+              </el-form-item>
+            </el-col>
+            <el-col :span="12">
+              <el-form-item label="浜插睘鐢佃瘽" prop="relativeTel">
+                <el-input
+                  v-model="patientForm.relativeTel"
+                  placeholder="璇疯緭鍏ヤ翰灞炵數璇�"
+                  maxlength="20"
+                  clearable
+                ></el-input>
+              </el-form-item>
+            </el-col>
+          </el-row>
+
+          <!-- 寤剁画鎶ょ悊姹囨�讳俊鎭� -->
+          <el-row :gutter="20" v-if="continuitySummary.continueCount > 0">
+            <el-col :span="24">
+              <el-form-item label="寤剁画鎶ょ悊姹囨��">
+                <div class="continuity-summary">
+                  <div class="summary-item">
+                    <span class="label">寤剁画娆℃暟锛�</span>
+                    <span class="value"
+                      >{{ continuitySummary.continueCount }} 娆�</span
+                    >
+                  </div>
+                  <div class="summary-item">
+                    <span class="label">鏈�鏂版湇鍔★細</span>
+                    <span class="value">{{
+                      formatDisplayTime(continuitySummary.continueTimeNow)
+                    }}</span>
+                  </div>
+                  <div class="summary-item">
+                    <span class="label">涓嬫鏈嶅姟锛�</span>
+                    <span class="value">{{
+                      formatDisplayTime(continuitySummary.continueTimeNext)
+                    }}</span>
+                  </div>
+                </div>
+              </el-form-item>
+            </el-col>
+          </el-row>
+
+          <!-- 鎿嶄綔鎸夐挳 -->
+          <el-form-item>
+            <el-button
+              type="primary"
+              @click="savePatientInfo"
+              :loading="savingPatientInfo"
+            >
+              淇濆瓨鎮h�呬俊鎭�
+            </el-button>
+            <el-button @click="resetPatientInfo">閲嶇疆</el-button>
+          </el-form-item>
+        </el-form>
+      </div>
+    </div>
+    <!-- 绗簩閮ㄥ垎锛氭湇鍔″熀纭�淇℃伅 -->
+    <div class="basic-info-section">
+      <div class="headline">
+        <div>鏈嶅姟鍩虹淇℃伅</div>
+      </div>
+      <div class="basic-info-container">
+        <!-- 宸﹀崐閮ㄥ垎锛氬綋鍓嶆湇鍔¢殢璁垮唴瀹癸紙鍙锛� -->
+        <div class="followup-content readonly-content">
+          <div class="sub-headline">
+            <i class="el-icon-document"></i> 褰撳墠鏈嶅姟闅忚鍐呭锛堝彧璇伙級
+            <el-button
+              type="text"
+              size="small"
+              @click="toggleQuestionSelection"
+              style="margin-left: 10px"
+            >
+              {{ showQuestionSelector ? "闅愯棌闂閫夊彇" : "閫夊彇寤剁画闂" }}
+            </el-button>
+          </div>
+
+          <!-- 闂閫夊彇闈㈡澘 -->
+          <div v-if="showQuestionSelector" class="question-selector-panel">
+            <div class="selector-header">
+              <span>璇烽�夋嫨寤剁画闂锛堝彲澶氶�夛級锛�</span>
+              <el-button
+                type="primary"
+                size="small"
+                @click="confirmQuestionSelection"
+              >
+                纭閫夊彇
+              </el-button>
+            </div>
+            <div class="question-list">
+              <el-checkbox-group v-model="selectedQuestionIds">
+                <div
+                  v-for="(question, index) in availableQuestions"
+                  :key="question.id"
+                  class="question-item"
+                >
+                  <el-checkbox :label="question.id">
+                    <div class="question-content">
+                      <span class="question-index"
+                        >{{ question.index + 1 }}.</span
+                      >
+                      <span class="question-text">{{ question.text }}</span>
+                    </div>
+                  </el-checkbox>
+                </div>
+              </el-checkbox-group>
+            </div>
+          </div>
+          <div class="content-container">
+            <el-tabs v-model="activeName" type="border-card">
+              <el-tab-pane name="wj">
+                <span slot="label"
+                  ><i class="el-icon-notebook-1"></i> 闂嵎闅忚缁撴灉</span
+                >
+                <div class="CONTENT">
+                  <div class="title">{{ taskname ? taskname : "闂嵎" }}</div>
+                  <div class="preview-left" v-if="!Voicetype">
+                    <div
+                      class="topic-dev"
+                      v-for="(item, index) in tableDatatop"
+                      :key="item.id"
+                    >
+                      <!-- 鍗曢�� -->
+                      <div
+                        :class="getTopicClass(item)"
+                        :key="index"
+                        v-if="item.scriptType == 1 && !item.astrict"
+                      >
+                        <div class="dev-text">
+                          {{ index + 1 }}銆乕鍗曢�塢<span>{{
+                            item.scriptContent
+                          }}</span>
+                        </div>
+                        <div class="dev-xx">
+                          <el-radio-group v-model="item.scriptResult" disabled>
+                            <el-radio
+                              v-for="(
+                                items, indexs
+                              ) in item.svyTaskTemplateTargetoptions"
+                              :class="getOptionClass(items)"
+                              :key="indexs"
+                              :label="items.optioncontent"
+                              >{{ items.optioncontent }}</el-radio
+                            >
+                          </el-radio-group>
+                        </div>
+                        <div
+                          v-if="item.showAppendInput || item.answerps"
+                          class="append-input-container"
+                        >
+                          <el-input
+                            type="textarea"
+                            :rows="2"
+                            placeholder="璇疯緭鍏ュ叿浣撲俊鎭�"
+                            v-model="item.answerps"
+                            readonly
+                          ></el-input>
+                        </div>
+                        <div v-show="item.prompt">
+                          <el-alert :title="item.prompt" type="warning">
+                          </el-alert>
+                        </div>
+                      </div>
+                      <!-- 澶氶�� -->
+                      <div
+                        :class="
+                          item.isabnormal
+                            ? 'scriptTopic-isabnormal'
+                            : 'scriptTopic-dev'
+                        "
+                        :key="index"
+                        v-if="item.scriptType == 2 && !item.astrict"
+                      >
+                        <div class="dev-text">
+                          {{ index + 1 }}銆乕澶氶�塢<span>{{
+                            item.scriptContent
+                          }}</span>
+                        </div>
+                        <div class="dev-xx">
+                          <el-checkbox-group
+                            v-model="item.scriptResult"
+                            disabled
+                          >
+                            <el-checkbox
+                              :class="items.isabnormal ? 'red-star' : ''"
+                              v-for="(
+                                items, indexs
+                              ) in item.svyTaskTemplateTargetoptions"
+                              :key="indexs"
+                              :label="items.optioncontent"
+                            >
+                              {{ items.optioncontent }}
+                            </el-checkbox>
+                          </el-checkbox-group>
+                        </div>
+                        <div v-show="item.prompt && item.scriptResult[0]">
+                          <el-alert :title="item.prompt" type="warning">
+                          </el-alert>
+                        </div>
+                      </div>
+                      <!-- 濉┖ -->
+                      <div
+                        class="scriptTopic-dev"
+                        :key="index"
+                        v-if="item.scriptType == 4 && !item.astrict"
+                      >
+                        <div class="dev-text">
+                          {{ index + 1 }}銆乕闂瓟]<span>{{
+                            item.scriptContent
+                          }}</span>
+                          <span v-if="item.valueType == 3">(鍙兘杈撳叆鏁板瓧)</span>
+                        </div>
+                        <div class="dev-xx" v-if="item.valueType == 3">
+                          <el-input
+                            type="text"
+                            placeholder="璇疯緭鍏ョ瓟妗�"
+                            v-model="item.scriptResult"
+                            readonly
+                          >
+                          </el-input>
+                        </div>
+                        <div class="dev-xx" v-else>
+                          <el-input
+                            type="textarea"
+                            :rows="2"
+                            placeholder="璇疯緭鍏ョ瓟妗�"
+                            v-model="item.scriptResult"
+                            readonly
+                          >
+                          </el-input>
+                        </div>
+                      </div>
+                    </div>
+                  </div>
+                  <div class="preview-left" v-else>
+                    <div
+                      class="topic-dev"
+                      v-for="(item, index) in tableDatatop"
+                      :key="item.id"
+                    >
+                      <div v-if="item.targetvalue">
+                        <div class="dev-text">
+                          {{ index + 1 }}銆乕鍗曢�塢<span>{{
+                            item.questiontext
+                          }}</span>
+                        </div>
+                        <div class="dev-xx">
+                          <el-radio-group v-model="item.matchedtext" disabled>
+                            <el-radio
+                              v-for="(items, index) in item.scriptResult"
+                              :key="index"
+                              :label="items"
+                              :class="items.isabnormal ? 'red-star' : ''"
+                              >{{ items }}</el-radio
+                            >
+                          </el-radio-group>
+                        </div>
+                        <div v-show="item.prompt">
+                          <el-alert :title="item.prompt" type="warning">
+                          </el-alert>
+                        </div>
+                      </div>
+                      <div class="scriptTopic-dev" :key="index" v-else>
+                        <div class="dev-text">
+                          {{ index + 1 }}銆乕闂瓟]<span>{{
+                            item.scriptContent
+                          }}</span>
+                          <span v-if="item.valueType == 3">(鍙兘杈撳叆鏁板瓧)</span>
+                        </div>
+                        <div class="dev-xx" v-if="item.valueType == 3">
+                          <el-input
+                            type="text"
+                            placeholder="璇疯緭鍏ョ瓟妗�"
+                            v-model="item.scriptResult"
+                            readonly
+                          >
+                          </el-input>
+                        </div>
+                        <div class="dev-xx" v-else>
+                          <el-input
+                            type="textarea"
+                            :rows="2"
+                            placeholder="璇疯緭鍏ョ瓟妗�"
+                            v-model="item.scriptResult"
+                            readonly
+                          >
+                          </el-input>
+                        </div>
+                      </div>
+                    </div>
+                  </div>
+                </div>
+              </el-tab-pane>
+              <el-tab-pane name="yy">
+                <span slot="label"
+                  ><i class="el-icon-headset"></i> 璇煶闅忚璇︽儏</span
+                >
+                <div class="borderdiv">
+                  <div class="title">{{ taskname ? taskname : "闂嵎" }}</div>
+                  <div class="voice-audio">
+                    瀹屾暣璇煶锛�
+                    <mini-audio
+                      :audio-source="
+                        voice ? voice : '@assets/order/example.mp3'
+                      "
+                    ></mini-audio>
+                  </div>
+                  <div class="preview-left">
+                    <div v-for="item in voiceDatatop">
+                      <div class="leftside">
+                        <i class="el-icon-phone-outline"></i
+                        ><span>{{ item.questiontext }}</span>
+                      </div>
+                      <div class="offside">
+                        <i class="el-icon-user"></i>
+                        <div class="offside-value">
+                          <el-input
+                            type="textarea"
+                            :autosize="{ minRows: 1 }"
+                            v-model="item.asrtext"
+                            readonly
+                          ></el-input>
+                          <div>
+                            <mini-audio
+                              :audio-source="
+                                item.questionvoice
+                                  ? item.questionvoice
+                                  : '@assets/order/example.mp3'
+                              "
+                            ></mini-audio>
+                          </div>
+                        </div>
+                      </div>
+                    </div>
+                  </div>
+                </div>
+              </el-tab-pane>
+            </el-tabs>
+          </div>
+        </div>
+
+        <!-- 鍙冲崐閮ㄥ垎锛氬巻娆″欢缁姢鐞嗘湇鍔� -->
+        <!-- 鍙冲崐閮ㄥ垎锛氬巻娆″欢缁姢鐞嗘湇鍔� -->
+        <div class="continuity-history">
+          <div class="sub-headline">
+            <i class="el-icon-time"></i> 鍘嗘寤剁画鎶ょ悊鏈嶅姟
+            <el-button
+              type="primary"
+              size="small"
+              icon="el-icon-plus"
+              @click="addContinuityTab"
+              style="margin-left: 10px"
+              >鏂板寤剁画鎶ょ悊</el-button
+            >
+          </div>
+          <div class="history-content">
+            <el-tabs
+              v-model="activeContinuityTab"
+              type="card"
+              closable
+              @tab-remove="removeContinuityTab"
+              @tab-click="handleTabClick"
+            >
+              <el-tab-pane
+                v-for="(item, index) in continuityTabs"
+                :key="item.name"
+                :label="item.title"
+                :name="item.name"
+              >
+                <div class="continuity-form">
+                  <el-form
+                    :ref="'continuityForm' + index"
+                    :model="item.form"
+                    :rules="continuityRules"
+                    label-width="120px"
+                  >
+                    <!-- 寤剁画闂琛ㄥ崟 -->
+                    <el-form-item label="寤剁画闂" prop="continuityProblems">
+                      <div class="continuity-problems-form">
+                        <div class="problems-header">
+                          <span>宸查�夊彇鐨勫欢缁棶棰橈細</span>
+                          <el-button
+                            type="text"
+                            size="small"
+                            icon="el-icon-plus"
+                            @click="addContinuityProblem(index)"
+                          >
+                            鏂板闂
+                          </el-button>
+                        </div>
+
+                        <!-- 宸查�夊彇鐨勯棶棰樺垪琛� -->
+                        <div
+                          v-if="
+                            item.form.continuityProblems &&
+                            item.form.continuityProblems.length > 0
+                          "
+                          class="problems-list-container"
+                        >
+                          <div
+                            v-for="(problem, problemIndex) in item.form
+                              .continuityProblems"
+                            :key="problemIndex"
+                            class="problem-item"
+                          >
+                            <div class="problem-content">
+                              <div class="problem-meta">
+                                <span class="problem-index"
+                                  >闂 {{ problemIndex + 1 }}</span
+                                >
+                                <el-select
+                                  v-model="problem.questionId"
+                                  placeholder="閫夋嫨闂"
+                                  size="small"
+                                  style="width: 300px; margin: 0 10px"
+                                  @change="
+                                    handleProblemChange(
+                                      index,
+                                      problemIndex,
+                                      $event
+                                    )
+                                  "
+                                >
+                                  <el-option
+                                    v-for="q in availableQuestions"
+                                    :key="q.id"
+                                    :label="q.text"
+                                    :value="q.id"
+                                  >
+                                    <span
+                                      >{{ q.index + 1 }}.
+                                      {{ truncateText(q.text, 40) }}</span
+                                    >
+                                  </el-option>
+                                </el-select>
+                                <!-- 淇锛氫紶閫掓纭殑绱㈠紩 -->
+                                <el-button
+                                  type="danger"
+                                  icon="el-icon-delete"
+                                  size="mini"
+                                  circle
+                                  @click="
+                                    removeContinuityProblem(index, problemIndex)
+                                  "
+                                >
+                                </el-button>
+                              </div>
+
+                              <!-- 闂嵎寮忛棶棰樺睍绀哄尯鍩� -->
+                              <div
+                                v-if="problem.questionId"
+                                class="question-display-area"
+                              >
+                                <!-- 鏍规嵁闂绫诲瀷鍔ㄦ�佹覆鏌� -->
+                                <div
+                                  v-if="
+                                    getQuestionOriginalData(problem.questionId)
+                                  "
+                                  class="question-render"
+                                >
+                                  <!-- 鍗曢�夌被鍨� -->
+                                  <div
+                                    v-if="
+                                      getQuestionOriginalData(
+                                        problem.questionId
+                                      ).scriptType == 1
+                                    "
+                                    class="question-item-render"
+                                  >
+                                    <div class="question-text">
+                                      <strong>[鍗曢�塢</strong>
+                                      <span>{{
+                                        getQuestionOriginalData(
+                                          problem.questionId
+                                        ).scriptContent
+                                      }}</span>
+                                    </div>
+                                    <div class="question-options">
+                                      <el-radio-group
+                                        v-model="problem.selectedOption"
+                                      >
+                                        <el-radio
+                                          v-for="option in getQuestionOriginalData(
+                                            problem.questionId
+                                          ).svyTaskTemplateTargetoptions"
+                                          :key="option.optioncontent"
+                                          :label="option.optioncontent"
+                                          :class="getOptionClass(option)"
+                                        >
+                                          {{ option.optioncontent }}
+                                        </el-radio>
+                                      </el-radio-group>
+                                    </div>
+                                    <!-- 闄勫姞杈撳叆妗� -->
+                                    <div
+                                      v-if="problem.showAppendInput"
+                                      class="append-input"
+                                      style="margin-top: 10px"
+                                    >
+                                      <el-input
+                                        type="textarea"
+                                        :rows="2"
+                                        placeholder="璇疯緭鍏ュ叿浣撲俊鎭�"
+                                        v-model="problem.appendInput"
+                                      ></el-input>
+                                    </div>
+                                  </div>
+
+                                  <!-- 澶氶�夌被鍨� -->
+                                  <div
+                                    v-else-if="
+                                      getQuestionOriginalData(
+                                        problem.questionId
+                                      ).scriptType == 2
+                                    "
+                                    class="question-item-render"
+                                  >
+                                    <div class="question-text">
+                                      <strong>[澶氶�塢</strong>
+                                      <span>{{
+                                        getQuestionOriginalData(
+                                          problem.questionId
+                                        ).scriptContent
+                                      }}</span>
+                                    </div>
+                                    <div class="question-options">
+                                      <el-checkbox-group
+                                        v-model="problem.selectedOptions"
+                                      >
+                                        <el-checkbox
+                                          v-for="option in getQuestionOriginalData(
+                                            problem.questionId
+                                          ).svyTaskTemplateTargetoptions"
+                                          :key="option.optioncontent"
+                                          :label="option.optioncontent"
+                                          :class="
+                                            option.isabnormal ? 'red-star' : ''
+                                          "
+                                        >
+                                          {{ option.optioncontent }}
+                                        </el-checkbox>
+                                      </el-checkbox-group>
+                                    </div>
+                                  </div>
+
+                                  <!-- 濉┖/闂瓟绫诲瀷 -->
+                                  <div
+                                    v-else-if="
+                                      getQuestionOriginalData(
+                                        problem.questionId
+                                      ).scriptType == 4
+                                    "
+                                    class="question-item-render"
+                                  >
+                                    <div class="question-text">
+                                      <strong>[闂瓟]</strong>
+                                      <span>{{
+                                        getQuestionOriginalData(
+                                          problem.questionId
+                                        ).scriptContent
+                                      }}</span>
+                                      <span
+                                        v-if="
+                                          getQuestionOriginalData(
+                                            problem.questionId
+                                          ).valueType == 3
+                                        "
+                                        >(鍙兘杈撳叆鏁板瓧)</span
+                                      >
+                                    </div>
+                                    <div class="question-options">
+                                      <el-input
+                                        v-if="
+                                          getQuestionOriginalData(
+                                            problem.questionId
+                                          ).valueType == 3
+                                        "
+                                        type="text"
+                                        placeholder="璇疯緭鍏ョ瓟妗�"
+                                        v-model="problem.answer"
+                                        style="width: 200px"
+                                      ></el-input>
+                                      <el-input
+                                        v-else
+                                        type="textarea"
+                                        :rows="2"
+                                        placeholder="璇疯緭鍏ョ瓟妗�"
+                                        v-model="problem.answer"
+                                        style="width: 100%"
+                                      ></el-input>
+                                    </div>
+                                  </div>
+                                </div>
+                                <div v-else class="no-question-data">
+                                  闂鏁版嵁鍔犺浇涓�...
+                                </div>
+                              </div>
+
+                              <!-- 鍘熸湁鐨勯棶棰樻弿杩扮瓑瀛楁 -->
+                              <div class="problem-detail">
+                                <div class="detail-row">
+                                  <span class="detail-label">褰撳墠鐘舵�侊細</span>
+                                  <el-select
+                                    v-model="problem.status"
+                                    placeholder="閫夋嫨鐘舵��"
+                                    size="small"
+                                    style="width: 120px; margin-right: 20px"
+                                  >
+                                    <el-option
+                                      label="鏈鐞�"
+                                      value="pending"
+                                    ></el-option>
+                                    <el-option
+                                      label="澶勭悊涓�"
+                                      value="processing"
+                                    ></el-option>
+                                    <el-option
+                                      label="宸茶В鍐�"
+                                      value="resolved"
+                                    ></el-option>
+                                    <el-option
+                                      label="鎸佺画鍏虫敞"
+                                      value="watching"
+                                    ></el-option>
+                                  </el-select>
+
+                                  <span
+                                    class="detail-label"
+                                    v-if="problem.status === 'resolved'"
+                                    style="margin-left: 20px"
+                                  >
+                                    瑙e喅鏃ユ湡锛�
+                                  </span>
+                                  <el-date-picker
+                                    v-if="problem.status === 'resolved'"
+                                    v-model="problem.resolvedDate"
+                                    type="date"
+                                    placeholder="閫夋嫨瑙e喅鏃ユ湡"
+                                    value-format="yyyy-MM-dd"
+                                    size="small"
+                                    style="width: 150px; margin-left: 10px"
+                                  ></el-date-picker>
+                                </div>
+
+                                <!-- <div class="detail-row">
+                                  <span class="detail-label">闂鎻忚堪锛�</span>
+                                  <el-input
+                                    type="textarea"
+                                    :rows="2"
+                                    v-model="problem.description"
+                                    placeholder="璇疯缁嗘弿杩拌寤剁画闂锛堝彲璁板綍璇勪及缁撴灉銆佸鐞嗗缓璁瓑锛�"
+                                    size="small"
+                                    style="flex: 1"
+                                  ></el-input>
+                                </div> -->
+                              </div>
+                            </div>
+                          </div>
+                        </div>
+                      </div>
+                    </el-form-item>
+
+                    <!-- 寤剁画鎬ф姢鐞嗚褰� -->
+                    <el-form-item label="鎶ょ悊璁板綍" prop="careRecord">
+                      <el-input
+                        type="textarea"
+                        :rows="4"
+                        v-model="item.form.careRecord"
+                        placeholder="璇疯緭鍏ュ欢缁�ф姢鐞嗚褰�"
+                        clearable
+                      ></el-input>
+                    </el-form-item>
+
+                    <!-- 璐d换鎶ゅ+銆佸洖璁垮舰寮忋�佹湇鍔℃椂闂� -->
+                    <el-row :gutter="20">
+                      <el-col :span="12">
+                        <el-form-item label="璐d换鎶ゅ+" prop="dutyNurse">
+                          <el-input
+                            v-model="item.form.dutyNurse"
+                            placeholder="璇疯緭鍏ヨ矗浠绘姢澹�"
+                            clearable
+                          ></el-input>
+                        </el-form-item>
+                      </el-col>
+                      <el-col :span="12">
+                        <el-form-item label="鍥炶褰㈠紡" prop="visitType">
+                          <el-select
+                            v-model="item.form.visitType"
+                            placeholder="璇烽�夋嫨鍥炶褰㈠紡"
+                            style="width: 100%"
+                            clearable
+                          >
+                            <el-option
+                              label="鐢佃瘽鍥炶"
+                              value="phone"
+                            ></el-option>
+                            <el-option
+                              label="涓婇棬鍥炶"
+                              value="home"
+                            ></el-option>
+                            <el-option
+                              label="闂ㄨ瘖鍥炶"
+                              value="clinic"
+                            ></el-option>
+                            <el-option
+                              label="寰俊鍥炶"
+                              value="wechat"
+                            ></el-option>
+                            <el-option label="鍏朵粬" value="other"></el-option>
+                          </el-select>
+                        </el-form-item>
+                      </el-col>
+                    </el-row>
+                    <el-row :gutter="20">
+                      <el-col :span="12">
+                        <el-form-item
+                          label="涓嬫鏈嶅姟鏃堕棿"
+                          prop="nextServiceTime"
+                        >
+                          <el-date-picker
+                            v-model="item.form.nextServiceTime"
+                            type="datetime"
+                            placeholder="閫夋嫨涓嬫寤剁画鏈嶅姟鏃堕棿"
+                            value-format="yyyy-MM-dd HH:mm:ss"
+                            style="width: 100%"
+                          >
+                          </el-date-picker>
+                          <div
+                            class="time-tip"
+                            v-if="item.form.nextServiceTime"
+                          >
+                            璺濅笅娆℃湇鍔¤繕鏈�
+                            {{ calculateDaysLeft(item.form.nextServiceTime) }}
+                            澶�
+                          </div>
+                        </el-form-item>
+                      </el-col>
+                      <el-col :span="12">
+                        <el-form-item label="鏈嶅姟鏃堕棿" prop="serviceTime">
+                          <el-date-picker
+                            v-model="item.form.serviceTime"
+                            type="datetime"
+                            placeholder="閫夋嫨鏈嶅姟鏃堕棿"
+                            value-format="yyyy-MM-dd HH:mm:ss"
+                            style="width: 100%"
+                          >
+                          </el-date-picker>
+                        </el-form-item>
+                      </el-col>
+                    </el-row>
+
+                    <!-- 涓嬫寤剁画鏈嶅姟鏃堕棿 -->
+
+                    <!-- 鎿嶄綔鎸夐挳 -->
+                    <el-form-item>
+                      <el-button
+                        type="primary"
+                        @click="saveContinuityTab(index)"
+                        :loading="item.saving"
+                      >
+                        淇濆瓨
+                      </el-button>
+                      <el-button @click="resetContinuityTab(index)">
+                        閲嶇疆
+                      </el-button>
+                    </el-form-item>
+                  </el-form>
+                </div>
+              </el-tab-pane>
+            </el-tabs>
+          </div>
+        </div>
+      </div>
+    </div>
+  </div>
+</template>
+<script>
+import {
+  getsearchrResults,
+  getPersonVoices,
+  getTaskservelist,
+  Editsingletaskson,
+} from "@/api/AiCentre/index";
+import {
+  messagelistpatient,
+  alterpatient,
+  listcontactinformation,
+} from "@/api/patient/homepage";
+
+export default {
+  dicts: ["sys_yujing"],
+  data() {
+    return {
+      // 璺敱鍙傛暟
+      taskid: "",
+      id: "",
+      sendname: "",
+      patid: "",
+      Voicetype: 0,
+      serviceType: "",
+
+      // 闅忚鍐呭鐩稿叧
+      activeName: "wj",
+      taskname: "",
+      voice: "",
+      tableDatatop: [],
+      voiceDatatop: [],
+      form: {},
+      userform: {},
+      // 鏂板锛氶棶棰橀�夋嫨鐩稿叧
+      showQuestionSelector: false,
+      selectedQuestionIds: [],
+      // 鎮h�呭熀纭�淇℃伅琛ㄥ崟
+      patientForm: {
+        name: "",
+        sex: "",
+        age: "",
+        telcode: "",
+        hospitalNumber: "",
+        dischargeDate: "",
+        diagnosis: "",
+        nurseName: "",
+        address: "",
+        relativeName: "",
+        relativeTel: "",
+      },
+      patientRules: {
+        name: [{ required: true, message: "璇疯緭鍏ユ偅鑰呭鍚�", trigger: "blur" }],
+        age: [
+          { required: true, message: "璇疯緭鍏ュ勾榫�", trigger: "blur" },
+          { pattern: /^\d+$/, message: "骞撮緞蹇呴』涓烘暟瀛�", trigger: "blur" },
+        ],
+        telcode: [
+          { required: true, message: "璇疯緭鍏ヨ仈绯荤數璇�", trigger: "blur" },
+          {
+            pattern: /^1[3-9]\d{9}$/,
+            message: "璇疯緭鍏ユ纭殑鎵嬫満鍙风爜",
+            trigger: "blur",
+          },
+        ],
+      },
+      savingPatientInfo: false,
+
+      // 寤剁画鎶ょ悊鐩稿叧
+      activeContinuityTab: "continuity-0",
+      continuityTabs: [],
+      continuityTabIndex: 0,
+      continuityRules: {
+        // 绉婚櫎continuityProblems鐨勯獙璇佽鍒�
+        careRecord: [
+          { required: true, message: "璇疯緭鍏ユ姢鐞嗚褰�", trigger: "blur" },
+        ],
+        dutyNurse: [
+          { required: true, message: "璇疯緭鍏ヨ矗浠绘姢澹�", trigger: "blur" },
+        ],
+        visitType: [
+          { required: true, message: "璇烽�夋嫨鍥炶褰㈠紡", trigger: "change" },
+        ],
+        serviceTime: [
+          { required: true, message: "璇烽�夋嫨鏈嶅姟鏃堕棿", trigger: "change" },
+        ],
+        nextServiceTime: [
+          { required: true, message: "璇烽�夋嫨涓嬫鏈嶅姟鏃堕棿", trigger: "change" },
+        ],
+      },
+
+      // 鍙�夌殑寤剁画闂锛堜粠宸︿晶闂嵎涓彁鍙栵級
+      availableQuestions: [],
+
+      // 寤剁画鎶ょ悊姹囨�讳俊鎭�
+      continuitySummary: {
+        continueCount: 0,
+        continueTimeNow: "",
+        continueTimeNext: "",
+        continueContent: "",
+      },
+
+      // 鍏朵粬
+      logsheetlist: [],
+    };
+  },
+  created() {
+    this.taskid = this.$route.query.taskid;
+    this.id = this.$route.query.id;
+    this.sendname = this.$route.query.sendname;
+    this.patid = this.$route.query.patid;
+    this.Voicetype = this.$route.query.Voicetype || 0;
+    this.serviceType = this.$route.query.serviceType;
+
+    this.getTaskservelist(this.id);
+  },
+  methods: {
+    // 鑾峰彇涓婚鏍峰紡绫�
+    getTopicClass(item) {
+      console.log(item.isabnormal, "getTopicClass");
+
+      if (item.isabnormal == 1) {
+        return "scriptTopic-isabnormal";
+      } else if (item.isabnormal == 2) {
+        return "scriptTopic-warning";
+      } else {
+        return "scriptTopic-dev";
+      }
+    },
+
+    // 鑾峰彇閫夐」鏍峰紡绫�
+    getOptionClass(items) {
+      if (items.isabnormal == 1) {
+        return "red-star";
+      } else if (items.isabnormal == 2) {
+        return "yellow-star";
+      }
+      return "";
+    },
+
+    // 鑾峰彇闂嵎鏁版嵁
+    getsearchrResults(id) {
+      getsearchrResults({
+        taskid: this.taskid,
+        patid: this.patid,
+        subId: id ? id : this.id,
+        isFinish: false,
+      }).then((res) => {
+        if (res.code === 200) {
+          this.tableDatatop = res.data.scriptResult;
+
+          this.tableDatatop.forEach((item) => {
+            if (item.scriptType == 2) item.scriptResult = [];
+            if (item.scriptResultId && item.scriptType != 2) {
+              item.isoption = 3;
+              item.scriptResult = item.scriptResult;
+            } else if (item.scriptResultId && item.scriptType == 2) {
+              item.scriptResult = item.scriptResult.split("&");
+              item.isoption = 3;
+            }
+          });
+          this.taskname = res.data.taskName;
+          this.overdata();
+          // 鎻愬彇鍙�夌殑寤剁画闂
+          this.extractAvailableQuestions();
+        }
+      });
+    },
+    overdata() {
+      this.tableDatatop.forEach((item, index) => {
+        var obj = item.svyTaskTemplateTargetoptions.find(
+          (items) => items.optioncontent == item.scriptResult
+        );
+        if (obj) {
+          console.log(obj, "obj");
+          if (obj.isabnormal) {
+            this.tableDatatop[index].isabnormal = obj.isabnormal;
+          }
+          this.$forceUpdate();
+        }
+      });
+    },
+    // 鎻愬彇鍙�夌殑寤剁画闂
+    extractAvailableQuestions() {
+      this.availableQuestions = this.tableDatatop
+        .filter(
+          (item) => item.scriptContent && item.scriptContent.trim() !== ""
+        )
+        .map((item, index) => ({
+          id: `question-${index}`,
+          index: index,
+          text: item.scriptContent,
+          originalIndex: index,
+        }));
+    }, // 鍒囨崲闂閫夋嫨闈㈡澘鏄剧ず
+    toggleQuestionSelection() {
+      this.showQuestionSelector = !this.showQuestionSelector;
+      if (this.showQuestionSelector) {
+        // 閲嶇疆閫夋嫨
+        this.selectedQuestionIds = [];
+      }
+    },
+    // 娣诲姞寤剁画闂
+    addContinuityProblem(tabIndex) {
+      this.continuityTabs[tabIndex].form.continuityProblems.push({
+        questionId: "",
+        status: "pending",
+        description: "",
+        resolvedDate: "",
+        createTime: new Date().toISOString(),
+        // 鏂板瀛楁锛岀敤浜庨棶鍗峰紡浜や簰
+        selectedOption: "", // 鍗曢�夌瓟妗�
+        selectedOptions: [], // 澶氶�夌瓟妗�
+        answer: "", // 濉┖绛旀
+        showAppendInput: false, // 鏄惁鏄剧ず闄勫姞杈撳叆妗�
+        appendInput: "", // 闄勫姞杈撳叆鍐呭
+      });
+    },
+    // 鏍规嵁闂ID鑾峰彇鍘熷闂鏁版嵁
+    getQuestionOriginalData(questionId) {
+      if (!questionId) return null;
+      const originalIndex = this.availableQuestions.find(
+        (q) => q.id === questionId
+      )?.originalIndex;
+      if (originalIndex !== undefined && this.tableDatatop[originalIndex]) {
+        return this.tableDatatop[originalIndex];
+      }
+      return null;
+    },
+    // 绉婚櫎寤剁画闂
+    removeContinuityProblem(tabIndex, problemIndex) {
+      this.continuityTabs[tabIndex].form.continuityProblems.splice(
+        problemIndex,
+        1
+      );
+    },
+
+    // 澶勭悊闂閫夋嫨鍙樻洿
+    handleProblemChange(tabIndex, problemIndex, questionId) {
+      const problem =
+        this.continuityTabs[tabIndex].form.continuityProblems[problemIndex];
+
+      if (!questionId) {
+        problem.description = "";
+        // 娓呯┖绛旀瀛楁
+        problem.selectedOption = "";
+        problem.selectedOptions = [];
+        problem.answer = "";
+        problem.showAppendInput = false;
+        problem.appendInput = "";
+        return;
+      }
+
+      // 鑷姩濉厖闂鎻忚堪
+      const question = this.availableQuestions.find((q) => q.id === questionId);
+      if (question) {
+        problem.description = `闂锛�${question.text}`;
+      }
+
+      // 鏍规嵁闂绫诲瀷鍒濆鍖栫瓟妗堝瓧娈�
+      const originalData = this.getQuestionOriginalData(questionId);
+      if (originalData) {
+        // 鍒濆鍖栧崟閫夌瓟妗�
+        if (originalData.scriptType === 1) {
+          problem.selectedOption = originalData.scriptResult || "";
+          // 妫�鏌ユ槸鍚﹂渶瑕佹樉绀洪檮鍔犺緭鍏ユ
+          problem.showAppendInput = originalData.showAppendInput || false;
+          problem.appendInput = originalData.answerps || "";
+        }
+        // 鍒濆鍖栧閫夌瓟妗�
+        else if (originalData.scriptType === 2) {
+          problem.selectedOptions = Array.isArray(originalData.scriptResult)
+            ? [...originalData.scriptResult]
+            : originalData.scriptResult
+            ? originalData.scriptResult.split("&")
+            : [];
+        }
+        // 鍒濆鍖栧~绌虹瓟妗�
+        else if (originalData.scriptType === 4) {
+          problem.answer = originalData.scriptResult || "";
+        }
+      }
+    },
+
+    // 鏍规嵁闂ID鑾峰彇闂鏂囨湰
+    getQuestionText(questionId) {
+      if (!questionId) return "鏈�夋嫨闂";
+      const question = this.availableQuestions.find((q) => q.id === questionId);
+      return question
+        ? `${question.index + 1}. ${question.text}`
+        : "闂宸插垹闄�";
+    },
+
+    // 鎴柇鏂囨湰
+    truncateText(text, length) {
+      if (!text) return "";
+      return text.length > length ? text.substring(0, length) + "..." : text;
+    },
+    // 纭闂閫夋嫨
+    confirmQuestionSelection() {
+      if (this.selectedQuestionIds.length === 0) {
+        this.$modal.msgWarning("璇疯嚦灏戦�夋嫨涓�涓欢缁棶棰�");
+        return;
+      }
+
+      // 鑾峰彇褰撳墠婵�娲荤殑鏍囩椤电储寮�
+      const activeTabIndex = this.continuityTabs.findIndex(
+        (tab) => tab.name === this.activeContinuityTab
+      );
+
+      if (activeTabIndex === -1) {
+        this.$modal.msgError("鏈壘鍒版縺娲荤殑寤剁画鎶ょ悊鏍囩椤�");
+        return;
+      }
+
+      // 娣诲姞閫変腑鐨勯棶棰樺埌褰撳墠鏍囩椤�
+      this.selectedQuestionIds.forEach((questionId) => {
+        // 妫�鏌ユ槸鍚﹀凡瀛樺湪鐩稿悓闂
+        const exists = this.continuityTabs[
+          activeTabIndex
+        ].form.continuityProblems.some(
+          (problem) => problem.questionId === questionId
+        );
+
+        if (!exists) {
+          this.continuityTabs[activeTabIndex].form.continuityProblems.push({
+            questionId: questionId,
+            status: "pending",
+            description: "",
+            resolvedDate: "",
+            createTime: new Date().toISOString(),
+          });
+        }
+      });
+
+      // 鍏抽棴閫夋嫨闈㈡澘
+      this.showQuestionSelector = false;
+      this.selectedQuestionIds = [];
+
+      this.$modal.msgSuccess(
+        `宸叉坊鍔� ${this.selectedQuestionIds.length} 涓欢缁棶棰榒
+      );
+    },
+
+    // 绉婚櫎寤剁画闂
+    removeContinuityProblem(tabIndex, problemIndex) {
+      this.continuityTabs[tabIndex].form.continuityProblems.splice(
+        problemIndex,
+        1
+      );
+    },
+
+    // 鑾峰彇璇煶鏁版嵁
+    getPersonVoices(id) {
+      let obj = {
+        taskid: this.taskid,
+        patid: this.patid,
+        subId: id ? id : this.id,
+      };
+
+      getPersonVoices(obj).then((res) => {
+        if (res.code == 200) {
+          this.voiceDatatop = res.data.serviceSubtaskDetails;
+          this.voice = res.data.voice;
+          this.activeName = "yy";
+          this.taskname = res.data.taskName;
+          this.tableDatatop = res.data.filteredDetails;
+          this.tableDatatop.forEach((item) => {
+            if (item.targetvalue) {
+              item.scriptResult = item.targetvalue.split("&");
+            } else {
+              item.scriptResult = [];
+            }
+          });
+
+          // 鎻愬彇鍙�夌殑寤剁画闂
+          this.extractAvailableQuestions();
+        }
+      });
+    },
+
+    // 鑾峰彇鍩虹淇℃伅
+    getuserinfo() {
+      const queryParams = {
+        pid: Number(this.patid),
+        allhosp: "0",
+      };
+
+      messagelistpatient(queryParams).then((response) => {
+        if (response.rows[0]) {
+          this.userform = response.rows[0];
+          this.initPatientForm();
+        }
+      });
+
+      listcontactinformation({ patid: this.patid }).then((response) => {
+        this.tableData = response.rows;
+        if (this.tableData.length) {
+          this.patientForm.relativeName = this.tableData[0].relation || "";
+          this.patientForm.relativeTel = this.tableData[0].contactway || "";
+        }
+      });
+    },
+
+    // 鍒濆鍖栨偅鑰呰〃鍗�
+    initPatientForm() {
+      if (this.userform) {
+        this.patientForm.name = this.userform.name || "";
+        this.patientForm.sex = this.userform.sex || "";
+        this.patientForm.age = this.userform.age || "";
+        this.patientForm.telcode = this.userform.telcode || "";
+        this.patientForm.address = this.userform.placeOfResidence || "";
+        this.patientForm.hospitalNumber = this.userform.medicalRecordNo || "";
+      }
+
+      if (this.form) {
+        this.patientForm.dischargeDate =
+          this.formatTime(this.form.endtime) || "";
+        this.patientForm.diagnosis = this.form.leavediagname || "";
+        this.patientForm.nurseName = this.form.nurseName || "";
+      }
+    },
+
+    // 鑾峰彇鎮h�呰褰�
+    getTaskservelist(id) {
+      getTaskservelist({
+        patid: this.patid,
+        subId: id,
+        pageSize: 100,
+      }).then((res) => {
+        if (res.code == 200) {
+          this.form = res.rows[0].serviceSubtaskList.find(
+            (item) => item.id == this.id
+          );
+          this.logsheetlist = res.rows[0].serviceSubtaskList;
+
+          // 鍒濆鍖栨偅鑰呬俊鎭�
+          this.initPatientForm();
+
+          // 鍔犺浇鍘嗗彶寤剁画鎶ょ悊鏁版嵁
+          this.loadContinuityHistory();
+          this.getuserinfo();
+        }
+
+        if (this.Voicetype) {
+          this.getPersonVoices();
+        } else {
+          this.getsearchrResults();
+        }
+      });
+    },
+
+    // 鍔犺浇鍘嗗彶寤剁画鎶ょ悊鏁版嵁
+    loadContinuityHistory() {
+      if (this.form && this.form.continueContent) {
+        try {
+          const historyData = JSON.parse(this.form.continueContent);
+          this.continuityTabs = historyData.map((item, index) => ({
+            name: `continuity-${index}`,
+            title: `寤剁画鎶ょ悊${index + 1}`,
+            form: {
+              continuityProblems: item.continuityProblems || [],
+              careRecord: item.careRecord || "",
+              dutyNurse: item.dutyNurse || "",
+              visitType: item.visitType || "",
+              serviceTime: item.serviceTime || "",
+              nextServiceTime: item.nextServiceTime || "",
+            },
+            saving: false,
+          }));
+
+          if (this.continuityTabs.length > 0) {
+            this.activeContinuityTab = this.continuityTabs[0].name;
+          }
+
+          // 鏇存柊姹囨�讳俊鎭�
+          this.updateContinuitySummary();
+        } catch (error) {
+          console.error("瑙f瀽寤剁画鎶ょ悊鍘嗗彶鏁版嵁澶辫触:", error);
+        }
+      }
+    },
+
+    // 鏇存柊寤剁画鎶ょ悊姹囨�讳俊鎭�
+    updateContinuitySummary() {
+      if (this.form) {
+        this.continuitySummary.continueCount = this.form.continueCount || 0;
+        this.continuitySummary.continueTimeNow =
+          this.form.continueTimeNow || "";
+        this.continuitySummary.continueTimeNext =
+          this.form.continueTimeNext || "";
+        this.continuitySummary.continueContent =
+          this.form.continueContent || "";
+      }
+    },
+
+    // 娣诲姞寤剁画鎶ょ悊鏍囩椤�
+    addContinuityTab() {
+      console.log(this.continuityTabs.length);
+      if (this.continuityTabs.length) {
+        this.continuityTabIndex = this.continuityTabs.length;
+      }
+      const newIndex = this.continuityTabIndex + 1;
+      const newTab = {
+        name: `continuity-${newIndex}`,
+        title: `寤剁画鎶ょ悊${newIndex}`,
+        form: {
+          continuityProblems: [],
+          careRecord: "",
+          dutyNurse: "",
+          visitType: "",
+          serviceTime: "",
+          nextServiceTime: "",
+        },
+        saving: false,
+      };
+
+      this.continuityTabs.push(newTab);
+      this.continuityTabIndex = newIndex;
+      this.activeContinuityTab = newTab.name;
+    },
+
+    // 绉婚櫎寤剁画鎶ょ悊鏍囩椤�
+    removeContinuityTab(targetName) {
+      const tabs = this.continuityTabs;
+      let activeName = this.activeContinuityTab;
+
+      if (activeName === targetName) {
+        tabs.forEach((tab, index) => {
+          if (tab.name === targetName) {
+            const nextTab = tabs[index + 1] || tabs[index - 1];
+            if (nextTab) {
+              activeName = nextTab.name;
+            }
+          }
+        });
+      }
+
+      this.activeContinuityTab = activeName;
+      this.continuityTabs = tabs.filter((tab) => tab.name !== targetName);
+    },
+
+    // 澶勭悊鏍囩椤电偣鍑�
+    handleTabClick(tab) {
+      this.activeContinuityTab = tab.name;
+    },
+
+    // 璁$畻璺濈涓嬫鏈嶅姟杩樻湁澶氬皯澶�
+    calculateDaysLeft(nextServiceTime) {
+      if (!nextServiceTime) return 0;
+
+      const nextTime = new Date(nextServiceTime);
+      const now = new Date();
+      const diffTime = nextTime - now;
+      const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24));
+
+      return diffDays > 0 ? diffDays : 0;
+    },
+
+    // 淇濆瓨寤剁画鎶ょ悊鏍囩椤�
+    saveContinuityTab(index) {
+      const formRef = this.$refs[`continuityForm${index}`];
+      if (!formRef) return;
+
+      // 楠岃瘉鍩烘湰琛ㄥ崟
+      formRef[0].validate((valid) => {
+        if (valid) {
+          // 楠岃瘉寤剁画闂鏄惁瀹屾暣
+          const problems = this.continuityTabs[index].form.continuityProblems;
+          let hasError = false;
+
+          problems.forEach((problem, problemIndex) => {
+            if (!problem.questionId) {
+              hasError = true;
+              this.$modal.msgError(`绗�${problemIndex + 1}涓欢缁棶棰樻湭閫夋嫨`);
+            }
+          });
+
+          if (hasError) {
+            return false;
+          }
+
+          this.continuityTabs[index].saving = true;
+
+          // 鏇存柊姹囨�讳俊鎭�
+          this.updateContinuitySummaryFromTabs();
+
+          // 璋冪敤淇濆瓨API
+          this.saveContinuityData();
+        } else {
+          this.$modal.msgError("璇峰~鍐欏畬鏁翠俊鎭�");
+          return false;
+        }
+      });
+    },
+
+    // 鏇存柊寤剁画鎶ょ悊姹囨�讳俊鎭�
+    updateContinuitySummaryFromTabs() {
+      if (this.continuityTabs.length === 0) return;
+
+      // 鎵惧埌鏈�鏂扮殑鏈嶅姟鏃堕棿
+      let latestTime = "";
+      let nextTime = "";
+      let totalProblems = 0;
+
+      this.continuityTabs.forEach((tab) => {
+        if (tab.form.serviceTime) {
+          if (
+            !latestTime ||
+            new Date(tab.form.serviceTime) > new Date(latestTime)
+          ) {
+            latestTime = tab.form.serviceTime;
+          }
+        }
+        if (tab.form.nextServiceTime) {
+          if (
+            !nextTime ||
+            new Date(tab.form.nextServiceTime) < new Date(nextTime)
+          ) {
+            nextTime = tab.form.nextServiceTime;
+          }
+        }
+
+        // 缁熻闂鏁伴噺
+        totalProblems += tab.form.continuityProblems.length;
+      });
+
+      this.continuitySummary.continueCount = this.continuityTabs.length;
+      this.continuitySummary.continueTimeNow = latestTime;
+      this.continuitySummary.continueTimeNext = nextTime;
+
+      // 鏋勫缓瀹屾暣鐨勫欢缁姢鐞嗘暟鎹�
+      const continuityData = this.continuityTabs.map((tab) => ({
+        ...tab.form,
+        tabTitle: tab.title,
+        tabName: tab.name,
+      }));
+
+      this.continuitySummary.continueContent = JSON.stringify(continuityData);
+      this.continuitySummary.totalProblems = totalProblems;
+    },
+
+    // 淇濆瓨寤剁画鎶ょ悊鏁版嵁
+    saveContinuityData() {
+      const vm = this;
+
+      // 楠岃瘉姣忎釜闂鐨剄uestionId鏄惁宸查�夋嫨
+      let hasEmptyQuestion = false;
+      this.continuityTabs.forEach((tab, tabIndex) => {
+        tab.form.continuityProblems.forEach((problem, problemIndex) => {
+          if (!problem.questionId) {
+            hasEmptyQuestion = true;
+            vm.$modal.msgError(
+              `绗�${tabIndex + 1}涓爣绛鹃〉鐨勭${problemIndex + 1}涓棶棰樻湭閫夋嫨`
+            );
+          }
+        });
+      });
+
+      if (hasEmptyQuestion) {
+        return;
+      }
+
+      const formData = {
+        id: vm.id,
+        patid: vm.patid,
+        taskid: vm.taskid,
+        continueFlag: 2,
+        continueCount: vm.continuitySummary.continueCount,
+        continueTimeNow: vm.continuitySummary.continueTimeNow,
+        continueTimeNext: vm.continuitySummary.continueTimeNext,
+        continueContent: vm.continuitySummary.continueContent,
+        // 鍙互娣诲姞闂嵎绛旀鐨勬暣鍚�
+        // questionnaireAnswers: vm.continuityTabs.map((tab) => ({
+        //   tabName: tab.name,
+        //   problems: tab.form.continuityProblems.map((problem) => ({
+        //     questionId: problem.questionId,
+        //     answer:
+        //       problem.selectedOption ||
+        //       problem.selectedOptions ||
+        //       problem.answer,
+        //     status: problem.status,
+        //     description: problem.description,
+        //   })),
+        // })),
+      };
+
+      Editsingletaskson(formData)
+        .then((res) => {
+          if (res.code === 200) {
+            vm.$modal.msgSuccess("寤剁画鎶ょ悊璁板綍淇濆瓨鎴愬姛");
+            // 閲嶇疆淇濆瓨鐘舵��
+            vm.continuityTabs.forEach((tab) => {
+              tab.saving = false;
+            });
+          } else {
+            vm.$modal.msgError("淇濆瓨澶辫触");
+          }
+        })
+        .catch((error) => {
+          console.error("淇濆瓨澶辫触:", error);
+          vm.$modal.msgError("淇濆瓨澶辫触");
+          vm.continuityTabs.forEach((tab) => {
+            tab.saving = false;
+          });
+        });
+    },
+
+    // 閲嶇疆寤剁画鎶ょ悊鏍囩椤�
+    resetContinuityTab(index) {
+      this.continuityTabs[index].form = {
+        continuityProblems: [],
+        careRecord: "",
+        dutyNurse: "",
+        visitType: "",
+        serviceTime: "",
+        nextServiceTime: "",
+      };
+      this.$refs[`continuityForm${index}`][0].clearValidate();
+    },
+
+    // 淇濆瓨鎮h�呬俊鎭�
+    savePatientInfo() {
+      this.$refs.patientForm.validate((valid) => {
+        if (valid) {
+          this.savingPatientInfo = true;
+
+          // 鏇存柊userform鏁版嵁
+          const updatedUserform = {
+            ...this.userform,
+            name: this.patientForm.name,
+            sex: this.patientForm.sex,
+            age: this.patientForm.age,
+            telcode: this.patientForm.telcode,
+            placeOfResidence: this.patientForm.address,
+            medicalRecordNo: this.patientForm.hospitalNumber,
+          };
+
+          alterpatient(updatedUserform)
+            .then((res) => {
+              if (res.code == 200) {
+                this.$modal.msgSuccess("鎮h�呬俊鎭繚瀛樻垚鍔�");
+                this.userform = updatedUserform;
+              } else {
+                this.$modal.msgError("鎮h�呬俊鎭慨鏀瑰け璐�");
+              }
+              this.savingPatientInfo = false;
+            })
+            .catch((error) => {
+              console.error("淇濆瓨澶辫触:", error);
+              this.$modal.msgError("淇濆瓨澶辫触");
+              this.savingPatientInfo = false;
+            });
+        } else {
+          this.$modal.msgError("璇峰~鍐欏畬鏁翠俊鎭�");
+          return false;
+        }
+      });
+    },
+
+    // 閲嶇疆鎮h�呬俊鎭�
+    resetPatientInfo() {
+      this.initPatientForm();
+      this.$refs.patientForm.clearValidate();
+    },
+
+    // 鏃堕棿鏍煎紡鍖�
+    formatTime(time) {
+      if (!time) return "";
+      return time.split(" ")[0];
+    },
+
+    // 鏍煎紡鍖栨樉绀烘椂闂�
+    formatDisplayTime(time) {
+      if (!time) return "鏈缃�";
+      return time.replace(" ", " ");
+    },
+
+    // 寮傚父鍒楁覆鏌�
+    tableRowClassName({ row }) {
+      if (row.id == this.id) {
+        return "warning-row";
+      }
+      return "";
+    },
+  },
+};
+</script>
+<style lang="scss" scoped>
+.ContinuityCarePage {
+  margin: 10px;
+  display: flex;
+  flex-direction: column;
+  gap: 20px;
+}
+
+.headline {
+  font-size: 20px;
+  height: 40px;
+  border-left: 5px solid #41a1be;
+  padding-left: 10px;
+  margin-bottom: 20px;
+  display: flex;
+  align-items: center;
+  color: #333;
+  font-weight: 600;
+}
+
+.sub-headline {
+  font-size: 16px;
+  height: 36px;
+  padding-left: 8px;
+  margin-bottom: 15px;
+  display: flex;
+  align-items: center;
+  color: #409eff;
+  font-weight: 500;
+  border-bottom: 2px solid #e4e7ed;
+  padding-bottom: 8px;
+
+  i {
+    margin-right: 8px;
+    font-size: 18px;
+  }
+}
+
+/* 绗竴閮ㄥ垎锛氭湇鍔″熀纭�淇℃伅 */
+.basic-info-section {
+  margin: 0 10px;
+  padding: 20px;
+  background: #fff;
+  border: 1px solid #dcdfe6;
+  box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.12), 0 0 6px 0 rgba(0, 0, 0, 0.04);
+  border-radius: 4px;
+
+  .basic-info-container {
+    display: flex;
+    gap: 20px;
+    min-height: 1000px;
+
+    @media screen and (max-width: 1200px) {
+      flex-direction: column;
+    }
+  }
+
+  .followup-content {
+    flex: 1;
+    min-width: 0;
+
+    &.readonly-content {
+      background: #f8f9fa;
+      border-radius: 8px;
+      padding: 15px;
+      border: 1px solid #e4e7ed;
+    }
+
+    .content-container {
+      height: calc(1000px - 60px);
+      overflow: hidden;
+      display: flex;
+      flex-direction: column;
+
+      ::v-deep .el-tabs {
+        flex: 1;
+        display: flex;
+        flex-direction: column;
+
+        .el-tabs__content {
+          flex: 1;
+          overflow: hidden;
+
+          .el-tab-pane {
+            height: 100%;
+            overflow: hidden;
+            display: flex;
+            flex-direction: column;
+          }
+        }
+      }
+    }
+  }
+
+  .continuity-history {
+    flex: 1;
+    min-width: 0;
+    background: #fff;
+    border-radius: 8px;
+    padding: 15px;
+    border: 1px solid #e4e7ed;
+    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
+
+    .history-content {
+      height: calc(1000px - 60px);
+      overflow: hidden;
+      display: flex;
+      flex-direction: column;
+
+      ::v-deep .el-tabs {
+        flex: 1;
+        display: flex;
+        flex-direction: column;
+
+        .el-tabs__content {
+          flex: 1;
+          overflow-y: auto;
+          padding: 15px 0;
+
+          .continuity-form {
+            padding: 0 10px;
+
+            .el-form {
+              .selected-problems {
+                margin-top: 10px;
+                padding: 10px;
+                background: #f5f7fa;
+                border-radius: 4px;
+                border: 1px solid #e4e7ed;
+              }
+
+              .time-tip {
+                margin-top: 5px;
+                font-size: 12px;
+                color: #67c23a;
+                font-style: italic;
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+}
+
+.patient-info-section {
+  margin: 0 10px 20px 10px;
+  padding: 20px;
+  background: #fff;
+  border: 1px solid #dcdfe6;
+  box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.12), 0 0 6px 0 rgba(0, 0, 0, 0.04);
+  border-radius: 4px;
+
+  .patient-info-form {
+    .continuity-summary {
+      padding: 15px;
+      background: #ddf0f8;
+      border-radius: 8px;
+      border: 1px solid #b3e0f2;
+
+      .summary-item {
+        display: inline-block;
+        margin-right: 30px;
+        margin-bottom: 8px;
+
+        .label {
+          font-weight: 500;
+          color: #333;
+        }
+
+        .value {
+          color: #409eff;
+          font-weight: 500;
+        }
+      }
+    }
+  }
+}
+
+/* 鍏变韩鏍峰紡 */
+.CONTENT {
+  padding: 10px;
+  height: 100%;
+  display: flex;
+  flex-direction: column;
+
+  .title {
+    font-size: 18px;
+    font-weight: bold;
+    margin-bottom: 20px;
+    text-align: center;
+    color: #333;
+  }
+}
+
+.preview-left {
+  margin: 10px;
+  padding: 20px;
+  border: 1px solid #dcdfe6;
+  border-radius: 4px;
+  max-height: 800px;
+  overflow-y: auto;
+  background: #fff;
+  flex: 1;
+
+  .topic-dev {
+    margin-bottom: 20px;
+    font-size: 16px;
+
+    .dev-text {
+      margin-bottom: 10px;
+      font-weight: 500;
+      color: #333;
+    }
+  }
+}
+
+.scriptTopic-dev {
+  padding: 15px;
+  border-radius: 4px;
+  background: #fafafa;
+  border: 1px solid #e4e7ed;
+  margin-bottom: 15px;
+}
+
+.scriptTopic-isabnormal {
+  padding: 15px;
+  border-radius: 4px;
+  background: #fff5f5;
+  border: 1px solid #f56c6c;
+  color: #f56c6c;
+  margin-bottom: 15px;
+}
+
+.scriptTopic-warning {
+  padding: 15px;
+  border-radius: 4px;
+  background: #fff9e6;
+  border: 1px solid #e6a23c;
+  color: #e6a23c;
+  margin-bottom: 15px;
+}
+
+.red-star {
+  ::v-deep.el-radio__label {
+    position: relative;
+    padding-right: 10px;
+  }
+
+  ::v-deep.el-radio__label::after {
+    content: "*";
+    color: #f56c6c;
+    position: absolute;
+    right: -5px;
+    top: 0;
+  }
+}
+
+.yellow-star {
+  ::v-deep.el-radio__label {
+    position: relative;
+    padding-right: 10px;
+  }
+
+  ::v-deep.el-radio__label::after {
+    content: "*";
+    color: #e6a23c;
+    position: absolute;
+    right: -5px;
+    top: 0;
+    font-weight: bold;
+  }
+}
+
+.borderdiv {
+  height: 100%;
+  padding: 10px;
+  display: flex;
+  flex-direction: column;
+
+  .title {
+    font-size: 18px;
+    font-weight: bold;
+    margin-bottom: 20px;
+    text-align: center;
+  }
+
+  .voice-audio {
+    display: flex;
+    align-items: center;
+    color: #59a0f0;
+    margin-bottom: 20px;
+    padding: 10px;
+    background: #f5f7fa;
+    border-radius: 4px;
+  }
+
+  .preview-left {
+    flex: 1;
+    margin: 0;
+
+    .leftside {
+      margin: 15px 0;
+
+      span {
+        display: inline-block;
+        padding: 8px 12px;
+        background: #409eff;
+        color: #fff;
+        border-radius: 8px;
+        max-width: 80%;
+        margin-left: 10px;
+      }
+    }
+
+    .offside {
+      display: flex;
+      flex-direction: row-reverse;
+      margin: 15px 0;
+
+      .offside-value {
+        padding: 8px 12px;
+        background: #67c23a;
+        color: #fff;
+        border-radius: 8px;
+        max-width: 80%;
+        margin-right: 10px;
+      }
+    }
+  }
+}
+
+/* 鍝嶅簲寮忚璁� */
+@media (max-width: 768px) {
+  .ContinuityCarePage {
+    margin: 5px;
+    gap: 10px;
+  }
+
+  .basic-info-section,
+  .patient-info-section {
+    margin: 0 5px;
+    padding: 10px;
+  }
+
+  .basic-info-container {
+    gap: 10px !important;
+  }
+
+  .patient-info-form {
+    .el-row {
+      flex-direction: column;
+    }
+
+    .el-col {
+      width: 100% !important;
+      margin-bottom: 10px;
+    }
+  }
+
+  .preview-left {
+    margin: 5px;
+    padding: 10px;
+  }
+}
+/* 闂閫夋嫨鍣ㄩ潰鏉� */
+.question-selector-panel {
+  margin-bottom: 20px;
+  padding: 15px;
+  background: #f8f9fa;
+  border: 1px solid #e4e7ed;
+  border-radius: 8px;
+
+  .selector-header {
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+    margin-bottom: 15px;
+    padding-bottom: 10px;
+    border-bottom: 1px solid #e4e7ed;
+
+    span {
+      font-weight: 500;
+      color: #333;
+    }
+  }
+
+  .question-list {
+    max-height: 200px;
+    overflow-y: auto;
+    padding-right: 10px;
+
+    .question-item {
+      margin-bottom: 10px;
+      padding: 8px 12px;
+      background: #fff;
+      border-radius: 6px;
+      border: 1px solid #e4e7ed;
+      transition: all 0.3s;
+
+      &:hover {
+        border-color: #409eff;
+        background: #f0f7ff;
+      }
+
+      .question-content {
+        display: flex;
+        align-items: flex-start;
+
+        .question-index {
+          font-weight: 600;
+          color: #409eff;
+          min-width: 30px;
+        }
+
+        .question-text {
+          flex: 1;
+          line-height: 1.5;
+        }
+      }
+    }
+  }
+}
+
+/* 寤剁画闂琛ㄥ崟 */
+.continuity-problems-form {
+  .problems-header {
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+    margin-bottom: 15px;
+    padding-bottom: 10px;
+    border-bottom: 1px solid #e4e7ed;
+
+    span {
+      font-weight: 500;
+      color: #333;
+    }
+  }
+
+  .problems-list {
+    .problem-item {
+      margin-bottom: 20px;
+      padding: 15px;
+      background: #f8f9fa;
+      border-radius: 8px;
+      border: 1px solid #e4e7ed;
+
+      &:last-child {
+        margin-bottom: 0;
+      }
+
+      .problem-content {
+        .problem-meta {
+          display: flex;
+          align-items: center;
+          margin-bottom: 15px;
+          padding-bottom: 10px;
+          border-bottom: 1px dashed #e4e7ed;
+
+          .problem-index {
+            font-weight: 500;
+            color: #409eff;
+            min-width: 80px;
+          }
+        }
+
+        .problem-detail {
+          .detail-row {
+            display: flex;
+            align-items: flex-start;
+            margin-bottom: 10px;
+
+            &:last-child {
+              margin-bottom: 0;
+            }
+
+            .detail-label {
+              font-weight: 500;
+              color: #666;
+              min-width: 100px;
+              line-height: 32px;
+            }
+
+            .detail-value {
+              flex: 1;
+              line-height: 1.5;
+              color: #333;
+              padding: 5px 0;
+            }
+          }
+        }
+      }
+    }
+  }
+
+  .empty-problems {
+    text-align: center;
+    padding: 30px 0;
+    background: #fafafa;
+    border-radius: 8px;
+    border: 1px dashed #e4e7ed;
+  }
+}
+/* 寤剁画闂鍒楄〃瀹瑰櫒 - 娣诲姞婊氬姩 */
+.problems-list-container {
+  max-height: 400px; /* 鎺у埗鏈�澶ч珮搴� */
+  overflow-y: auto;
+  padding-right: 10px;
+  margin-bottom: 15px;
+
+  &::-webkit-scrollbar {
+    width: 6px;
+  }
+
+  &::-webkit-scrollbar-track {
+    background: #f1f1f1;
+    border-radius: 3px;
+  }
+
+  &::-webkit-scrollbar-thumb {
+    background: #c1c1c1;
+    border-radius: 3px;
+
+    &:hover {
+      background: #a8a8a8;
+    }
+  }
+}
+
+/* 闂嵎寮忛棶棰樺睍绀� */
+.question-display-area {
+  margin: 15px 0;
+  padding: 15px;
+  background: #fff;
+  border-radius: 8px;
+  border: 1px solid #e4e7ed;
+
+  .question-item-render {
+    .question-text {
+      margin-bottom: 15px;
+      font-size: 14px;
+      line-height: 1.5;
+      color: #333;
+
+      strong {
+        color: #409eff;
+        margin-right: 5px;
+      }
+
+      span {
+        color: #666;
+      }
+    }
+
+    .question-options {
+      margin-left: 20px;
+
+      .el-radio,
+      .el-checkbox {
+        display: block;
+        margin-bottom: 8px;
+        margin-right: 20px;
+      }
+    }
+
+    .append-input {
+      margin-left: 20px;
+      margin-top: 10px;
+    }
+  }
+
+  .no-question-data {
+    text-align: center;
+    color: #999;
+    padding: 20px;
+    font-style: italic;
+  }
+}
+
+/* 璋冩暣闂璇︽儏甯冨眬 */
+.problem-detail {
+  margin-top: 5px;
+  padding-top: 5px;
+  padding-bottom: 20px;
+  margin-bottom: 10px;
+  border-bottom: 1px dashed #6e9af4;
+
+  .detail-row {
+    display: flex;
+    align-items: center;
+    margin-bottom: 15px;
+
+    &:last-child {
+      margin-bottom: 0;
+    }
+
+    .detail-label {
+      font-weight: 500;
+      color: #666;
+      min-width: 80px;
+      white-space: nowrap;
+    }
+  }
+}
+
+/* 鍝嶅簲寮忚皟鏁� */
+@media (max-width: 768px) {
+  .problems-list-container {
+    max-height: 300px;
+  }
+
+  .problem-detail {
+    .detail-row {
+      flex-direction: column;
+      align-items: flex-start;
+
+      .detail-label {
+        margin-bottom: 5px;
+        min-width: auto;
+      }
+
+      .el-select,
+      .el-date-picker {
+        width: 100% !important;
+        margin: 5px 0 !important;
+      }
+    }
+  }
+}
+/* 鍝嶅簲寮忚皟鏁� */
+@media (max-width: 768px) {
+  .question-selector-panel {
+    padding: 10px;
+
+    .question-list {
+      .question-item {
+        padding: 6px 8px;
+      }
+    }
+  }
+
+  .continuity-problems-form {
+    .problems-list {
+      .problem-item {
+        padding: 10px;
+
+        .problem-content {
+          .problem-meta {
+            flex-direction: column;
+            align-items: flex-start;
+
+            .el-select {
+              width: 100% !important;
+              margin: 10px 0;
+            }
+          }
+
+          .problem-detail {
+            .detail-row {
+              flex-direction: column;
+              align-items: flex-start;
+
+              .detail-label {
+                margin-bottom: 5px;
+                min-width: auto;
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+}
+/* 婊氬姩鏉$編鍖� */
+.preview-left,
+.history-content .el-tabs__content,
+.content-container .el-tabs__content {
+  &::-webkit-scrollbar {
+    width: 6px;
+  }
+
+  &::-webkit-scrollbar-track {
+    background: #f1f1f1;
+    border-radius: 3px;
+  }
+
+  &::-webkit-scrollbar-thumb {
+    background: #c1c1c1;
+    border-radius: 3px;
+
+    &:hover {
+      background: #a8a8a8;
+    }
+  }
+}
+</style>
diff --git a/src/views/followvisit/Continue/index.vue b/src/views/followvisit/Continue/index.vue
new file mode 100644
index 0000000..7394444
--- /dev/null
+++ b/src/views/followvisit/Continue/index.vue
@@ -0,0 +1,2103 @@
+<template>
+  <div class="app-container">
+    <!-- <div class="leftvlue" style="margin-bottom: 20px">
+      <el-row :gutter="10">
+        <el-col :span="2.5" v-for="(item, index) in cardlist" :key="index">
+          <el-card
+            shadow="hover"
+            :body-style="item.router ? ' cursor: pointer' : 'cursor: default'"
+          >
+            <div style="padding: 8px" @click="$router.push(item.router)">
+              <span>{{ item.name }}</span>
+              <div
+                style="
+                  text-align: center;
+                  font-size: 18px;
+                  margin-top: 10px;
+                  font-weight: 600;
+                "
+              >
+                {{ item.value ? item.value : 0 }}
+              </div>
+            </div>
+          </el-card>
+        </el-col>
+        <el-col :span="2.5">
+          <div class="ysfleftvlue">
+            <el-card shadow="hover">
+              <div style="padding: 8px">
+                <span>琛ㄥ崟宸插彂閫�</span>
+                <div
+                  style="
+                    text-align: center;
+                    font-size: 18px;
+                    margin-top: 10px;
+                    font-weight: 600;
+                  "
+                >
+                  {{ yfsvalue }}
+                </div>
+              </div>
+            </el-card>
+          </div>
+        </el-col>
+        <el-col :span="2.5">
+          <div class="errleftvlue">
+            <el-card shadow="hover">
+              <div style="padding: 8px">
+                <span>寮傚父</span>
+                <div
+                  style="
+                    text-align: center;
+                    font-size: 18px;
+                    margin-top: 10px;
+                    font-weight: 600;
+                  "
+                >
+                  {{ ycvalue }}
+                </div>
+              </div>
+            </el-card>
+          </div>
+        </el-col>
+        <el-col :span="2.5" v-if="orgname == '鐪佺珛鍚屽痉缈犺嫅闄㈠尯'">
+          <div class="jgleftvlue">
+            <el-card shadow="hover ">
+              <div style="padding: 8px">
+                <span>璀﹀憡</span>
+                <div
+                  style="
+                    text-align: center;
+                    font-size: 18px;
+                    margin-top: 10px;
+                    font-weight: 600;
+                  "
+                >
+                  {{ jgvalue }}
+                </div>
+              </div>
+            </el-card>
+          </div>
+        </el-col>
+      </el-row>
+    </div> -->
+    <el-row :gutter="20">
+      <!--鐢ㄦ埛鏁版嵁-->
+      <el-form
+        :model="topqueryParams"
+        ref="queryForm"
+        size="small"
+        :inline="true"
+        v-show="showSearch"
+        label-width="98px"
+      >
+        <el-form-item label="浠诲姟鍚嶇О">
+          <el-input
+            v-model="topqueryParams.taskName"
+            placeholder="璇烽�夋嫨浠诲姟鍚嶇О"
+          ></el-input>
+        </el-form-item>
+
+        <el-form-item label="鍑洪櫌鏃堕棿">
+          <el-date-picker
+            v-model="dateRange"
+            style="width: 240px"
+            value-format="yyyy-MM-dd"
+            type="daterange"
+            range-separator="-"
+            start-placeholder="寮�濮嬫棩鏈�"
+            end-placeholder="缁撴潫鏃ユ湡"
+          ></el-date-picker>
+        </el-form-item>
+        <el-form-item label="搴旈殢璁挎椂闂�">
+          <el-date-picker
+            v-model="dateRangefs"
+            style="width: 240px"
+            value-format="yyyy-MM-dd"
+            type="daterange"
+            range-separator="-"
+            start-placeholder="寮�濮嬫棩鏈�"
+            end-placeholder="缁撴潫鏃ユ湡"
+          ></el-date-picker>
+        </el-form-item>
+
+        <el-form-item label="鎮h�呭鍚�" prop="sendname">
+          <el-input
+            v-model="topqueryParams.sendname"
+            placeholder="璇疯緭鍏ユ偅鑰呭鍚�"
+          ></el-input>
+        </el-form-item>
+        <el-form-item label="璇婃柇鍚嶇О" prop="leavediagname">
+          <el-input
+            v-model="topqueryParams.leavediagname"
+            placeholder="璇疯緭鍏ヨ瘖鏂悕绉�"
+          ></el-input>
+        </el-form-item>
+        <el-form-item label="闅忚浜哄憳" prop="updateBy">
+          <el-input
+            v-model="topqueryParams.updateBy"
+            placeholder="璇疯緭鍏ラ殢璁夸汉鍛�"
+          ></el-input>
+        </el-form-item>
+        <!-- <el-form-item label="涓绘不鍖荤敓" prop="drname">
+          <el-input
+            v-model="topqueryParams.drname"
+            placeholder="璇疯緭鍏ヤ富娌诲尰鐢�"
+          ></el-input>
+        </el-form-item> -->
+        <!-- <el-form-item label="缁忕鍖荤敓" prop="managementDoctor">
+          <el-input
+            v-model="topqueryParams.managementDoctor"
+            placeholder="璇疯緭鍏ヤ富娌诲尰鐢�"
+          ></el-input>
+        </el-form-item> -->
+        <!-- <el-form-item label="鏃ユ湡闄愬埗" prop="status">
+          <el-select v-model="endOut" placeholder="璇烽�夋嫨">
+            <el-option
+              v-for="item in endOuts"
+              :key="item.value"
+              :label="item.label"
+              :value="item.value"
+            >
+            </el-option>
+          </el-select>
+        </el-form-item> -->
+        <el-form-item label="鎮h�呰寖鍥�" prop="status">
+          <el-cascader
+            v-model="topqueryParams.scopetype"
+            placeholder="榛樿鍏ㄩ儴"
+            :options="sourcetype"
+            :props="{ expandTrigger: 'hover' }"
+            @change="handleChange"
+          ></el-cascader>
+        </el-form-item>
+
+        <el-form-item label="浠诲姟鐘舵��" prop="status">
+          <el-select v-model="topqueryParams.sendstate" placeholder="璇烽�夋嫨">
+            <el-option
+              v-for="item in topicoptions"
+              :key="item.value"
+              :label="item.label"
+              :value="item.value"
+            >
+            </el-option>
+          </el-select>
+        </el-form-item>
+        <!-- <el-form-item label="鎺掑簭鏂瑰紡" prop="status">
+          <el-select v-model="topqueryParams.sort" placeholder="璇烽�夋嫨">
+            <el-option
+              v-for="item in topicoptionssort"
+              :key="item.value"
+              :label="item.label"
+              :value="item.value"
+            >
+            </el-option>
+          </el-select>
+        </el-form-item> -->
+
+        <el-form-item>
+          <el-button
+            type="primary"
+            icon="el-icon-search"
+            size="medium"
+            @click="handleQuery(1)"
+            >鎼滅储</el-button
+          >
+          <el-button icon="el-icon-refresh" size="medium" @click="resetQuery"
+            >閲嶇疆</el-button
+          >
+        </el-form-item>
+      </el-form>
+      <el-divider></el-divider>
+      <el-row :gutter="10" class="mb8">
+        <el-col :span="1.5">
+          <div class="documentf">
+            <div class="document">
+              <el-button
+                type="warning"
+                plain
+                icon="el-icon-warning-outline"
+                size="medium"
+                @click="toleadExport(1)"
+                >鎵ц澶辫触</el-button
+              >
+            </div>
+          </div>
+        </el-col>
+        <el-col :span="1.5">
+          <div class="documentf">
+            <div class="document">
+              <el-button
+                type="danger"
+                plain
+                icon="el-icon-warning"
+                size="medium"
+                @click="toleadExport(2)"
+                >缁撴灉寮傚父</el-button
+              >
+            </div>
+          </div>
+        </el-col>
+      </el-row>
+      <el-table
+        v-loading="loading"
+        ref="userform"
+        :data="userList"
+        :row-class-name="tableRowClassName"
+        @selection-change="handleSelectionChange"
+      >
+        <el-table-column type="selection" width="50" align="center" />
+        <el-table-column
+          label="浠诲姟鍚嶇О"
+          fixed
+          width="150"
+          show-overflow-tooltip
+          align="center"
+          key="taskName"
+          prop="taskName"
+        />
+        <!-- <el-table-column label="搴忓彿" fixed align="center" key="id" prop="id" /> -->
+        <el-table-column
+          label="濮撳悕"
+          width="100"
+          align="center"
+          key="sendname"
+          prop="sendname"
+        >
+          <template slot-scope="scope">
+            <el-button
+              size="medium"
+              type="text"
+              @click="
+                gettoken360(scope.row.sfzh, scope.row.drcode, scope.row.drname)
+              "
+              ><span class="button-textsc">{{
+                scope.row.sendname
+              }}</span></el-button
+            >
+          </template>
+        </el-table-column>
+        <el-table-column
+          label="璇婃柇鍚嶇О"
+          align="center"
+          key="leavediagname"
+          prop="leavediagname"
+          width="120"
+          :show-overflow-tooltip="true"
+        >
+        </el-table-column>
+        <el-table-column
+          label="寤剁画鎶ょ悊娆℃暟"
+          align="center"
+          key="continueCount"
+          prop="continueCount"
+          width="120"
+          :show-overflow-tooltip="true"
+        >
+        </el-table-column>
+        <el-table-column
+          label="鏈�鏂板欢缁姢鐞嗘椂闂�"
+          sortable
+          align="center"
+          prop="finishtime"
+          width="160"
+        >
+          <template slot-scope="scope">
+            <span>{{ parseTime(scope.row.continueTimeNext) }}</span>
+          </template>
+        </el-table-column>
+        <el-table-column
+          label="涓嬫寤剁画鎶ょ悊鏃堕棿"
+          sortable
+          align="center"
+          prop="finishtime"
+          width="160"
+        >
+          <template slot-scope="scope">
+            <span>{{ parseTime(scope.row.continueTimeNow) }}</span>
+          </template>
+        </el-table-column>
+        <el-table-column
+          label="浠诲姟鐘舵��"
+          align="center"
+          key="sendstate"
+          prop="sendstate"
+          width="120"
+        >
+          <template slot-scope="scope">
+            <el-tooltip
+              class="item"
+              effect="dark"
+              :content="scope.row.remark"
+              placement="top-start"
+            >
+              <div v-if="scope.row.sendstate == 1">
+                <el-tag type="primary" :disable-transitions="false"
+                  >琛ㄥ崟宸查鍙�</el-tag
+                >
+              </div>
+              <div v-if="scope.row.sendstate == 2">
+                <el-tag type="primary" :disable-transitions="false"
+                  >寰呴殢璁�</el-tag
+                >
+              </div>
+              <div v-if="scope.row.sendstate == 3">
+                <el-tag type="success" :disable-transitions="false"
+                  >琛ㄥ崟宸插彂閫�</el-tag
+                >
+              </div>
+              <div v-if="scope.row.sendstate == 4">
+                <el-tag type="info" :disable-transitions="false">涓嶆墽琛�</el-tag>
+              </div>
+              <div v-if="scope.row.sendstate == 5">
+                <el-tag type="danger" :disable-transitions="false"
+                  >鍙戦�佸け璐�</el-tag
+                >
+              </div>
+            <div v-if="scope.row.sendstate == 6">
+                <el-tag type="success" :disable-transitions="false"
+                  >宸插畬鎴�</el-tag
+                >
+              </div>
+              <div v-if="scope.row.sendstate == 7">
+                <el-tag type="danger" :disable-transitions="false"
+                  >瓒呮椂</el-tag
+                >
+              </div>
+            </el-tooltip>
+          </template>
+        </el-table-column>
+        <!-- <el-table-column
+          label="浠诲姟寮傚父璇存槑"
+          width="120"
+          align="center"
+          key="remark"
+          prop="remark" -->
+        />
+
+        <el-table-column
+          label="澶勭悊鎰忚"
+          align="center"
+          key="suggest"
+          prop="suggest"
+          width="120"
+        >
+          <template slot-scope="scope">
+            <dict-tag
+              :options="dict.type.sys_suggest"
+              :value="scope.row.suggest"
+            />
+          </template>
+        </el-table-column>
+
+        <el-table-column
+          label="棣栨闅忚瀹屾垚鏃堕棿"
+          sortable
+          align="center"
+          prop="finishtime"
+          width="160"
+        >
+          <template slot-scope="scope">
+            <span>{{ parseTime(scope.row.finishtime) }}</span>
+          </template>
+        </el-table-column>
+        <el-table-column
+          label="鍑洪櫌鏃ユ湡"
+          width="200"
+          align="center"
+          key="endtime"
+          prop="endtime"
+        >
+          <template slot-scope="scope">
+            <span>{{ formatTime(scope.row.endtime) }}</span>
+          </template></el-table-column
+        >
+        <el-table-column
+          label="搴旈殢璁挎棩鏈�"
+          width="200"
+          align="center"
+          key="visitTime"
+          prop="visitTime"
+        >
+          <template slot-scope="scope">
+            <span>{{ formatTime(scope.row.visitTime) }}</span>
+          </template></el-table-column
+        >
+        <el-table-column
+          label="涓绘不鍖荤敓"
+          width="120"
+          align="center"
+          key="drname"
+          prop="drname"
+        />
+        <el-table-column
+          v-if="orgname != '涓芥按甯備腑鍖婚櫌'"
+          label="闅忚浜哄憳"
+          align="center"
+          key="updateBy"
+          prop="updateBy"
+          width="120"
+        />
+        <el-table-column
+          v-if="orgname != '涓芥按甯備腑鍖婚櫌'"
+          label="缁忕鍖荤敓"
+          align="center"
+          key="managementDoctor"
+          prop="managementDoctor"
+          width="120"
+        />
+        <el-table-column
+          label="鍑洪櫌澶╂暟"
+          width="120"
+          align="center"
+          key="endDay"
+          prop="endDay"
+        >
+          <template slot-scope="scope">
+            <span>{{ scope.row.endDay ? scope.row.endDay + "澶�" : "" }}</span>
+          </template>
+        </el-table-column>
+        <el-table-column
+          label="韬唤璇佸彿鐮�"
+          width="200"
+          align="center"
+          key="sfzh"
+          prop="sfzh"
+        />
+        <el-table-column
+          label="鑱旂郴鐢佃瘽"
+          width="200"
+          align="center"
+          key="phone"
+          prop="phone"
+        />
+        <el-table-column
+          label="璐d换鎶ゅ+"
+          width="120"
+          align="center"
+          key="nurseName"
+          prop="nurseName"
+        />
+
+        <el-table-column
+          label="绉戝"
+          align="center"
+          key="deptname"
+          prop="deptname"
+          width="120"
+        >
+        </el-table-column>
+        <el-table-column
+          label="鐥呭尯"
+          align="center"
+          key="leavehospitaldistrictname"
+          prop="leavehospitaldistrictname"
+          width="120"
+        >
+        </el-table-column>
+
+        <el-table-column
+          label="鍑洪櫌闅忚妯℃澘鍚嶇О"
+          align="center"
+          key="templatename"
+          prop="templatename"
+          width="200"
+        />
+        <el-table-column
+          label="浠诲姟鎵ц鏂瑰紡"
+          align="center"
+          key="preachform"
+          prop="preachform"
+          width="160"
+          :show-overflow-tooltip="true"
+        >
+          <template slot-scope="scope">
+            <span v-for="item in scope.row.preachform">{{ item }}銆� </span>
+          </template>
+        </el-table-column>
+        <!-- <el-table-column
+          label="浠诲姟鍙戦�佹祦绋�"
+          align="center"
+          key="serviceSubtaskRecordList"
+          prop="serviceSubtaskRecordList"
+          width="160"
+          :show-overflow-tooltip="true"
+        >
+          <template slot-scope="scope">
+            <span v-for="item in scope.row.serviceSubtaskRecordList"
+              >{{ item.remark }}銆�
+            </span>
+          </template>
+        </el-table-column> -->
+        <el-table-column
+          label="浠诲姟缁撴灉璇存槑"
+          width="220"
+          align="center"
+          key="remark"
+          prop="remark"
+        >
+          <template slot-scope="scope" v-if="scope.row.remark">
+            <el-tooltip
+              :content="scope.row.remark"
+              placement="top"
+              effect="dark"
+            >
+              <el-tag
+                type="warning"
+                v-if="scope.row.sendstate != 5 && scope.row.sendstate != 4"
+                >{{ scope.row.remark }}</el-tag
+              >
+              <el-tag type="warning" v-else>{{ scope.row.remark }}</el-tag>
+            </el-tooltip>
+          </template>
+        </el-table-column>
+        <el-table-column
+          label="鎿嶄綔"
+          align="center"
+          fixed="right"
+          width="120"
+          class-name="small-padding fixed-width"
+        >
+          <template slot-scope="scope">
+            <el-button size="medium" type="text" @click="Seedetails(scope.row)"
+              ><span class="button-zx"
+                ><i class="el-icon-s-order"></i>鏌ョ湅璇︽儏</span
+              ></el-button
+            >
+          </template>
+        </el-table-column>
+      </el-table>
+
+      <pagination
+        v-show="total > 0"
+        :total="total"
+        :page.sync="topqueryParams.pageNum"
+        :limit.sync="topqueryParams.pageSize"
+        @pagination="getList"
+      />
+    </el-row>
+    <!-- 婊℃剰搴﹀脊妗� -->
+    <el-dialog
+      title="闅忚婊℃剰搴﹁瘎鍒�"
+      :visible.sync="scoreDialogVisible"
+      width="80%"
+      :close-on-click-modal="false"
+    >
+      <el-table :data="selectedRows" border style="width: 100%">
+        <el-table-column
+          label="濮撳悕"
+          width="100"
+          align="center"
+          prop="sendname"
+        />
+        <el-table-column
+          label="浠诲姟鍚嶇О"
+          width="180"
+          align="center"
+          prop="taskName"
+        />
+        <!-- 鏂板璇勫垎鍒� -->
+        <el-table-column
+          label="鐪熷疄鎬�(20)"
+          align="center"
+          key="authenticity"
+          prop="authenticity"
+          width="150"
+        >
+          <template slot-scope="scope">
+            <el-input-number
+              v-model="scope.row.authenticity"
+              :min="0"
+              :max="20"
+              :step="1"
+              size="small"
+            />
+          </template>
+        </el-table-column>
+        <el-table-column
+          label="涓�鍛ㄥ唴瀹屾垚(20)"
+          align="center"
+          key="weekFinish"
+          prop="weekFinish"
+          width="150"
+        >
+          <template slot-scope="scope">
+            <el-input-number
+              v-model="scope.row.weekFinish"
+              :min="0"
+              :max="20"
+              :step="1"
+              size="small"
+            />
+          </template>
+        </el-table-column>
+        <el-table-column
+          label="瑙勮寖鎬�(10)"
+          align="center"
+          key="standard"
+          prop="standard"
+          width="150"
+        >
+          <template slot-scope="scope">
+            <el-input-number
+              v-model="scope.row.standard"
+              :min="0"
+              :max="10"
+              :step="1"
+              size="small"
+            />
+          </template>
+        </el-table-column>
+        <el-table-column
+          label="鍙婃椂鎬�(10)"
+          align="center"
+          key="timeliness"
+          prop="timeliness"
+          width="150"
+        >
+          <template slot-scope="scope">
+            <el-input-number
+              v-model="scope.row.timeliness"
+              :min="0"
+              :max="10"
+              :step="1"
+              size="small"
+            />
+          </template>
+        </el-table-column>
+        <el-table-column
+          label="瀹f暀鎯呭喌(10)"
+          align="center"
+          key="library"
+          prop="library"
+          width="150"
+        >
+          <template slot-scope="scope">
+            <el-input-number
+              v-model="scope.row.library"
+              :min="0"
+              :max="10"
+              :step="1"
+              size="small"
+            />
+          </template>
+        </el-table-column>
+        <el-table-column
+          label="鐜婊℃剰搴�(10)"
+          align="center"
+          key="environment"
+          prop="environment"
+          width="150"
+        >
+          <template slot-scope="scope">
+            <el-input-number
+              v-model="scope.row.environment"
+              :min="0"
+              :max="10"
+              :step="1"
+              size="small"
+            />
+          </template>
+        </el-table-column>
+        <el-table-column
+          label="鍖荤敓婊℃剰搴�(10)"
+          align="center"
+          key="doctorSatisfaction"
+          prop="doctorSatisfaction"
+          width="150"
+        >
+          <template slot-scope="scope">
+            <el-input-number
+              v-model="scope.row.doctorSatisfaction"
+              :min="0"
+              :max="10"
+              :step="1"
+              size="small"
+            />
+          </template>
+        </el-table-column>
+        <el-table-column
+          label="鎶ゅ+婊℃剰搴�(10)"
+          align="center"
+          key="nurseSatisfaction"
+          prop="nurseSatisfaction"
+          width="150"
+        >
+          <template slot-scope="scope">
+            <el-input-number
+              v-model="scope.row.nurseSatisfaction"
+              :min="0"
+              :max="10"
+              :step="1"
+              size="small"
+            />
+          </template>
+        </el-table-column>
+        <el-table-column
+          label="鎬诲垎"
+          align="center"
+          key="total"
+          prop="total"
+          fixed="right"
+        >
+          <template slot-scope="scope">
+            <span>{{ calculateTotal(scope.row) }}</span>
+          </template>
+        </el-table-column>
+      </el-table>
+
+      <div slot="footer" class="dialog-footer">
+        <el-button @click="scoreDialogVisible = false">鍙栨秷</el-button>
+        <el-button type="primary" @click="saveScores">淇濆瓨</el-button>
+      </div>
+    </el-dialog>
+    <!-- 娣诲姞鎴栦慨鏀瑰奖鍍忛殢璁垮璇濇 -->
+    <el-dialog
+      :title="amendtag ? '淇敼鎮h�呬俊鎭�' : '鏂板鎮h��'"
+      :visible.sync="Labelchange"
+      width="900px"
+    >
+      <el-form ref="form" :model="form" :rules="rules" label-width="100px">
+        <el-row>
+          <el-col :span="8">
+            <el-form-item label="濮撳悕" width="100" prop="name">
+              <el-input
+                v-model="form.name"
+                placeholder="璇疯緭鍏ュ鍚�"
+                maxlength="30"
+              />
+            </el-form-item>
+          </el-col>
+          <el-col :span="8">
+            <el-form-item label="鎬у埆" width="100" prop="sex">
+              <el-select v-model="form.sex" placeholder="璇烽�夋嫨鎬у埆">
+                <el-option
+                  v-for="dict in sextype"
+                  :key="dict.value"
+                  :label="dict.label"
+                  :value="dict.value"
+                ></el-option>
+              </el-select>
+            </el-form-item>
+          </el-col>
+          <el-col :span="8">
+            <el-form-item label="骞撮緞" prop="age">
+              <el-input
+                v-model="form.age"
+                placeholder="璇疯緭鍏ュ勾榫�"
+                maxlength="30"
+              />
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row>
+          <el-col :span="8">
+            <el-form-item label="杩囨护鍖荤敓" width="100" prop="filterDrname">
+              <el-input
+                v-model="form.filterDrname"
+                placeholder="璇疯緭鍏ュ尰鐢熷鍚�"
+                maxlength="30"
+              />
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row>
+          <el-col :span="24">
+            <el-form-item label="杩囨护鍘熷洜">
+              <el-input
+                v-model="form.notrequiredreason"
+                type="textarea"
+                placeholder="璇疯緭鍏ヨ繃婊ゅ師鍥�"
+              ></el-input>
+            </el-form-item>
+          </el-col>
+        </el-row>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="submitForm">纭� 瀹�</el-button>
+        <el-button @click="cancel">鍙� 娑�</el-button>
+      </div>
+    </el-dialog>
+    <!-- 淇敼鍙戦�佹椂闂村璇濇 -->
+    <el-dialog
+      title="鍙戦�佹椂闂磋缃�"
+      :visible.sync="modificationVisible"
+      width="45%"
+    >
+      <div style="margin-bottom: 20px; color: red">
+        缁熶竴淇敼褰撳ぉ鏈彂閫佺殑浠诲姟鏃堕棿
+      </div>
+
+      <el-form
+        :model="ruleForm"
+        :rules="rules"
+        ref="ruleForm"
+        label-width="120px"
+        class="demo-ruleForm"
+      >
+        <el-form-item label="鍙戦�佹棩鏈�">
+          <el-date-picker
+            v-model="ruleForm.value1"
+            type="date"
+            placeholder="閫夋嫨鏃ユ湡"
+          >
+          </el-date-picker>
+        </el-form-item>
+
+        <el-form-item label="鏃堕棿娈�" prop="type">
+          <el-checkbox-group v-model="ruleForm.type">
+            <el-checkbox label="涓婂崍" name="type"></el-checkbox>
+            <el-checkbox label="涓嬪崍" name="type"></el-checkbox>
+            <el-checkbox label="鏅氫笂" name="type"></el-checkbox>
+          </el-checkbox-group>
+        </el-form-item>
+        <el-form-item label="涓婂崍鏃堕棿鍖洪棿" required>
+          <el-time-picker
+            is-range
+            v-model="ruleForm.value2"
+            range-separator="鑷�"
+            start-placeholder="寮�濮嬫椂闂�"
+            end-placeholder="缁撴潫鏃堕棿"
+            placeholder="閫夋嫨鏃堕棿鑼冨洿"
+          >
+          </el-time-picker>
+        </el-form-item>
+        <el-form-item label="涓嬪崍鏃堕棿鍖洪棿" required>
+          <el-time-picker
+            is-range
+            v-model="ruleForm.value3"
+            range-separator="鑷�"
+            start-placeholder="寮�濮嬫椂闂�"
+            end-placeholder="缁撴潫鏃堕棿"
+            placeholder="閫夋嫨鏃堕棿鑼冨洿"
+          >
+          </el-time-picker>
+        </el-form-item>
+        <el-form-item label="鏅氫笂鏃堕棿鍖洪棿" required>
+          <el-time-picker
+            is-range
+            v-model="ruleForm.value4"
+            range-separator="鑷�"
+            start-placeholder="寮�濮嬫椂闂�"
+            end-placeholder="缁撴潫鏃堕棿"
+            placeholder="閫夋嫨鏃堕棿鑼冨洿"
+          >
+          </el-time-picker>
+        </el-form-item>
+      </el-form>
+
+      <span slot="footer" class="dialog-footer">
+        <el-button @click="modificationVisible = false">鍙� 娑�</el-button>
+        <el-button type="primary" @click="modificationVisible = false"
+          >纭� 瀹�</el-button
+        >
+      </span>
+    </el-dialog>
+    <!-- 鍐嶆闅忚 -->
+    <el-dialog title="鎮h�呭啀娆¢殢璁�" :visible.sync="dialogFormVisible">
+      <el-form ref="zcform" :rules="zcrules" :model="zcform" label-width="80px">
+        <el-form-item label="浠诲姟鍚嶇О">
+          <el-input
+            style="width: 400px"
+            disabled
+            v-model="zcform.taskName"
+          ></el-input>
+        </el-form-item>
+        <el-form-item label="鎮h�呭悕绉�">
+          <el-input
+            style="width: 400px"
+            disabled
+            v-model="zcform.sendname"
+          ></el-input>
+        </el-form-item>
+        <el-form-item label="骞撮緞">
+          <el-input
+            style="width: 400px"
+            disabled
+            v-model="zcform.age"
+          ></el-input>
+        </el-form-item>
+        <el-form-item label="绉戝">
+          <el-input
+            style="width: 400px"
+            disabled
+            v-model="zcform.deptname"
+          ></el-input>
+        </el-form-item>
+        <el-form-item label="鐥呭尯">
+          <el-input
+            style="width: 400px"
+            disabled
+            v-model="zcform.leavehospitaldistrictname"
+          ></el-input>
+        </el-form-item>
+
+        <el-form-item label="闅忚鏂瑰紡" prop="resource">
+          <el-radio-group v-model="zcform.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="鍑洪櫌鏃堕棿">
+          <el-input
+            style="width: 400px"
+            disabled
+            v-model="zcform.endtime"
+          ></el-input>
+        </el-form-item>
+        <el-form-item label="闅忚瀹屾垚鏃堕棿" prop="date1">
+          <el-date-picker
+            type="date"
+            placeholder="閫夋嫨鏃ユ湡"
+            v-model="zcform.date1"
+            style="width: 100%"
+          ></el-date-picker>
+        </el-form-item>
+        <el-form-item label="闅忚璁板綍">
+          <el-input type="textarea" v-model="zcform.remark"></el-input>
+        </el-form-item>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button @click="dialogFormVisible = false">鍙� 娑�</el-button>
+        <el-button type="primary" @click="setupsubtask">纭鍒涘缓鏈嶅姟</el-button>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import {
+  delUser,
+  addUser,
+  updateUser,
+  resetUserPwd,
+  changeUserStatus,
+} from "@/api/system/user";
+import {
+  getTaskservelist,
+  buidegetTasklist,
+  addserviceSubtask,
+  query360PatInfo,
+  addsatisfaction,
+} from "@/api/AiCentre/index";
+import { alterpatient, particularpatient } from "@/api/patient/homepage";
+import Treeselect from "@riophae/vue-treeselect";
+import store from "@/store";
+import "@riophae/vue-treeselect/dist/vue-treeselect.css";
+
+export default {
+  name: "Discharge",
+  dicts: ["sys_normal_disable", "sys_user_sex", "sys_yujing", "sys_suggest"],
+  components: { Treeselect },
+  data() {
+    return {
+      // 閬僵灞�
+      loading: true,
+      // 閫変腑鏁扮粍
+      ids: [],
+      // 闈炲崟涓鐢�
+      single: true,
+      // 闈炲涓鐢�
+      multiple: true,
+      // 鏄剧ず鎼滅储鏉′欢
+      showSearch: true,
+      dialogFormVisible: false,
+      // 鎬绘潯鏁�
+      total: 0,
+      // 鐢ㄦ埛琛ㄦ牸鏁版嵁
+      userList: null,
+      // 寮瑰嚭灞傛爣棰�
+      title: "鏂板褰卞儚闅忚",
+      // 鏄惁鏄剧ず淇敼銆佹坊鍔犲脊鍑哄眰
+      addalteropen: false,
+      // 淇敼鍙戦�佹椂闂村璇濇
+      modificationVisible: false,
+      // 閮ㄩ棬鍚嶇О
+      deptName: undefined,
+      // 榛樿瀵嗙爜
+      initPassword: undefined,
+      // 鏃ユ湡鑼冨洿
+      dateRange: [],
+      dateRangefs: [],
+      // 宀椾綅閫夐」
+      postOptions: [],
+      ruleForm: {
+        type: [],
+      },
+      zcform: {},
+      dynamicTags: ["閫夐」涓�", "閫夐」浜�", "閫夐」涓�"], //閫夐」
+      inputVisible: false,
+      Labelchange: false,
+      ycvalue: "",
+      jgvalue: "",
+      yfsvalue: "",
+      inputValue: "",
+      preachform: "",
+      previewVisible: false, //褰卞儚闅忚棰勮寮规
+      radio: "",
+      radios: [],
+      previewtype: 2, //棰勮褰卞儚闅忚绫诲瀷
+      total: 0, // 鎬绘潯鏁�
+      // 婊℃剰搴﹁皟鏌ユ暟鎹�
+      scoreDialogVisible: false,
+      selectedRows: [],
+
+      value: [],
+      list: [],
+
+      sourcetype: [
+        {
+          value: 1,
+          label: "绉戝",
+          children: [],
+        },
+        {
+          value: 2,
+          label: "鐥呭尯",
+          children: [],
+        },
+        {
+          value: 3,
+          label: "鍏ㄩ儴",
+        },
+      ],
+      loading: false,
+      cardlist: [
+        {
+          name: "鍑洪櫌鏈嶅姟鎬婚噺",
+          value: 0,
+        },
+        // {
+        //   name: "鎮h�呰繃婊�",
+        //   value: 0,
+        // },
+        {
+          name: "闇�闅忚",
+          value: 0,
+        },
+        {
+          name: "鍙戦�佸け璐�",
+          value: 0,
+        },
+        {
+          name: "寰呴殢璁�",
+          value: 0,
+        },
+        // {
+        //   name: "宸插彂閫�",
+        //   value: 0,
+        // },
+
+        // {
+        //   name: "琛ㄥ崟宸插彂閫�",
+        //   value: 0,
+        // },
+      ],
+      zcrules: {
+        date1: [
+          { required: true, message: "璇烽�夋嫨闅忚鏂瑰紡", trigger: "change" },
+        ],
+        resource: [
+          { required: true, message: "璇烽�夋嫨闅忚鏃堕棿", trigger: "blur" },
+        ],
+      },
+      // 琛ㄥ崟鍙傛暟
+      form: {
+        phonenumber: "",
+        totagid: "",
+        types: "",
+        nickName: "",
+        qystatus: "",
+        btstatus: "",
+      },
+      // endOut: 1,
+      endOut: localStorage.getItem("orgname") == "涓芥按甯備腑鍖婚櫌" ? 0 : 1, //0 鍑洪櫌鏃堕棿(姝e簭)    1 鍑洪櫌鏃堕棿(鍊掑簭)   2 鍙戦�佹椂闂�(姝e簭)    3 鍙戦�佹椂闂�(鍊掑簭)  7搴旈殢璁挎棩鏈�(鍊掑簭) 搴旈殢璁挎棩鏈�(姝e簭)
+      endOuts: [
+        {
+          value: 0,
+          label: "鎴鑷冲綋鏃ユ湇鍔�",
+        },
+        {
+          value: 1,
+          label: "鍏ㄩ儴鏈嶅姟",
+        },
+      ],
+      topicoptionssort: [
+        {
+          value: 0,
+          label: "鍑洪櫌鏃堕棿(姝e簭)",
+        },
+        {
+          value: 1,
+          label: "鍑洪櫌鏃堕棿(鍊掑簭)",
+        },
+        {
+          value: 2,
+          label: "鍙戦�佹椂闂�(姝e簭)",
+        },
+        {
+          value: 3,
+          label: "鍙戦�佹椂闂�(鍊掑簭)",
+        },
+        {
+          value: 7,
+          label: "搴旈殢璁挎棩鏈�(姝e簭)",
+        },
+        {
+          value: 8,
+          label: "搴旈殢璁挎棩鏈�(鍊掑簭)",
+        },
+      ],
+      // 鏌ヨ鍙傛暟
+      topqueryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        sort: localStorage.getItem("orgname") == "涓芥按甯備腑鍖婚櫌" ? 8 : 2, //0 鍑洪櫌鏃堕棿(姝e簭)    1 鍑洪櫌鏃堕棿(鍊掑簭)   2 鍙戦�佹椂闂�(姝e簭)    3 鍙戦�佹椂闂�(鍊掑簭)  7搴旈殢璁挎棩鏈�(鍊掑簭) 搴旈殢璁挎棩鏈�(姝e簭)
+        searchscope: 3,
+        continueFlag: 2,
+        visitCount: 1,
+        scopetype: [],
+        leaveldeptcodes: [],
+        leavehospitaldistrictcodes: [],
+      },
+      orgname: "",
+      propss: { multiple: true },
+      options: [],
+
+      topicoptions: [
+        {
+          value: null,
+          label: "鍏ㄩ儴",
+        },
+        {
+          value: 1,
+          label: "琛ㄥ崟宸查鍙�",
+        },
+        {
+          value: 2,
+          label: "寰呴殢璁�",
+        },
+        {
+          value: 3,
+          label: "琛ㄥ崟宸插彂閫�",
+        },
+        {
+          value: 4,
+          label: "涓嶆墽琛�",
+        },
+         {
+          value: 5,
+          label: "鍙戦�佸け璐�",
+        },
+        {
+          value: 6,
+          label: "宸插畬鎴�",
+        },
+         {
+          value: 7,
+          label: "瓒呮椂",
+        },
+      ],
+      sextype: [
+        {
+          value: 1,
+          label: "鐢�",
+        },
+        {
+          value: 2,
+          label: "濂�",
+        },
+      ],
+      topicoptionsyj: [
+        {
+          value: 1,
+          label: "寮傚父",
+        },
+        {
+          value: 2,
+          label: "璀﹀憡",
+        },
+        {
+          value: 0,
+          label: "姝e父",
+        },
+      ],
+      url: "http://9.208.2.190:8090/smartor/serviceExternal/query360PatInfo",
+      postData: {
+        XiaoXiTou: {
+          FaSongFCSJC: "ZJHES",
+          FaSongJGID: localStorage.getItem("orgid"),
+          FaSongJGMC: localStorage.getItem("orgname"),
+          FaSongSJ: "2025-01-09聽17:29:36",
+          FaSongXTJC: "SUIFANGXT",
+          FaSongXTMC: "闅忚绯荤粺",
+          XiaoXiID: "5FA92AFB-9833-4608-87C7-F56A654AC171",
+          XiaoXiLX: "SC_LC_360STCX",
+          XiaoXiMC: "360聽瑙嗗浘鏌ヨ",
+          ZuHuID: localStorage.getItem("ZuHuID"),
+          ZuHuMC: localStorage.getItem("orgname"),
+        },
+        YeWuXX: {
+          BingRenXX: {
+            ZhengJianHM: "",
+            ZhengJianLXDM: "01",
+            ZhengJianLXMC: "灞呮皯韬唤璇�",
+            ZuZhiJGID: localStorage.getItem("orgid"),
+            ZuZhiJGMC: localStorage.getItem("orgname"),
+          },
+          YongHuXX: {
+            XiTongID: "SUIFANGXT",
+            XiTongMC: "闅忚绯荤粺",
+            YongHuID: localStorage.getItem("YongHuID"),
+            YongHuXM: localStorage.getItem("YongHuXM"),
+            ZuZhiJGID: localStorage.getItem("orgid"),
+            ZuZhiJGMC: localStorage.getItem("orgname"),
+            idp: "lyra",
+          },
+        },
+      },
+      amendtag: false,
+      errtype: "",
+      leavehospitaldistrictcode: "",
+      serviceState: [],
+      checkboxlist: [],
+      // 琛ㄥ崟鏍¢獙
+      rules: {},
+    };
+  },
+  watch: {},
+  created() {
+    this.serviceState = store.getters.serviceState;
+    this.checkboxlist = store.getters.checkboxlist;
+    this.errtype = this.$route.query.errtype;
+    this.orgname = localStorage.getItem("orgname");
+    this.leavehospitaldistrictcode =
+      this.$route.query.leavehospitaldistrictcode;
+    this.sourcetype[0].children = store.getters.belongDepts.map((dept) => {
+      return {
+        label: dept.deptName,
+        value: dept.deptCode,
+      };
+    });
+    this.sourcetype[1].children = store.getters.belongWards.map((dept) => {
+      return {
+        label: dept.districtName,
+        value: dept.districtCode,
+      };
+    });
+    if (this.errtype) {
+      this.toleadExport(2);
+    } else {
+      this.getList(1);
+    }
+    this.getConfigKey("sys.user.initPassword").then((response) => {
+      this.initPassword = response.msg;
+    });
+  },
+  activated() {
+    this.getList(1);
+  },
+  methods: {
+    /** 鏌ヨ闅忚鏈嶅姟鍒楄〃 */
+    getList(refresh) {
+      // 榛樿鍏ㄩ儴
+      if (this.topqueryParams.searchscope == 3) {
+        this.topqueryParams.leaveldeptcodes = store.getters.belongDepts.map(
+          (obj) => obj.deptCode
+        );
+        this.topqueryParams.leavehospitaldistrictcodes =
+          store.getters.belongWards.map((obj) => obj.districtCode);
+      }
+      if (this.endOut == 0) {
+        this.topqueryParams.endSendDateTime = this.formatDateToYYYYMMDDHHMMSS(
+          this.getEndOfDay()
+        );
+      } else {
+        // this.topqueryParams.endSendDateTime = null;
+      }
+      // 鎺ュ彈寮傚父璺宠浆
+      if (this.errtype) {
+        this.topqueryParams.leavehospitaldistrictcodes.push(
+          this.leavehospitaldistrictcode
+        );
+        console.log(this.topqueryParams.leavehospitaldistrictcodes, "11");
+      }
+      this.loading = true;
+      if (
+        this.topqueryParams.leavehospitaldistrictcodes[0] &&
+        this.topqueryParams.leaveldeptcodes[0]
+      ) {
+        this.topqueryParams.deptOrDistrict = 2;
+      } else {
+        this.topqueryParams.deptOrDistrict = 1;
+      }
+      getTaskservelist(this.topqueryParams).then((response) => {
+        this.userList = response.rows[0].serviceSubtaskList;
+        this.total = response.total;
+        if (refresh) {
+          this.cardlist[0].value =
+            Number(response.rows[0].wzx) + Number(response.rows[0].ysf);
+          // this.cardlist[1].value = response.rows[0].wzx;
+          this.cardlist[1].value = response.rows[0].ysf;
+          this.ycvalue = response.rows[0].yc;
+          this.jgvalue = response.rows[0].jg;
+          this.cardlist[2].value = response.rows[0].fssb;
+          this.cardlist[3].value = response.rows[0].dsf;
+          // this.cardlist[4].value = response.rows[0].yfs2;
+          this.yfsvalue = response.rows[0].yfs;
+        }
+        this.loading = false;
+        this.userList.forEach((item) => {
+          let idArray = null;
+          if (item.endtime) {
+            item.endDay = this.daysBetween(item.endtime);
+          }
+
+          if (item.preachform) {
+            if (item.endtime) {
+              item.preachformson = item.preachform;
+              idArray = item.preachform.split(",");
+            }
+
+            item.preachform = idArray.map((value) => {
+              // 鏌ユ壘id瀵瑰簲鐨勫璞�
+              const item = this.checkboxlist.find(
+                (item) => item.value == value
+              );
+              // 濡傛灉鎵惧埌瀵瑰簲鐨刬d锛岃繑鍥瀕abel鍊硷紝鍚﹀垯杩斿洖null
+              return item ? item.label : null;
+            });
+          }
+        });
+        this.total = response.total;
+      });
+    },
+    // 鏃堕棿
+    getEndOfDay() {
+      const date = new Date(); // 鍒涘缓涓�涓〃绀哄綋鍓嶆椂闂寸殑Date瀵硅薄
+      date.setHours(23, 59, 59, 0); // 灏嗘椂闂磋缃负23:59:59.000
+      return date;
+    },
+    formatDateToYYYYMMDDHHMMSS(date) {
+      const year = date.getFullYear();
+      const month = String(date.getMonth() + 1).padStart(2, "0"); // 鏈堜唤琛ラ浂
+      const day = String(date.getDate()).padStart(2, "0"); // 鏃ユ湡琛ラ浂
+      const hours = String(date.getHours()).padStart(2, "0");
+      const minutes = String(date.getMinutes()).padStart(2, "0");
+      const seconds = String(date.getSeconds()).padStart(2, "0");
+
+      return `${year}-${month}-${day}`;
+    },
+    affiliation() {
+      this.topqueryParams.managementDoctorCode = store.getters.hisUserId;
+      this.getList(1);
+    },
+    onthatday() {
+      this.topqueryParams.startSendDateTime = this.getCurrentDate();
+      this.topqueryParams.endSendDateTime = this.getCurrentDate();
+      this.getList(1);
+    },
+    getCurrentDate() {
+      const now = new Date();
+      return now.toISOString().slice(0, 10); // 鎴彇鍓�10涓瓧绗︼紝鍗� YYYY-MM-DD
+    },
+    buidegetTasklist(type) {
+      if (this.topqueryParams.searchscope == 3) {
+        this.topqueryParams.leaveldeptcodes = store.getters.belongDepts.map(
+          (obj) => obj.deptCode
+        );
+        this.topqueryParams.leavehospitaldistrictcodes =
+          store.getters.belongWards.map((obj) => obj.districtCode);
+      }
+      // 鎺ュ彈寮傚父璺宠浆
+      if (this.errtype) {
+        this.topqueryParams.leavehospitaldistrictcodes.push(
+          this.leavehospitaldistrictcode
+        );
+      }
+      let obj = {
+        pageNum: 1,
+        pageSize: 10,
+        leavehospitaldistrictcodes:
+          this.topqueryParams.leavehospitaldistrictcodes,
+        sendstates: [2, 3],
+        leaveldeptcodes: this.topqueryParams.leaveldeptcodes,
+      };
+      buidegetTasklist(obj).then((response) => {
+        this.userList = response.rows[0].serviceSubtaskList;
+        this.total = response.total;
+        if (refresh) {
+          this.cardlist[0].value =
+            Number(response.rows[0].wzx) + Number(response.rows[0].ysf);
+          this.cardlist[1].value = response.rows[0].wzx;
+          this.cardlist[2].value = response.rows[0].ysf;
+          this.ycvalue = response.rows[0].yc;
+          this.jgvalue = response.rows[0].jg;
+          this.cardlist[3].value = response.rows[0].fssb;
+          this.cardlist[4].value = response.rows[0].dsf;
+          // this.cardlist[5].value = response.rows[0].yfs2;
+          this.yfsvalue = response.rows[0].yfs;
+        }
+        this.loading = false;
+        this.userList.forEach((item) => {
+          let idArray = null;
+          if (item.endtime) {
+            item.endDay = this.daysBetween(item.endtime);
+          }
+
+          if (item.preachform) {
+            if (item.endtime) {
+              item.preachformson = item.preachform;
+              idArray = item.preachform.split(",");
+            }
+
+            item.preachform = idArray.map((value) => {
+              // 鏌ユ壘id瀵瑰簲鐨勫璞�
+              const item = this.checkboxlist.find(
+                (item) => item.value == value
+              );
+              // 濡傛灉鎵惧埌瀵瑰簲鐨刬d锛岃繑鍥瀕abel鍊硷紝鍚﹀垯杩斿洖null
+              return item ? item.label : null;
+            });
+          }
+        });
+        this.total = response.total;
+      });
+    },
+    // 鏌ョ湅闂ㄨ瘖闅忚璇︽儏
+    Referencequestion(row) {
+      this.previewVisible = true;
+    },
+    // 娣诲姞寮规鎼滅储
+    remoteMethod(query) {
+      if (query !== "") {
+        this.loading = true;
+        setTimeout(() => {
+          this.loading = false;
+          this.options = this.list.filter((item) => {
+            return item.label.toLowerCase().indexOf(query.toLowerCase()) > -1;
+          });
+        }, 200);
+      } else {
+        this.options = [];
+      }
+    },
+    // 褰卞儚闅忚鐘舵�佷慨鏀�
+    handleStatusChange(row) {
+      let text = row.status === "0" ? "鍚敤" : "鍋滅敤";
+      this.$modal
+        .confirm('纭瑕�"' + text + '""' + row.userName + '"鐢ㄦ埛鍚楋紵')
+        .then(function () {
+          return changeUserStatus(row.userId, row.status);
+        })
+        .then(() => {
+          this.$modal.msgSuccess(text + "鎴愬姛");
+        })
+        .catch(function () {
+          row.status = row.status === "0" ? "1" : "0";
+        });
+    },
+
+    // 琛ㄥ崟閲嶇疆
+    reset() {
+      this.form = {
+        userId: undefined,
+        deptId: undefined,
+        userName: undefined,
+        nickName: undefined,
+        password: undefined,
+        phonenumber: undefined,
+        email: undefined,
+        sex: undefined,
+        status: "0",
+        remark: undefined,
+        postIds: [],
+        roleIds: [],
+      };
+      this.resetForm("form");
+    },
+    /** 鎼滅储鎸夐挳鎿嶄綔 */
+    handleQuery(refresh) {
+      if (this.topqueryParams.searchscope == 3) {
+        this.topqueryParams.leaveldeptcodes = store.getters.belongDepts.map(
+          (obj) => obj.deptCode
+        );
+        this.topqueryParams.leavehospitaldistrictcodes =
+          store.getters.belongWards.map((obj) => obj.districtCode);
+      }
+      this.topqueryParams.pageNum = 1;
+      this.topqueryParams.startOutHospTime = this.dateRange[0];
+      this.topqueryParams.endOutHospTime = this.dateRange[1];
+      this.topqueryParams.startSendDateTime = this.dateRangefs[0];
+      this.topqueryParams.endSendDateTime = this.dateRangefs[1];
+      this.getList(refresh);
+    },
+    // 鎮h�呰寖鍥村鐞�
+    handleChange(value) {
+      let type = value[0];
+      let code = value.slice(-1)[0];
+      this.topqueryParams.leavehospitaldistrictcodes = [];
+      this.topqueryParams.leaveldeptcodes = [];
+      if (type == 1) {
+        this.topqueryParams.leaveldeptcodes.push(code);
+        this.topqueryParams.leavehospitaldistrictcodes = [];
+        this.topqueryParams.searchscope = 1;
+      } else if (type == 2) {
+        this.topqueryParams.leavehospitaldistrictcodes.push(code);
+        this.topqueryParams.leaveldeptcodes = [];
+        this.topqueryParams.searchscope = 2;
+      } else {
+        this.topqueryParams.searchscope = 3;
+      }
+    },
+    /** 閲嶇疆鎸夐挳鎿嶄綔 */
+    resetQuery() {
+      this.dateRange = [];
+      this.dateRangefs = [];
+      this.topqueryParams = {
+        pageNum: 1,
+        pageSize: 10,
+        sort: 2, //0 鍑洪櫌鏃堕棿(姝e簭)    1 鍑洪櫌鏃堕棿(鍊掑簭)   2 鍙戦�佹椂闂�(姝e簭)    3 鍙戦�佹椂闂�(鍊掑簭)
+        searchscope: 3,
+        continueFlag: 2,
+        visitCount: 1,
+        scopetype: [],
+        leaveldeptcodes: [],
+        leavehospitaldistrictcodes: [],
+      };
+      this.handleQuery(1);
+    },
+    handleSelectionChange(rows) {
+      this.selectedRows = rows.map((row) => {
+        // 鍒濆鍖栬瘎鍒嗗瓧娈�
+        return {
+          ...row,
+          authenticity: row.authenticity || 0,
+          weekFinish: row.weekFinish || 0,
+          standard: row.standard || 0,
+          timeliness: row.timeliness || 0,
+          library: row.library || 0,
+          environment: row.environment || 0,
+          doctorSatisfaction: row.doctorSatisfaction || 0,
+          nurseSatisfaction: row.nurseSatisfaction || 0,
+        };
+      });
+
+      if (this.selectedRows.length > 0) {
+        this.multiple = false;
+      } else {
+        this.multiple = true;
+      }
+    },
+
+    // 璁$畻鎬诲垎
+    calculateTotal(row) {
+      return (
+        (row.authenticity || 0) +
+        (row.weekFinish || 0) +
+        (row.standard || 0) +
+        (row.timeliness || 0) +
+        (row.library || 0) +
+        (row.environment || 0) +
+        (row.doctorSatisfaction || 0) +
+        (row.nurseSatisfaction || 0)
+      );
+    },
+
+    // 淇濆瓨璇勫垎
+    saveScores() {
+      this.selectedRows.forEach((item) => {
+        item.createBy = null;
+        item.patName = item.sendname;
+        item.hospitaldistrictname = item.leavehospitaldistrictname;
+      });
+      addsatisfaction(this.selectedRows).then((res) => {
+        if (res.code == 200) {
+          this.$message.success("璇勫垎淇濆瓨鎴愬姛");
+          this.scoreDialogVisible = false;
+          this.selectedRows = [];
+          this.$refs.userform.clearSelection();
+        } else {
+          this.$modal.msgWarning("璇勫垎淇濆瓨澶辫触");
+          this.scoreDialogVisible = false;
+          this.selectedRows = [];
+          this.$refs.userform.clearSelection();
+        }
+      });
+      // 杩欓噷鍙互娣诲姞淇濆瓨閫昏緫锛屽璋冪敤API淇濆瓨璇勫垎
+    },
+    //鍒犻櫎閫夐」
+    handleClose(tag) {
+      this.dynamicTags.splice(this.dynamicTags.indexOf(tag), 1);
+    },
+    //瑙﹀彂鏂板杈撳叆
+    showInput() {
+      this.inputVisible = true;
+      this.$nextTick((_) => {
+        this.$refs.saveTagInput.$refs.input.focus();
+      });
+    },
+    //鑾峰彇澶卞幓鐒︾偣瑙﹀彂
+    handleInputConfirm() {
+      let inputValue = this.inputValue;
+      if (inputValue) {
+        this.dynamicTags.push(inputValue);
+      }
+      this.inputVisible = false;
+      this.inputValue = "";
+    },
+    /** 鏂板鎸夐挳鎿嶄綔 */
+    handleAdd() {
+      this.$router.push({
+        path: "/followvisit/QuestionnaireTask",
+        query: {
+          type: 2,
+          serviceType: 2,
+        },
+      });
+    },
+    //鎮h��360璺宠浆
+    gettoken360(sfzh, drcode, drname) {
+      // this.$modal.msgWarning("360鍔熻兘鏆傛湭寮�閫�");
+
+      this.postData.YeWuXX.BingRenXX.ZhengJianHM = sfzh;
+
+      query360PatInfo(this.postData).then((res) => {
+        if (res.data.url) {
+          window.open(res.data.url, "_blank");
+          // this.linkUrl = res.data.url;
+        } else {
+          this.$modal.msgWarning("360鏌ヨ鏃犵粨鏋�");
+        }
+      });
+    },
+
+    /** 閲嶇疆瀵嗙爜鎸夐挳鎿嶄綔 */
+    handleResetPwd(row) {
+      this.$prompt('璇疯緭鍏�"' + row.userName + '"鐨勬柊瀵嗙爜', "鎻愮ず", {
+        confirmButtonText: "纭畾",
+        cancelButtonText: "鍙栨秷",
+        closeOnClickModal: false,
+        inputPattern: /^.{5,20}$/,
+        inputErrorMessage: "鐢ㄦ埛瀵嗙爜闀垮害蹇呴』浠嬩簬 5 鍜� 20 涔嬮棿",
+      })
+        .then(({ value }) => {
+          resetUserPwd(row.userId, value).then((response) => {
+            this.$modal.msgSuccess("淇敼鎴愬姛锛屾柊瀵嗙爜鏄細" + value);
+          });
+        })
+        .catch(() => {});
+    },
+    // 鍙栨秷鎸夐挳
+    cancel() {
+      this.Labelchange = false;
+      this.reset();
+    },
+    /** 鎻愪氦鎸夐挳 */
+    submitForm: function () {
+      this.$refs["form"].validate((valid) => {
+        if (valid) {
+          this.form.isoperation = 2;
+          this.form.notrequiredFlag = 1;
+          alterpatient(this.form)
+            .then((response) => {
+              console.log(response);
+            })
+            .then(() => {
+              this.getList(1);
+              this.$modal.msgSuccess("鎮h�呰繃婊ゆ垚鍔�");
+            });
+
+          this.reset();
+          this.Labelchange = false;
+        }
+      });
+    },
+    /** 鍒犻櫎鎸夐挳鎿嶄綔 */
+    handleDelete(row) {
+      const userIds = row.userId || this.ids;
+      this.$modal
+        .confirm('鏄惁纭鍒犻櫎鐢ㄦ埛缂栧彿涓�"' + userIds + '"鐨勬暟鎹」锛�')
+        .then(function () {
+          return delUser(userIds);
+        })
+        .then(() => {
+          this.getList(1);
+          this.$modal.msgSuccess("鍒犻櫎鎴愬姛");
+        })
+        .catch(() => {});
+    },
+    // 鍏ㄩ儴鍋滄
+    AllStop() {
+      this.$modal
+        .confirm("鏄惁鍋滄鍏ㄩ儴浠诲姟锛�")
+        .then(function () {
+          return console.log("鍋滄鎴愬姛");
+        })
+        .then(() => {
+          this.getList(1);
+          this.$modal.msgWarning("鍋滄鎴愬姛");
+        })
+        .catch(() => {});
+    },
+    // 鍏ㄩ儴寮�濮�
+    AllStarted() {
+      this.$modal
+        .confirm("鏄惁寮�鍚叏閮ㄤ换鍔★紵")
+        .then(function () {
+          return console.log("寮�鍚垚鍔�");
+        })
+        .then(() => {
+          this.getList(1);
+          this.$modal.msgSuccess("寮�鍚垚鍔�");
+        })
+        .catch(() => {});
+    },
+    // 浠诲姟閲嶇疆
+    TaskReset() {
+      this.$modal
+        .confirm("鏄惁閲嶇疆閫変腑鐨勪换鍔¢」锛�")
+        .then(function () {
+          return console.log("閫変腑鎴愬姛");
+        })
+        .then(() => {
+          this.getList(1);
+          this.$modal.msgSuccess("閲嶇疆鎴愬姛");
+        })
+        .catch(() => {});
+    },
+    // 璁剧疆鍙戦�佹椂闂�
+    Sendtimesetting() {
+      this.modificationVisible = true;
+    },
+    // 璺宠浆璇︽儏椤�
+    Seedetails(row) {
+      let type = "";
+      console.log(row, "rwo");
+      if (row.type == 1) {
+        type = 1;
+      }
+      this.$router.push({
+        path: "/followvisit/ContinueFordetails/",
+        query: {
+          taskid: row.taskid,
+          patid: row.patid,
+          id: row.id,
+          Voicetype: type,
+          visitCount: this.topqueryParams.visitCount,
+        },
+      });
+    },
+    // 鍐嶆闅忚
+    followupvisit(row) {
+      this.zcform = row;
+      this.zcform.endtime = this.formatTime(this.zcform.endtime);
+      this.dialogFormVisible = true;
+    },
+    onSubmit() {},
+    // 鏆傚仠鏈嶅姟
+    handlestop(row) {
+      let objson = row;
+      this.$modal
+        .confirm(
+          '鏄惁纭鏆傚仠浠诲姟鍚嶇О涓�"' +
+            row.taskName +
+            '鎮h�呭悕绉颁负"' +
+            row.sendname +
+            '"鐨勬暟鎹」锛�'
+        )
+        .then(() => {
+          getTaskservelist({
+            patid: row.patid,
+            taskid: row.taskid,
+          }).then((res) => {
+            if (res.code == 200) {
+              objson.sendstate = 4;
+              objson.remark = "鏈嶅姟鏆傚仠";
+              Editsingletaskson(objson).then((res) => {
+                if (res.code) {
+                  this.$modal.msgSuccess("璁板綍鎴愬姛");
+                  this.getList(1);
+                }
+              });
+            }
+          });
+        })
+        .catch(() => {});
+    },
+    // 鎮h�呰繃婊よЕ鍙�
+    handleUpdate(row) {
+      particularpatient(row.patid).then((response) => {
+        this.form = response.data;
+        this.form.filterDrname = store.getters.nickName;
+      });
+      this.amendtag = true;
+      this.Labelchange = true;
+    },
+    // 渚挎嵎鎸夐挳
+    toleadExport(too) {
+      if (too == 1) {
+        this.topqueryParams.sendstate = 4;
+        this.topqueryParams.excep = null;
+      } else if (too == 2) {
+        this.topqueryParams.excep = 1;
+      }
+      this.handleQuery();
+    },
+    /** 瀵煎嚭鎸夐挳鎿嶄綔 */
+    handleExport() {
+      this.topqueryParams.pageNum = null;
+      this.topqueryParams.pageSize = null;
+      this.download(
+        "smartor/serviceSubtask/patItemExport",
+        {
+          ...this.topqueryParams,
+        },
+        `user_${new Date().getTime()}.xlsx`
+      );
+    },
+    // 寮傚父鍒楁覆鏌�
+    tableRowClassName({ row, rowIndex }) {
+      if (row.excep == 1) {
+        return "warning-row";
+      } else if (row.excep == 2) {
+        return "remind-row";
+      }
+      return "";
+    },
+    // 鍒涘缓鍐嶆闅忚鏈嶅姟
+    setupsubtask() {
+      this.$refs["zcform"].validate((valid) => {
+        if (valid) {
+          this.zcform.remark =
+            this.zcform.remark + "銆�" + this.getCurrentTime() + "銆�";
+          let form = structuredClone(this.zcform);
+          form.visitTime = this.formatTime(form.date1);
+          form.finishtime = "";
+          if (form.resource) {
+            if (form.resource == 2) {
+              form.serviceType = 13;
+            }
+          } else {
+            this.$modal.msgError("鏈�夋嫨闅忚鏂瑰紡");
+          }
+          form.id = null;
+          form.sendstate = 2;
+          form.preachform = form.preachformson;
+          form.longTask = 0;
+          addserviceSubtask(form).then((res) => {
+            if (res.code == 200) {
+              this.$modal.msgSuccess("鍒涘缓鎴愬姛");
+            } else {
+              this.$modal.msgError("鍒涘缓澶辫触");
+            }
+            this.dialogFormVisible = false;
+          });
+        }
+      });
+    },
+    getCurrentTime() {
+      const now = new Date();
+      const year = now.getFullYear();
+      const month = String(now.getMonth() + 1).padStart(2, "0");
+      const day = String(now.getDate()).padStart(2, "0");
+      const hours = String(now.getHours()).padStart(2, "0");
+      const minutes = String(now.getMinutes()).padStart(2, "0");
+      const seconds = String(now.getSeconds()).padStart(2, "0");
+
+      return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
+    },
+  },
+};
+</script>
+
+<style lang="scss" scoped>
+.el-button--primary.is-plain {
+  color: #ffffff;
+  background: #409eff;
+  border-color: #4fabe9;
+}
+
+.document {
+  // width: 100px;
+  height: 50px;
+}
+::v-deep.el-table .warning-row {
+  background: #eec4c4;
+}
+::v-deep.el-table .remind-row {
+  background: #fcf5aa;
+}
+
+.documentf {
+  display: flex;
+  justify-content: flex-end;
+}
+
+.download {
+  text-align: center;
+
+  .el-upload__tip {
+    font-size: 23px;
+  }
+
+  .el-upload__text {
+    font-size: 23px;
+  }
+}
+
+.uploading {
+  margin-top: 20px;
+  margin: 20px;
+  padding: 30px;
+  background: #ffffff;
+  border: 1px solid #dcdfe6;
+  -webkit-box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.12),
+    0 0 6px 0 rgba(0, 0, 0, 0.04);
+}
+
+.el-tag + .el-tag {
+  margin-left: 10px;
+}
+
+.button-new-tag {
+  margin-left: 10px;
+  height: 32px;
+  line-height: 30px;
+  padding-top: 0;
+  padding-bottom: 0;
+}
+
+.input-new-tag {
+  width: 90px;
+  margin-left: 10px;
+  vertical-align: bottom;
+}
+
+.drexamine {
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  padding: 30px;
+  background: #daeaf5;
+
+  img {
+    width: 100px;
+    height: 100px;
+  }
+}
+
+.qrcode-dialo {
+  // text-align: center;
+  //   display: flex;
+  margin: 20px;
+  padding: 30px;
+  background: #edf1f7;
+  border: 1px solid #dcdfe6;
+  -webkit-box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.12),
+    0 0 6px 0 rgba(0, 0, 0, 0.04);
+
+  .topic-dev {
+    margin-bottom: 25px;
+    font-size: 20px !important;
+
+    .dev-text {
+      margin-bottom: 10px;
+    }
+  }
+}
+::v-deep.leftvlue .el-card__body {
+  background: #f2f8ff;
+  color: #324a9b;
+}
+::v-deep.leftvlue .el-card__body:hover {
+  background: #3664d9;
+  color: #fff;
+  cursor: pointer; /* 榧犳爣鎮诞鏃跺彉涓烘墜褰� */
+}
+::v-deep.errleftvlue .el-card__body {
+  background: #fdd0d7;
+}
+::v-deep.errleftvlue .el-card__body:hover {
+  background: #f88d96;
+  cursor: pointer; /* 榧犳爣鎮诞鏃跺彉涓烘墜褰� */
+}
+::v-deep.jgleftvlue .el-card__body:hover {
+  background: #f7f075;
+  cursor: pointer; /* 榧犳爣鎮诞鏃跺彉涓烘墜褰� */
+}
+
+::v-deep.ysfleftvlue .el-card__body {
+  background: #d0fdd8;
+}
+::v-deep.ysfleftvlue .el-card__body:hover {
+  background: #0abc54;
+  cursor: pointer; /* 榧犳爣鎮诞鏃跺彉涓烘墜褰� */
+}
+.button-bb {
+  font-weight: 500;
+  background-color: #2ba05c;
+  padding: 5px;
+  border-radius: 1px;
+  color: #ffffff;
+}
+.button-xq {
+  font-weight: 500;
+  background-color: #409eff;
+  padding: 5px;
+  border-radius: 1px;
+  color: #ffffff;
+}
+.button-sc {
+  font-weight: 500;
+  background-color: #b3a21f;
+  padding: 5px;
+  border-radius: 1px;
+  color: #ffffff;
+}
+.button-zx {
+  background: #324a9b;
+  padding: 5px;
+  border-radius: 1px;
+  color: #ffffff;
+}
+
+::v-deep.el-radio-group {
+  span {
+    font-size: 24px;
+  }
+}
+.purple-button {
+  background-color: #7e22ce;
+  border-color: #7e22ce;
+  color: #fff;
+}
+
+.purple-button:hover,
+.purple-button:focus {
+  background-color: #9333ea;
+  border-color: #9333ea;
+}
+
+.purple-button:active {
+  background-color: #6b21a8;
+  border-color: #6b21a8;
+}
+.button-textxga {
+  color: #de7897;
+}
+.purple-button.is-disabled {
+  background-color: #d8b4fe;
+  border-color: #d8b4fe;
+  opacity: 1; /* 淇濇寔绂佺敤鐘舵�侀�忔槑搴� */
+}
+// 閫夐」瀛椾綋鏀惧ぇ
+// ::v-deep.el-checkbox-group {
+//   span {
+//     font-size: 24px;
+//   }
+// }
+</style>
diff --git a/src/views/followvisit/HistoricalFollow/index.vue b/src/views/followvisit/HistoricalFollow/index.vue
new file mode 100644
index 0000000..4b5b99a
--- /dev/null
+++ b/src/views/followvisit/HistoricalFollow/index.vue
@@ -0,0 +1,1327 @@
+<template>
+  <!-- 鍘嗗彶闅忚璁板綍 -->
+  <div class="app-container">
+    <div class="leftvlue" style="margin-bottom: 20px"></div>
+    <el-row :gutter="20">
+      <!--鐢ㄦ埛鏁版嵁-->
+      <el-form
+        :model="topqueryParams"
+        ref="queryForm"
+        size="small"
+        :inline="true"
+        v-show="showSearch"
+        label-width="98px"
+      >
+        <el-form-item label="浠诲姟鍚嶇О">
+          <el-input
+            v-model="topqueryParams.taskName"
+            placeholder="璇烽�夋嫨浠诲姟鍚嶇О"
+          ></el-input>
+        </el-form-item>
+
+        <el-form-item label="鎮h�呭鍚�" prop="sendname">
+          <el-input
+            v-model="topqueryParams.sendname"
+            placeholder="璇疯緭鍏ユ偅鑰呭鍚�"
+          ></el-input>
+        </el-form-item>
+        <el-form-item label="璇婃柇鍚嶇О" prop="leavediagname">
+          <el-input
+            v-model="topqueryParams.leavediagname"
+            placeholder="璇疯緭鍏ヨ瘖鏂悕绉�"
+          ></el-input>
+        </el-form-item>
+        <el-form-item label="浠诲姟鐘舵��" prop="status">
+          <el-select v-model="topqueryParams.sendstate" placeholder="璇烽�夋嫨">
+            <el-option
+              v-for="item in topicoptions"
+              :key="item.value"
+              :label="item.label"
+              :value="item.value"
+            >
+            </el-option>
+          </el-select>
+        </el-form-item>
+
+        <el-form-item>
+          <el-button
+            type="primary"
+            icon="el-icon-search"
+            size="medium"
+            @click="handleQuery(1)"
+            >鎼滅储</el-button
+          >
+          <el-button icon="el-icon-refresh" size="medium" @click="resetQuery"
+            >閲嶇疆</el-button
+          >
+        </el-form-item>
+      </el-form>
+      <el-divider></el-divider>
+      <el-row :gutter="10" class="mb8">
+        <el-col :span="1.5">
+          <div class="documentf">
+            <div class="document">
+              <el-button
+                type="warning"
+                plain
+                icon="el-icon-upload2"
+                size="medium"
+                @click="handleExport"
+                >瀵煎嚭</el-button
+              >
+            </div>
+          </div>
+        </el-col>
+      </el-row>
+      <el-table
+        v-loading="loading"
+        :data="userList"
+        :row-class-name="tableRowClassName"
+        @selection-change="handleSelectionChange"
+      >
+        <el-table-column type="selection" width="50" align="center" />
+        <el-table-column
+          label="浠诲姟鍚嶇О"
+          fixed
+          align="center"
+          key="taskName"
+          prop="taskName"
+          width="180"
+        />
+        <!-- <el-table-column label="搴忓彿" fixed align="center" key="id" prop="id" /> -->
+        <el-table-column
+          label="濮撳悕"
+          width="100"
+          align="center"
+          key="sendname"
+          prop="sendname"
+        >
+          <template slot-scope="scope">
+            <el-button
+              size="medium"
+              type="text"
+              @click="
+                gettoken360(scope.row.sfzh, scope.row.drcode, scope.row.drname)
+              "
+              ><span class="button-textsc">{{
+                scope.row.sendname
+              }}</span></el-button
+            >
+          </template>
+        </el-table-column>
+        <el-table-column
+          label="浠诲姟鐘舵��"
+          align="center"
+          key="sendstate"
+          prop="sendstate"
+          width="120"
+        >
+          <template slot-scope="scope">
+            <el-tooltip
+              class="item"
+              effect="dark"
+              :content="scope.row.remark"
+              placement="top-start"
+            >
+              <div v-if="scope.row.sendstate == 1">
+                <el-tag type="primary" :disable-transitions="false"
+                  >琛ㄥ崟宸查鍙�</el-tag
+                >
+              </div>
+              <div v-if="scope.row.sendstate == 2">
+                <el-tag type="primary" :disable-transitions="false"
+                  >寰呴殢璁�</el-tag
+                >
+              </div>
+              <div v-if="scope.row.sendstate == 3">
+                <el-tag type="success" :disable-transitions="false"
+                  >琛ㄥ崟宸插彂閫�</el-tag
+                >
+              </div>
+              <div v-if="scope.row.sendstate == 4">
+                <el-tag type="info" :disable-transitions="false">涓嶆墽琛�</el-tag>
+              </div>
+              <div v-if="scope.row.sendstate == 5">
+                <el-tag type="danger" :disable-transitions="false"
+                  >鍙戦�佸け璐�</el-tag
+                >
+              </div>
+              <div v-if="scope.row.sendstate == 6">
+                <el-tag type="danger" :disable-transitions="false"
+                  >宸插畬鎴�</el-tag
+                >
+              </div>
+            </el-tooltip>
+          </template>
+        </el-table-column>
+        <el-table-column
+          label="璇婃柇鍚嶇О"
+          align="center"
+          key="leavediagname"
+          prop="leavediagname"
+          width="120"
+          :show-overflow-tooltip="true"
+        >
+        </el-table-column>
+
+        <el-table-column
+          label="澶勭悊鎰忚"
+          align="center"
+          key="suggest"
+          prop="suggest"
+          width="120"
+        >
+          <template slot-scope="scope">
+            <dict-tag
+              :options="dict.type.sys_suggest"
+              :value="scope.row.suggest"
+            />
+          </template>
+        </el-table-column>
+        <el-table-column
+          label="闅忚浜哄憳"
+          align="center"
+          key="updateBy"
+          prop="updateBy"
+          width="120"
+        />
+        <el-table-column
+          label="闅忚瀹屾垚鏃堕棿"
+          sortable
+          align="center"
+          prop="finishtime"
+          width="160"
+        >
+          <template slot-scope="scope">
+            <span>{{ parseTime(scope.row.finishtime) }}</span>
+          </template>
+        </el-table-column>
+
+        <el-table-column
+          label="搴旈殢璁挎棩鏈�"
+          width="200"
+          align="center"
+          key="visitTime"
+          prop="visitTime"
+        >
+          <template slot-scope="scope">
+            <span>{{ formatTime(scope.row.visitTime) }}</span>
+          </template></el-table-column
+        >
+        <el-table-column
+          label="鍑洪櫌鏃ユ湡"
+          width="200"
+          align="center"
+          key="endtime"
+          prop="endtime"
+        >
+          <template slot-scope="scope">
+            <span>{{ formatTime(scope.row.endtime) }}</span>
+          </template></el-table-column
+        >
+        <el-table-column
+          label="鍑洪櫌澶╂暟"
+          width="120"
+          align="center"
+          key="endDay"
+          prop="endDay"
+        >
+          <template slot-scope="scope">
+            <span>{{ scope.row.endDay ? scope.row.endDay + "澶�" : "" }}</span>
+          </template>
+        </el-table-column>
+        <el-table-column
+          label="韬唤璇佸彿鐮�"
+          width="200"
+          align="center"
+          key="sfzh"
+          prop="sfzh"
+        />
+        <el-table-column
+          label="鑱旂郴鐢佃瘽"
+          width="200"
+          align="center"
+          key="phone"
+          prop="phone"
+        />
+        <el-table-column
+          label="璐d换鎶ゅ+"
+          width="120"
+          align="center"
+          key="nurseName"
+          prop="nurseName"
+        />
+        <el-table-column
+          label="涓绘不鍖荤敓"
+          width="120"
+          align="center"
+          key="drname"
+          prop="drname"
+        />
+
+        <!-- <el-table-column
+          label="鐥呭巻鍙�"
+          align="center"
+          sortable
+          key="medicalRecordNo"
+          prop="medicalRecordNo"
+          width="120"
+        /> -->
+
+        <!-- <el-table-column label="骞撮緞" align="center" key="age" prop="age" /> -->
+        <!-- <el-table-column label="鎬у埆"width="100" align="center" key="sex" prop="sex" /> -->
+        <!-- <el-table-column label="搴婂彿" align="center" key="badNo" prop="badNo" /> -->
+        <el-table-column
+          label="绉戝"
+          align="center"
+          key="deptname"
+          prop="deptname"
+          width="120"
+        >
+        </el-table-column>
+        <el-table-column
+          label="鐥呭尯"
+          align="center"
+          key="leavehospitaldistrictname"
+          prop="leavehospitaldistrictname"
+          width="120"
+        >
+        </el-table-column>
+
+        <!-- <el-table-column
+          label="鐤剧梾鍚嶇О"
+          align="center"
+          key="icdName"
+          prop="icdName"
+          width="120"
+          :show-overflow-tooltip="true"
+        >
+        </el-table-column> -->
+
+        <el-table-column
+          label="鍑洪櫌闅忚妯℃澘鍚嶇О"
+          align="center"
+          key="templatename"
+          prop="templatename"
+          width="200"
+        />
+        <el-table-column
+          label="浠诲姟鎵ц鏂瑰紡"
+          align="center"
+          key="preachform"
+          prop="preachform"
+          width="160"
+          :show-overflow-tooltip="true"
+        >
+          <template slot-scope="scope">
+            <span v-for="item in scope.row.preachform">{{ item }}銆� </span>
+          </template>
+        </el-table-column>
+        <el-table-column
+          label="浠诲姟缁撴灉璇存槑"
+          width="200"
+          align="center"
+          key="remark"
+          prop="remark"
+        >
+          <template slot-scope="scope" v-if="scope.row.remark">
+            <el-tag
+              type="warning"
+              v-if="scope.row.sendstate != 5 && scope.row.sendstate != 4"
+              >{{ scope.row.remark }}</el-tag
+            >
+            <el-tag type="warning" v-else>{{ scope.row.remark }}</el-tag>
+          </template>
+        </el-table-column>
+        <el-table-column
+          label="鎿嶄綔"
+          align="center"
+          fixed="right"
+          width="200"
+          class-name="small-padding fixed-width"
+        >
+          <template slot-scope="scope">
+            <el-button size="medium" type="text" @click="Seedetails(scope.row)"
+              ><span class="button-zx"
+                ><i class="el-icon-s-order"></i>鏌ョ湅璇︽儏</span
+              ></el-button
+            >
+          </template>
+        </el-table-column>
+      </el-table>
+
+      <pagination
+        v-show="total > 0"
+        :total="total"
+        :page.sync="topqueryParams.pageNum"
+        :limit.sync="topqueryParams.pageSize"
+        @pagination="getList"
+      />
+    </el-row>
+    <!-- 娣诲姞鎴栦慨鏀瑰奖鍍忛殢璁垮璇濇 -->
+    <el-dialog
+      :title="title"
+      :visible.sync="addalteropen"
+      width="700px"
+      append-to-body
+    >
+      <el-form ref="form" :model="form" label-width="100px">
+        <el-row :gutter="20">
+          <el-col :span="12"
+            ><el-form-item label="浠诲姟鍚嶇О">
+              <el-input v-model="form.name"></el-input> </el-form-item
+          ></el-col>
+        </el-row>
+        <el-row :gutter="20">
+          <el-col :span="24"
+            ><el-form-item label="鎵�灞炵瀹�">
+              <el-select v-model="form.region" placeholder="璇烽�夋嫨绉戝">
+                <el-option label="鍖哄煙涓�" value="shanghai"></el-option>
+                <el-option label="鍖哄煙浜�" value="beijing"></el-option>
+              </el-select> </el-form-item></el-col
+        ></el-row>
+        <el-row :gutter="20">
+          <el-col :span="24"
+            ><el-form-item label="闅忚绫诲瀷">
+              <el-select v-model="form.region" placeholder="璇烽�夋嫨闅忚绫诲瀷">
+                <el-option label="鍖哄煙涓�" value="shanghai"></el-option>
+                <el-option label="鍖哄煙浜�" value="beijing"></el-option>
+              </el-select> </el-form-item
+          ></el-col>
+        </el-row>
+        <el-row :gutter="20">
+          <el-col :span="24">
+            <el-form-item label="鏈嶅姟妯″潡">
+              <el-select v-model="form.region" placeholder="璇烽�夋嫨妯″潡">
+                <el-option label="鍖哄煙涓�" value="shanghai"></el-option>
+                <el-option label="鍖哄煙浜�" value="beijing"></el-option>
+              </el-select>
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row :gutter="20">
+          <el-col :span="24">
+            <el-form-item label="褰卞儚闅忚瑕佹眰">
+              <el-input type="textarea" v-model="form.desc"></el-input>
+            </el-form-item>
+          </el-col>
+        </el-row>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="submitForm">鎻� 浜�</el-button>
+        <el-button @click="cancel">杩� 鍥�</el-button>
+      </div>
+    </el-dialog>
+    <!-- 淇敼鍙戦�佹椂闂村璇濇 -->
+    <!-- 鍐嶆闅忚 -->
+    <el-dialog title="鎮h�呭啀娆¢殢璁�" :visible.sync="dialogFormVisible">
+      <el-form ref="form" :model="zcform" label-width="80px">
+        <el-form-item label="鎮h�呭悕绉�">
+          <el-input style="width: 400px" v-model="zcform.name"></el-input>
+        </el-form-item>
+        <el-form-item label="浠诲姟鍚嶇О">
+          <el-input style="width: 400px" v-model="zcform.name"></el-input>
+        </el-form-item>
+        <el-form-item label="闅忚鏂瑰紡">
+          <el-radio-group v-model="zcform.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="闅忚鏃堕棿" v-if="!zcform.delivery">
+          <el-col :span="11">
+            <el-date-picker
+              type="date"
+              placeholder="閫夋嫨鏃ユ湡"
+              v-model="zcform.date1"
+              style="width: 100%"
+            ></el-date-picker>
+          </el-col>
+          <el-col class="line" :span="2">-</el-col>
+          <el-col :span="11">
+            <el-time-picker
+              placeholder="閫夋嫨鏃堕棿"
+              v-model="zcform.date2"
+              style="width: 100%"
+            ></el-time-picker>
+          </el-col>
+        </el-form-item>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button @click="dialogFormVisible = false">鍙� 娑�</el-button>
+        <el-button type="primary" @click="dialogFormVisible = false"
+          >纭� 瀹�</el-button
+        >
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import {
+  listUser,
+  getUser,
+  delUser,
+  addUser,
+  updateUser,
+  resetUserPwd,
+  changeUserStatus,
+} from "@/api/system/user";
+import {
+  historservelist,
+  buidegetTasklist,
+  query360PatInfo,
+} from "@/api/AiCentre/index";
+import Treeselect from "@riophae/vue-treeselect";
+import store from "@/store";
+import "@riophae/vue-treeselect/dist/vue-treeselect.css";
+
+export default {
+  name: "Discharge",
+  dicts: ["sys_normal_disable", "sys_user_sex", "sys_yujing", "sys_suggest"],
+  components: { Treeselect },
+  data() {
+    return {
+      // 閬僵灞�
+      loading: true,
+      // 閫変腑鏁扮粍
+      ids: [],
+      // 闈炲崟涓鐢�
+      single: true,
+      // 闈炲涓鐢�
+      multiple: true,
+      // 鏄剧ず鎼滅储鏉′欢
+      showSearch: true,
+      dialogFormVisible: false,
+      // 鎬绘潯鏁�
+      total: 0,
+      // 鐢ㄦ埛琛ㄦ牸鏁版嵁
+      userList: null,
+      // 寮瑰嚭灞傛爣棰�
+      title: "鏂板褰卞儚闅忚",
+      // 鏄惁鏄剧ず淇敼銆佹坊鍔犲脊鍑哄眰
+      addalteropen: false,
+      // 淇敼鍙戦�佹椂闂村璇濇
+      modificationVisible: false,
+      // 閮ㄩ棬鍚嶇О
+      deptName: undefined,
+      // 榛樿瀵嗙爜
+      initPassword: undefined,
+      // 鏃ユ湡鑼冨洿
+      dateRange: [],
+      // 宀椾綅閫夐」
+      postOptions: [],
+      ruleForm: {
+        type: [],
+      },
+      postData: {
+        XiaoXiTou: {
+          FaSongFCSJC: "ZJHES",
+          FaSongJGID: localStorage.getItem("orgid"),
+          FaSongJGMC: localStorage.getItem("orgname"),
+          FaSongSJ: "2025-01-09聽17:29:36",
+          FaSongXTJC: "SUIFANGXT",
+          FaSongXTMC: "闅忚绯荤粺",
+          XiaoXiID: "5FA92AFB-9833-4608-87C7-F56A654AC171",
+          XiaoXiLX: "SC_LC_360STCX",
+          XiaoXiMC: "360聽瑙嗗浘鏌ヨ",
+          ZuHuID: localStorage.getItem("ZuHuID"),
+          ZuHuMC: localStorage.getItem("orgname"),
+        },
+        YeWuXX: {
+          BingRenXX: {
+            ZhengJianHM: "",
+            ZhengJianLXDM: "01",
+            ZhengJianLXMC: "灞呮皯韬唤璇�",
+            ZuZhiJGID: localStorage.getItem("orgid"),
+            ZuZhiJGMC: localStorage.getItem("orgname"),
+          },
+          YongHuXX: {
+            XiTongID: "SUIFANGXT",
+            XiTongMC: "闅忚绯荤粺",
+            YongHuID: localStorage.getItem("YongHuID"),
+            YongHuXM: localStorage.getItem("YongHuXM"),
+            ZuZhiJGID: localStorage.getItem("orgid"),
+            ZuZhiJGMC: localStorage.getItem("orgname"),
+            idp: "lyra",
+          },
+        },
+      },
+      zcform: {},
+      dynamicTags: ["閫夐」涓�", "閫夐」浜�", "閫夐」涓�"], //閫夐」
+      inputVisible: false,
+      ycvalue: "",
+      yfsvalue: "",
+      inputValue: "",
+      preachform: "",
+      previewVisible: false, //褰卞儚闅忚棰勮寮规
+      radio: "",
+      radios: [],
+      previewtype: 2, //棰勮褰卞儚闅忚绫诲瀷
+      total: 0, // 鎬绘潯鏁�
+      ImportQuantity: 999, //瀵煎奖鍍忛殢璁挎暟閲�
+      //棰勮褰卞儚闅忚淇℃伅
+      previewvalue: {
+        username: "杩欎釜鍖荤敓瀵逛綘鎬庝箞鏍�",
+      },
+      value: [],
+      list: [],
+
+      sourcetype: [
+        {
+          value: 1,
+          label: "绉戝",
+          children: [],
+        },
+        {
+          value: 2,
+          label: "鐥呭尯",
+          children: [],
+        },
+        {
+          value: 3,
+          label: "鍏ㄩ儴",
+        },
+      ],
+      loading: false,
+      cardlist: [
+        {
+          name: "鍑洪櫌鏈嶅姟鎬婚噺",
+          value: 0,
+        },
+        // {
+        //   name: "鎮h�呰繃婊�",
+        //   value: 0,
+        // },
+        {
+          name: "闇�闅忚",
+          value: 0,
+        },
+
+        // {
+        //   name: "寮傚父",
+        //   value: 0,
+        // },
+        {
+          name: "鍙戦�佸け璐�",
+          value: 0,
+        },
+        {
+          name: "寰呴殢璁�",
+          value: 0,
+        },
+        // {
+        //   name: "宸插彂閫�",
+        //   value: 0,
+        // },
+
+        // {
+        //   name: "琛ㄥ崟宸插彂閫�",
+        //   value: 0,
+        // },
+      ],
+
+      // 琛ㄥ崟鍙傛暟
+      form: {
+        phonenumber: "",
+        totagid: "",
+        types: "",
+        nickName: "",
+        qystatus: "",
+        btstatus: "",
+      },
+      // 鏌ヨ鍙傛暟
+      topqueryParams: {
+        pageNum: 1,
+        pageSize: 10,
+      },
+      propss: { multiple: true },
+      options: [],
+
+      topicoptions: [
+        {
+          value: null,
+          label: "鍏ㄩ儴",
+        },
+        {
+          value: 1,
+          label: "琛ㄥ崟宸查鍙�",
+        },
+        {
+          value: 2,
+          label: "寰呴殢璁�",
+        },
+        {
+          value: 3,
+          label: "琛ㄥ崟宸插彂閫�",
+        },
+        {
+          value: 4,
+          label: "涓嶆墽琛�",
+        },
+         {
+          value: 5,
+          label: "鍙戦�佸け璐�",
+        },
+        {
+          value: 6,
+          label: "宸插畬鎴�",
+        },
+         {
+          value: 7,
+          label: "瓒呮椂",
+        },
+      ],
+      topicoptionsyj: [
+        {
+          value: 1,
+          label: "寮傚父",
+        },
+        {
+          value: 0,
+          label: "姝e父",
+        },
+      ],
+      topicoptionssort: [
+        {
+          value: 0,
+          label: "鍑洪櫌鏃堕棿(姝e簭)",
+        },
+        {
+          value: 1,
+          label: "鍑洪櫌鏃堕棿(鍊掑簭)",
+        },
+        {
+          value: 2,
+          label: "鍙戦�佹椂闂�(姝e簭)",
+        },
+        {
+          value: 3,
+          label: "鍙戦�佹椂闂�(鍊掑簭)",
+        },
+        {
+          value: 7,
+          label: "搴旈殢璁挎棩鏈�(姝e簭)",
+        },
+        {
+          value: 8,
+          label: "搴旈殢璁挎棩鏈�(鍊掑簭)",
+        },
+      ],
+      errtype: "",
+      leavehospitaldistrictcode: "",
+      serviceState: [],
+      checkboxlist: [],
+      // 琛ㄥ崟鏍¢獙
+      rules: {},
+    };
+  },
+  watch: {},
+  created() {
+    this.serviceState = store.getters.serviceState;
+    this.checkboxlist = store.getters.checkboxlist;
+    this.errtype = this.$route.query.errtype;
+    this.leavehospitaldistrictcode =
+      this.$route.query.leavehospitaldistrictcode;
+    this.sourcetype[0].children = store.getters.belongDepts.map((dept) => {
+      return {
+        label: dept.deptName,
+        value: dept.deptCode,
+      };
+    });
+    this.sourcetype[1].children = store.getters.belongWards.map((dept) => {
+      return {
+        label: dept.districtName,
+        value: dept.districtCode,
+      };
+    });
+    if (this.errtype) {
+      this.toleadExport(2);
+    } else {
+      this.getList(1);
+    }
+    this.getConfigKey("sys.user.initPassword").then((response) => {
+      this.initPassword = response.msg;
+    });
+  },
+  activated() {
+    this.getList(1);
+  },
+  methods: {
+    /** 鏌ヨ褰卞儚闅忚鏈嶅姟鍒楄〃 */
+    getList(refresh) {
+      // 榛樿鍏ㄩ儴
+
+      this.loading = true;
+
+      historservelist(this.topqueryParams).then((response) => {
+        // this.userList = response.rows[0].serviceSubtaskList;
+        this.userList = response?.rows ?? [];
+        this.total = response.total;
+        this.loading = false;
+        this.userList.forEach((item) => {
+          let idArray = null;
+          if (item.endtime) {
+            item.endDay = this.daysBetween(item.endtime);
+          }
+
+          if (item.preachform) {
+            if (item.endtime) {
+              item.preachformson = item.preachform;
+              idArray = item.preachform.split(",");
+            }
+
+            item.preachform = idArray.map((value) => {
+              // 鏌ユ壘id瀵瑰簲鐨勫璞�
+              const item = this.checkboxlist.find(
+                (item) => item.value == value
+              );
+              // 濡傛灉鎵惧埌瀵瑰簲鐨刬d锛岃繑鍥瀕abel鍊硷紝鍚﹀垯杩斿洖null
+              return item ? item.label : null;
+            });
+          }
+        });
+        this.total = response.total;
+      });
+    },
+    //鎮h��360璺宠浆
+    gettoken360(sfzh, drcode, drname) {
+      // this.$modal.msgWarning('360鍔熻兘鏆傛湭寮�閫�');
+
+      this.postData.YeWuXX.BingRenXX.ZhengJianHM = sfzh;
+
+      query360PatInfo(this.postData).then((res) => {
+        if (res.data.url) {
+          window.open(res.data.url, "_blank");
+          // this.linkUrl = res.data.url;
+        } else {
+          this.$modal.msgWarning("360鏌ヨ鏃犵粨鏋�");
+        }
+      });
+    },
+    buidegetTasklist(type) {
+      if (this.topqueryParams.searchscope == 3) {
+        this.topqueryParams.leaveldeptcodes = store.getters.belongDepts.map(
+          (obj) => obj.deptCode
+        );
+        this.topqueryParams.leavehospitaldistrictcodes =
+          store.getters.belongWards.map((obj) => obj.districtCode);
+      }
+      // 鎺ュ彈寮傚父璺宠浆
+      if (this.errtype) {
+        this.topqueryParams.leavehospitaldistrictcodes.push(
+          this.leavehospitaldistrictcode
+        );
+      }
+      let obj = {
+        pageNum: 1,
+        pageSize: 10,
+        leavehospitaldistrictcodes:
+          this.topqueryParams.leavehospitaldistrictcodes,
+        sendstates: [2, 3],
+        leaveldeptcodes: this.topqueryParams.leaveldeptcodes,
+      };
+      buidegetTasklist(obj).then((response) => {
+        this.userList = response.rows[0].serviceSubtaskList;
+        this.total = response.total;
+        if (refresh) {
+          this.cardlist[0].value =
+            Number(response.rows[0].wzx) + Number(response.rows[0].ysf);
+          this.cardlist[1].value = response.rows[0].wzx;
+          this.cardlist[2].value = response.rows[0].ysf;
+          this.ycvalue = response.rows[0].yc;
+          this.cardlist[3].value = response.rows[0].fssb;
+          this.cardlist[4].value = response.rows[0].dsf;
+          // this.cardlist[5].value = response.rows[0].yfs2;
+          this.yfsvalue = response.rows[0].yfs;
+        }
+        this.loading = false;
+        this.userList.forEach((item) => {
+          let idArray = null;
+          if (item.endtime) {
+            item.endDay = this.daysBetween(item.endtime);
+          }
+
+          if (item.preachform) {
+            if (item.endtime) {
+              item.preachformson = item.preachform;
+              idArray = item.preachform.split(",");
+            }
+
+            item.preachform = idArray.map((value) => {
+              // 鏌ユ壘id瀵瑰簲鐨勫璞�
+              const item = this.checkboxlist.find(
+                (item) => item.value == value
+              );
+              // 濡傛灉鎵惧埌瀵瑰簲鐨刬d锛岃繑鍥瀕abel鍊硷紝鍚﹀垯杩斿洖null
+              return item ? item.label : null;
+            });
+          }
+        });
+        this.total = response.total;
+      });
+    },
+    // 鏌ョ湅闂ㄨ瘖闅忚璇︽儏
+    Referencequestion(row) {
+      this.previewVisible = true;
+    },
+    // 娣诲姞寮规鎼滅储
+    remoteMethod(query) {
+      if (query !== "") {
+        this.loading = true;
+        setTimeout(() => {
+          this.loading = false;
+          this.options = this.list.filter((item) => {
+            return item.label.toLowerCase().indexOf(query.toLowerCase()) > -1;
+          });
+        }, 200);
+      } else {
+        this.options = [];
+      }
+    },
+    // 褰卞儚闅忚鐘舵�佷慨鏀�
+    handleStatusChange(row) {
+      let text = row.status === "0" ? "鍚敤" : "鍋滅敤";
+      this.$modal
+        .confirm('纭瑕�"' + text + '""' + row.userName + '"鐢ㄦ埛鍚楋紵')
+        .then(function () {
+          return changeUserStatus(row.userId, row.status);
+        })
+        .then(() => {
+          this.$modal.msgSuccess(text + "鎴愬姛");
+        })
+        .catch(function () {
+          row.status = row.status === "0" ? "1" : "0";
+        });
+    },
+    // 鍙栨秷鎸夐挳
+    cancel() {
+      this.addalteropen = false;
+      this.reset();
+    },
+    // 琛ㄥ崟閲嶇疆
+    reset() {
+      this.form = {
+        userId: undefined,
+        deptId: undefined,
+        userName: undefined,
+        nickName: undefined,
+        password: undefined,
+        phonenumber: undefined,
+        email: undefined,
+        sex: undefined,
+        status: "0",
+        remark: undefined,
+        postIds: [],
+        roleIds: [],
+      };
+      this.resetForm("form");
+    },
+    /** 鎼滅储鎸夐挳鎿嶄綔 */
+    handleQuery(refresh) {
+      if (this.topqueryParams.searchscope == 3) {
+        this.topqueryParams.leaveldeptcodes = store.getters.belongDepts.map(
+          (obj) => obj.deptCode
+        );
+        this.topqueryParams.leavehospitaldistrictcodes =
+          store.getters.belongWards.map((obj) => obj.districtCode);
+      }
+      this.topqueryParams.pageNum = 1;
+      this.topqueryParams.startOutHospTime = this.dateRange[0];
+      this.topqueryParams.endOutHospTime = this.dateRange[1];
+
+      this.getList(refresh);
+    },
+    // 鎮h�呰寖鍥村鐞�
+    handleChange(value) {
+      let type = value[0];
+      let code = value.slice(-1)[0];
+      this.topqueryParams.leavehospitaldistrictcodes = [];
+      this.topqueryParams.leaveldeptcodes = [];
+
+      if (type == 1) {
+        this.topqueryParams.leaveldeptcodes.push(code);
+        this.topqueryParams.leavehospitaldistrictcodes = [];
+        this.topqueryParams.searchscope = 1;
+      } else if (type == 2) {
+        this.topqueryParams.leavehospitaldistrictcodes.push(code);
+        this.topqueryParams.leaveldeptcodes = [];
+        this.topqueryParams.searchscope = 2;
+      } else {
+        this.topqueryParams.searchscope = 3;
+      }
+    },
+    /** 閲嶇疆鎸夐挳鎿嶄綔 */
+    resetQuery() {
+      this.dateRange = [];
+      this.topqueryParams = {
+        pageNum: 1,
+        pageSize: 10,
+        serviceType: 13,
+        sort: 2,
+        searchscope: 2,
+        sendstate: 2,
+        scopetype: [],
+        leaveldeptcodes: [],
+        leavehospitaldistrictcodes: [],
+      };
+      this.handleQuery(1);
+    },
+    // 澶氶�夋閫変腑鏁版嵁
+    handleSelectionChange(selection) {
+      this.ids = selection.map((item) => item.userId);
+      this.single = selection.length != 1;
+      this.multiple = !selection.length;
+    },
+    //鍒犻櫎閫夐」
+    handleClose(tag) {
+      this.dynamicTags.splice(this.dynamicTags.indexOf(tag), 1);
+    },
+    //瑙﹀彂鏂板杈撳叆
+    showInput() {
+      this.inputVisible = true;
+      this.$nextTick((_) => {
+        this.$refs.saveTagInput.$refs.input.focus();
+      });
+    },
+    onthatday() {
+      this.topqueryParams.startSendDateTime = this.getCurrentDate();
+      this.topqueryParams.endSendDateTime = this.getCurrentDate();
+      this.getList(1);
+    },
+    getCurrentDate() {
+      const now = new Date();
+      return now.toISOString().slice(0, 10); // 鎴彇鍓�10涓瓧绗︼紝鍗� YYYY-MM-DD
+    },
+    //鑾峰彇澶卞幓鐒︾偣瑙﹀彂
+    handleInputConfirm() {
+      let inputValue = this.inputValue;
+      if (inputValue) {
+        this.dynamicTags.push(inputValue);
+      }
+      this.inputVisible = false;
+      this.inputValue = "";
+    },
+    /** 鏂板鎸夐挳鎿嶄綔 */
+    handleAdd() {
+      this.$router.push({
+        path: "/followvisit/QuestionnaireTask",
+        query: {
+          type: 2,
+          serviceType: 13,
+        },
+      });
+    },
+
+    /** 閲嶇疆瀵嗙爜鎸夐挳鎿嶄綔 */
+    handleResetPwd(row) {
+      this.$prompt('璇疯緭鍏�"' + row.userName + '"鐨勬柊瀵嗙爜', "鎻愮ず", {
+        confirmButtonText: "纭畾",
+        cancelButtonText: "鍙栨秷",
+        closeOnClickModal: false,
+        inputPattern: /^.{5,20}$/,
+        inputErrorMessage: "鐢ㄦ埛瀵嗙爜闀垮害蹇呴』浠嬩簬 5 鍜� 20 涔嬮棿",
+      })
+        .then(({ value }) => {
+          resetUserPwd(row.userId, value).then((response) => {
+            this.$modal.msgSuccess("淇敼鎴愬姛锛屾柊瀵嗙爜鏄細" + value);
+          });
+        })
+        .catch(() => {});
+    },
+
+    /** 鎻愪氦鎸夐挳 */
+    submitForm: function () {
+      this.$refs["form"].validate((valid) => {
+        if (valid) {
+          if (this.form.userId != undefined) {
+            updateUser(this.form).then((response) => {
+              this.$modal.msgSuccess("淇敼鎴愬姛");
+              this.open = false;
+              this.getList(1);
+            });
+          } else {
+            addUser(this.form).then((response) => {
+              this.$modal.msgSuccess("鏂板鎴愬姛");
+              this.open = false;
+              this.getList(1);
+            });
+          }
+        }
+      });
+    },
+    /** 鍒犻櫎鎸夐挳鎿嶄綔 */
+    handleDelete(row) {
+      const userIds = row.userId || this.ids;
+      this.$modal
+        .confirm('鏄惁纭鍒犻櫎鐢ㄦ埛缂栧彿涓�"' + userIds + '"鐨勬暟鎹」锛�')
+        .then(function () {
+          return delUser(userIds);
+        })
+        .then(() => {
+          this.getList(1);
+          this.$modal.msgSuccess("鍒犻櫎鎴愬姛");
+        })
+        .catch(() => {});
+    },
+    // 鍏ㄩ儴鍋滄
+    AllStop() {
+      this.$modal
+        .confirm("鏄惁鍋滄鍏ㄩ儴浠诲姟锛�")
+        .then(function () {
+          return console.log("鍋滄鎴愬姛");
+        })
+        .then(() => {
+          this.getList(1);
+          this.$modal.msgWarning("鍋滄鎴愬姛");
+        })
+        .catch(() => {});
+    },
+    // 鍏ㄩ儴寮�濮�
+    AllStarted() {
+      this.$modal
+        .confirm("鏄惁寮�鍚叏閮ㄤ换鍔★紵")
+        .then(function () {
+          return console.log("寮�鍚垚鍔�");
+        })
+        .then(() => {
+          this.getList(1);
+          this.$modal.msgSuccess("寮�鍚垚鍔�");
+        })
+        .catch(() => {});
+    },
+    // 浠诲姟閲嶇疆
+    TaskReset() {
+      this.$modal
+        .confirm("鏄惁閲嶇疆閫変腑鐨勪换鍔¢」锛�")
+        .then(function () {
+          return console.log("閫変腑鎴愬姛");
+        })
+        .then(() => {
+          this.getList(1);
+          this.$modal.msgSuccess("閲嶇疆鎴愬姛");
+        })
+        .catch(() => {});
+    },
+    // 璁剧疆鍙戦�佹椂闂�
+    Sendtimesetting() {
+      this.modificationVisible = true;
+    },
+    // 璺宠浆璇︽儏椤�
+    Seedetails(row) {
+      let type = "";
+      console.log(row, "rwo");
+      if (row.type == 1) {
+        type = 1;
+      }
+      this.$router.push({
+        path: "/followvisit/record/detailpage/",
+        query: {
+          taskid: row.taskid,
+          patid: row.patid,
+          id: row.id,
+          Voicetype: type,
+          again: 1,
+        },
+      });
+    },
+    // 鍐嶆闅忚
+    followupvisit() {
+      this.dialogFormVisible = true;
+    },
+    onSubmit() {},
+
+    // 渚挎嵎鎸夐挳
+    toleadExport(too) {
+      if (too == 1) {
+        this.topqueryParams.sendstate = 4;
+        this.topqueryParams.excep = null;
+      } else if (too == 2) {
+        this.topqueryParams.excep = 1;
+      }
+      this.handleQuery();
+    },
+    /** 瀵煎嚭鎸夐挳鎿嶄綔 */
+    handleExport() {
+      console.log(this.topqueryParams);
+
+      this.download(
+        // "smartor/serviceSubtask/export",
+        "smartor/serviceSubtask/getSubtaskByDiagnameExport",
+        {
+          ...this.topqueryParams,
+        },
+        `user_${new Date().getTime()}.xlsx`
+      );
+    },
+    // 寮傚父鍒楁覆鏌�
+    tableRowClassName({ row, rowIndex }) {
+      if (row.excep == 1) {
+        return "warning-row";
+      }
+      return "";
+    },
+  },
+};
+</script>
+
+<style lang="scss" scoped>
+.el-button--primary.is-plain {
+  color: #ffffff;
+  background: #409eff;
+  border-color: #4fabe9;
+}
+
+.document {
+  // width: 100px;
+  height: 50px;
+}
+::v-deep.el-table .warning-row {
+  background: #eec4c4;
+}
+
+.documentf {
+  display: flex;
+  justify-content: flex-end;
+}
+
+.download {
+  text-align: center;
+
+  .el-upload__tip {
+    font-size: 23px;
+  }
+
+  .el-upload__text {
+    font-size: 23px;
+  }
+}
+
+.uploading {
+  margin-top: 20px;
+  margin: 20px;
+  padding: 30px;
+  background: #ffffff;
+  border: 1px solid #dcdfe6;
+  -webkit-box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.12),
+    0 0 6px 0 rgba(0, 0, 0, 0.04);
+}
+
+.el-tag + .el-tag {
+  margin-left: 10px;
+}
+
+.button-new-tag {
+  margin-left: 10px;
+  height: 32px;
+  line-height: 30px;
+  padding-top: 0;
+  padding-bottom: 0;
+}
+
+.input-new-tag {
+  width: 90px;
+  margin-left: 10px;
+  vertical-align: bottom;
+}
+
+.drexamine {
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  padding: 30px;
+  background: #daeaf5;
+
+  img {
+    width: 100px;
+    height: 100px;
+  }
+}
+
+.qrcode-dialo {
+  // text-align: center;
+  //   display: flex;
+  margin: 20px;
+  padding: 30px;
+  background: #edf1f7;
+  border: 1px solid #dcdfe6;
+  -webkit-box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.12),
+    0 0 6px 0 rgba(0, 0, 0, 0.04);
+
+  .topic-dev {
+    margin-bottom: 25px;
+    font-size: 20px !important;
+
+    .dev-text {
+      margin-bottom: 10px;
+    }
+  }
+}
+::v-deep.leftvlue .el-card__body {
+  background: #f2f8ff;
+  color: #324a9b;
+}
+::v-deep.leftvlue .el-card__body:hover {
+  background: #3664d9;
+  color: #fff;
+  cursor: pointer; /* 榧犳爣鎮诞鏃跺彉涓烘墜褰� */
+}
+::v-deep.errleftvlue .el-card__body {
+  background: #fdd0d7;
+}
+::v-deep.errleftvlue .el-card__body:hover {
+  background: #f88d96;
+  cursor: pointer; /* 榧犳爣鎮诞鏃跺彉涓烘墜褰� */
+}
+
+::v-deep.ysfleftvlue .el-card__body {
+  background: #d0fdd8;
+}
+::v-deep.ysfleftvlue .el-card__body:hover {
+  background: #8df8a4;
+  cursor: pointer; /* 榧犳爣鎮诞鏃跺彉涓烘墜褰� */
+}
+.button-bb {
+  font-weight: 500;
+  background-color: #2ba05c;
+  padding: 5px;
+  border-radius: 1px;
+  color: #ffffff;
+}
+.button-xq {
+  font-weight: 500;
+  background-color: #409eff;
+  padding: 5px;
+  border-radius: 1px;
+  color: #ffffff;
+}
+.button-sc {
+  font-weight: 500;
+  background-color: #b3a21f;
+  padding: 5px;
+  border-radius: 1px;
+  color: #ffffff;
+}
+.button-zx {
+  background: #4fabe9;
+  padding: 5px;
+  border-radius: 1px;
+  color: #ffffff;
+}
+
+::v-deep.el-radio-group {
+  span {
+    font-size: 24px;
+  }
+}
+
+// 閫夐」瀛椾綋鏀惧ぇ
+// ::v-deep.el-checkbox-group {
+//   span {
+//     font-size: 24px;
+//   }
+// }
+</style>
diff --git a/src/views/followvisit/OutpatientAgain/index.vue b/src/views/followvisit/OutpatientAgain/index.vue
index fc7ef5f..8ba6250 100644
--- a/src/views/followvisit/OutpatientAgain/index.vue
+++ b/src/views/followvisit/OutpatientAgain/index.vue
@@ -79,7 +79,7 @@
           ></el-input>
         </el-form-item>
 
-        <el-form-item label="闂ㄨ瘖鏃堕棿">
+        <el-form-item label="鏈嶅姟鏃堕棿">
           <el-date-picker
             v-model="dateRange"
             style="width: 240px"
@@ -180,7 +180,7 @@
         <el-col :span="1.5">
           <el-button
             type="primary"
-                        icon="el-icon-plus"
+            icon="el-icon-plus"
             size="medium"
             @click="handleAdd"
             >鏂板</el-button
@@ -325,9 +325,14 @@
                   >鍙戦�佸け璐�</el-tag
                 >
               </div>
-              <div v-if="scope.row.sendstate == 6">
+            <div v-if="scope.row.sendstate == 6">
                 <el-tag type="success" :disable-transitions="false"
                   >宸插畬鎴�</el-tag
+                >
+              </div>
+              <div v-if="scope.row.sendstate == 7">
+                <el-tag type="danger" :disable-transitions="false"
+                  >瓒呮椂</el-tag
                 >
               </div>
             </el-tooltip>
@@ -382,11 +387,11 @@
           label="搴旈殢璁挎棩鏈�"
           width="200"
           align="center"
-          key="longSendTime"
-          prop="longSendTime"
+          key="visitTime"
+          prop="visitTime"
         >
           <template slot-scope="scope">
-            <span>{{ formatTime(scope.row.longSendTime) }}</span>
+            <span>{{ formatTime(scope.row.visitTime) }}</span>
           </template></el-table-column
         >
         <el-table-column
@@ -398,7 +403,7 @@
         />
 
         <!-- <el-table-column
-          label="闂ㄨ瘖澶╂暟"
+          label="鏈嶅姟澶╂暟"
           width="120"
           align="center"
           key="endDay"
@@ -485,7 +490,7 @@
         />
 
         <el-table-column
-          label="闂ㄨ瘖闅忚妯℃澘鍚嶇О"
+          label="鏈嶅姟闅忚妯℃澘鍚嶇О"
           align="center"
           key="templatename"
           prop="templatename"
@@ -644,7 +649,7 @@
             </el-form-item>
           </el-col>
         </el-row>
-<el-row >
+        <el-row>
           <el-col :span="8">
             <el-form-item label="杩囨护鍖荤敓" width="100" prop="filterDrname">
               <el-input
@@ -795,7 +800,7 @@
         <!-- <el-form-item label="鍗冲埢鍙戦��">
           <el-switch v-model="zcform.delivery"></el-switch>
         </el-form-item> -->
-        <el-form-item label="闂ㄨ瘖鏃堕棿">
+        <el-form-item label="鏈嶅姟鏃堕棿">
           <el-input
             style="width: 400px"
             disabled
@@ -919,7 +924,7 @@
       loading: false,
       cardlist: [
         {
-          name: "闂ㄨ瘖鏈嶅姟鎬婚噺",
+          name: "鏈嶅姟璺熻釜鎬婚噺",
           value: 0,
         },
         // {
@@ -968,11 +973,11 @@
       topicoptionssort: [
         {
           value: 0,
-          label: "闂ㄨ瘖鏃堕棿(姝e簭)",
+          label: "鏈嶅姟鏃堕棿(姝e簭)",
         },
         {
           value: 1,
-          label: "闂ㄨ瘖鏃堕棿(鍊掑簭)",
+          label: "鏈嶅姟鏃堕棿(鍊掑簭)",
         },
         {
           value: 2,
@@ -996,13 +1001,13 @@
         pageNum: 1,
         pageSize: 10,
         sendstate: 2,
-        sort: localStorage.getItem("orgname") == "涓芥按甯備腑鍖婚櫌" ? 8 : 2, //0 闂ㄨ瘖鏃堕棿(姝e簭)    1 闂ㄨ瘖鏃堕棿(鍊掑簭)   2 鍙戦�佹椂闂�(姝e簭)    3 鍙戦�佹椂闂�(鍊掑簭)  7搴旈殢璁挎棩鏈�(鍊掑簭) 搴旈殢璁挎棩鏈�(姝e簭)
+        sort: localStorage.getItem("orgname") == "涓芥按甯備腑鍖婚櫌" ? 8 : 2, //0 鏈嶅姟鏃堕棿(姝e簭)    1 鏈嶅姟鏃堕棿(鍊掑簭)   2 鍙戦�佹椂闂�(姝e簭)    3 鍙戦�佹椂闂�(鍊掑簭)  7搴旈殢璁挎棩鏈�(鍊掑簭) 搴旈殢璁挎棩鏈�(姝e簭)
         serviceType: 3,
         searchscope: 3,
         visitCount: 2,
         scopetype: [],
         visitDeptCodes: [],
-        leaveldeptcodes:[],
+        // leaveldeptcodes:[],
         leavehospitaldistrictcodes: [],
       },
       propss: { multiple: true },
@@ -1029,13 +1034,17 @@
           value: 4,
           label: "涓嶆墽琛�",
         },
-        {
+         {
           value: 5,
           label: "鍙戦�佸け璐�",
         },
         {
           value: 6,
           label: "宸插畬鎴�",
+        },
+         {
+          value: 7,
+          label: "瓒呮椂",
         },
       ],
       sextype: [
@@ -1141,9 +1150,9 @@
         this.topqueryParams.visitDeptCodes = store.getters.belongDepts.map(
           (obj) => obj.deptCode
         );
-        this.topqueryParams.leaveldeptcodes = store.getters.belongDepts.map(
-          (obj) => obj.deptCode
-        );
+        // this.topqueryParams.leaveldeptcodes = store.getters.belongDepts.map(
+        //   (obj) => obj.deptCode
+        // );
         this.topqueryParams.leavehospitaldistrictcodes =
           store.getters.belongWards.map((obj) => obj.districtCode);
       }
@@ -1157,9 +1166,9 @@
       this.loading = true;
       if (
         this.topqueryParams.leavehospitaldistrictcodes[0] &&
-        this.topqueryParams.visitDeptCodes[0]&&this.topqueryParams.leaveldeptcodes[0]
+        this.topqueryParams.visitDeptCodes[0]
       ) {
-        this.topqueryParams.deptOrDistrict = 2;
+        this.topqueryParams.deptOrDistrict = 4;
       } else {
         this.topqueryParams.deptOrDistrict = 1;
       }
@@ -1204,7 +1213,7 @@
       });
     },
     affiliation() {
-      this.topqueryParams.managementDoctorCode= store.getters.hisUserId;
+      this.topqueryParams.managementDoctorCode = store.getters.hisUserId;
 
       this.getList(1);
     },
@@ -1222,9 +1231,9 @@
         this.topqueryParams.visitDeptCodes = store.getters.belongDepts.map(
           (obj) => obj.deptCode
         );
-          this.topqueryParams.leaveldeptcodes = store.getters.belongDepts.map(
-          (obj) => obj.deptCode
-        );
+        //   this.topqueryParams.leaveldeptcodes = store.getters.belongDepts.map(
+        //   (obj) => obj.deptCode
+        // );
         this.topqueryParams.leavehospitaldistrictcodes =
           store.getters.belongWards.map((obj) => obj.districtCode);
       }
@@ -1241,7 +1250,7 @@
           this.topqueryParams.leavehospitaldistrictcodes,
         sendstates: [2, 3],
         visitDeptCodes: this.topqueryParams.visitDeptCodes,
-        leaveldeptcodes: this.topqueryParams.leaveldeptcodes,
+        // leaveldeptcodes: this.topqueryParams.leaveldeptcodes,
       };
       buidegetTasklist(obj).then((response) => {
         this.userList = response.rows[0].serviceSubtaskList;
@@ -1283,7 +1292,7 @@
         this.total = response.total;
       });
     },
-    // 鏌ョ湅闂ㄨ瘖闅忚璇︽儏
+    // 鏌ョ湅鏈嶅姟闅忚璇︽儏
     Referencequestion(row) {
       this.previewVisible = true;
     },
@@ -1341,9 +1350,9 @@
         this.topqueryParams.visitDeptCodes = store.getters.belongDepts.map(
           (obj) => obj.deptCode
         );
-        this.topqueryParams.leaveldeptcodes = store.getters.belongDepts.map(
-          (obj) => obj.deptCode
-        );
+        // this.topqueryParams.leaveldeptcodes = store.getters.belongDepts.map(
+        //   (obj) => obj.deptCode
+        // );
         this.topqueryParams.leavehospitaldistrictcodes =
           store.getters.belongWards.map((obj) => obj.districtCode);
       }
@@ -1361,16 +1370,16 @@
       let code = value.slice(-1)[0];
       this.topqueryParams.leavehospitaldistrictcodes = [];
       this.topqueryParams.visitDeptCodes = [];
-      this.topqueryParams.leaveldeptcodes = [];
+      // this.topqueryParams.leaveldeptcodes = [];
       if (type == 1) {
         this.topqueryParams.visitDeptCodes.push(code);
-        this.topqueryParams.leaveldeptcodes.push(code);
+        // this.topqueryParams.leaveldeptcodes.push(code);
         this.topqueryParams.leavehospitaldistrictcodes = [];
         this.topqueryParams.searchscope = 1;
       } else if (type == 2) {
         this.topqueryParams.leavehospitaldistrictcodes.push(code);
         this.topqueryParams.visitDeptCodes = [];
-        this.topqueryParams.leaveldeptcodes = [];
+        // this.topqueryParams.leaveldeptcodes = [];
         this.topqueryParams.searchscope = 2;
       } else {
         this.topqueryParams.searchscope = 3;
@@ -1384,13 +1393,13 @@
         pageNum: 1,
         pageSize: 10,
         sendstate: 2,
-        sort: 2, //0 闂ㄨ瘖鏃堕棿(姝e簭)    1 闂ㄨ瘖鏃堕棿(鍊掑簭)   2 鍙戦�佹椂闂�(姝e簭)    3 鍙戦�佹椂闂�(鍊掑簭)
+        sort: 2, //0 鏈嶅姟鏃堕棿(姝e簭)    1 鏈嶅姟鏃堕棿(鍊掑簭)   2 鍙戦�佹椂闂�(姝e簭)    3 鍙戦�佹椂闂�(鍊掑簭)
         serviceType: 3,
         searchscope: 3,
         visitCount: 2,
         scopetype: [],
         visitDeptCodes: [],
-        leaveldeptcodes:[],
+        // leaveldeptcodes:[],
         leavehospitaldistrictcodes: [],
       };
       this.handleQuery(1);
@@ -1478,7 +1487,7 @@
             .then((response) => {
               console.log(response);
             })
-              .then(() => {
+            .then(() => {
               this.getList(1);
               this.$modal.msgSuccess("鎮h�呰繃婊ゆ垚鍔�");
             });
@@ -1547,11 +1556,11 @@
     },
     // 璺宠浆璇︽儏椤�
     Seedetails(row) {
-    let type = "";
+      let type = "";
       console.log(row, "rwo");
-        if (row.type == 1) {
-          type = 1;
-        }
+      if (row.type == 1) {
+        type = 1;
+      }
       this.$router.push({
         path: "/followvisit/record/detailpage/",
         query: {
@@ -1645,7 +1654,7 @@
           this.zcform.remark =
             this.zcform.remark + "銆�" + this.getCurrentTime() + "銆�";
           let form = structuredClone(this.zcform);
-          form.longSendTime = this.formatTime(form.date1);
+          form.visitTime = this.formatTime(form.date1);
           form.finishtime = "";
           if (form.resource) {
             if (form.resource == 2) {
@@ -1777,11 +1786,11 @@
   }
 }
 ::v-deep.leftvlue .el-card__body {
-  background: #F2F8FF;
-  color: #324A9B;
+  background: #f2f8ff;
+  color: #324a9b;
 }
 ::v-deep.leftvlue .el-card__body:hover {
-  background: #3664D9;
+  background: #3664d9;
   color: #fff;
   cursor: pointer; /* 榧犳爣鎮诞鏃跺彉涓烘墜褰� */
 }
diff --git a/src/views/followvisit/SpecificDisease/index.vue b/src/views/followvisit/SpecificDisease/index.vue
index c5131a7..ac905dc 100644
--- a/src/views/followvisit/SpecificDisease/index.vue
+++ b/src/views/followvisit/SpecificDisease/index.vue
@@ -324,11 +324,11 @@
           label="搴旈殢璁挎棩鏈�"
           width="200"
           align="center"
-          key="longSendTime"
-          prop="longSendTime"
+          key="visitTime"
+          prop="visitTime"
         >
           <template slot-scope="scope">
-            <span>{{ formatTime(scope.row.longSendTime) }}</span>
+            <span>{{ formatTime(scope.row.visitTime) }}</span>
           </template></el-table-column
         >
         <el-table-column
@@ -892,7 +892,7 @@
           value: 4,
           label: "涓嶆墽琛�",
         },
-        {
+         {
           value: 5,
           label: "鍙戦�佸け璐�",
         },
@@ -900,6 +900,10 @@
           value: 6,
           label: "宸插畬鎴�",
         },
+         {
+          value: 7,
+          label: "瓒呮椂",
+        },
       ],
       topicoptionsyj: [
         {
diff --git a/src/views/followvisit/Tracking/index.vue b/src/views/followvisit/Tracking/index.vue
new file mode 100644
index 0000000..d93f58c
--- /dev/null
+++ b/src/views/followvisit/Tracking/index.vue
@@ -0,0 +1,1793 @@
+<template>
+  <div class="app-container">
+
+    <el-row :gutter="20">
+      <!--鐢ㄦ埛鏁版嵁-->
+      <el-form
+        :model="topqueryParams"
+        ref="queryForm"
+        size="small"
+        :inline="true"
+        v-show="showSearch"
+        label-width="98px"
+      >
+        <el-form-item label="浠诲姟鍚嶇О">
+          <el-input
+            v-model="topqueryParams.taskName"
+            placeholder="璇烽�夋嫨浠诲姟鍚嶇О"
+          ></el-input>
+        </el-form-item>
+
+        <el-form-item label="寤剁画鎶ょ悊鏃堕棿">
+          <el-date-picker
+            v-model="dateRange"
+            style="width: 240px"
+            value-format="yyyy-MM-dd"
+            type="daterange"
+            range-separator="-"
+            start-placeholder="寮�濮嬫棩鏈�"
+            end-placeholder="缁撴潫鏃ユ湡"
+          ></el-date-picker>
+        </el-form-item>
+        <el-form-item label="搴旈殢璁挎椂闂�">
+          <el-date-picker
+            v-model="dateRangefs"
+            style="width: 240px"
+            value-format="yyyy-MM-dd"
+            type="daterange"
+            range-separator="-"
+            start-placeholder="寮�濮嬫棩鏈�"
+            end-placeholder="缁撴潫鏃ユ湡"
+          ></el-date-picker>
+        </el-form-item>
+
+        <el-form-item label="鎮h�呭鍚�" prop="sendname">
+          <el-input
+            v-model="topqueryParams.sendname"
+            placeholder="璇疯緭鍏ユ偅鑰呭鍚�"
+          ></el-input>
+        </el-form-item>
+        <el-form-item label="璇婃柇鍚嶇О" prop="leavediagname">
+          <el-input
+            v-model="topqueryParams.leavediagname"
+            placeholder="璇疯緭鍏ヨ瘖鏂悕绉�"
+          ></el-input>
+        </el-form-item>
+
+        <el-form-item label="鎮h�呰寖鍥�" prop="status">
+          <el-cascader
+            v-model="topqueryParams.scopetype"
+            placeholder="榛樿鍏ㄩ儴"
+            :options="sourcetype"
+            :props="{ expandTrigger: 'hover' }"
+            @change="handleChange"
+          ></el-cascader>
+        </el-form-item>
+
+        <el-form-item label="浠诲姟鐘舵��" prop="status">
+          <el-select v-model="topqueryParams.sendstate" placeholder="璇烽�夋嫨">
+            <el-option
+              v-for="item in topicoptions"
+              :key="item.value"
+              :label="item.label"
+              :value="item.value"
+            >
+            </el-option>
+          </el-select>
+        </el-form-item>
+        <el-form-item label="鎺掑簭鏂瑰紡" prop="status">
+          <el-select v-model="topqueryParams.sort" placeholder="璇烽�夋嫨">
+            <el-option
+              v-for="item in topicoptionssort"
+              :key="item.value"
+              :label="item.label"
+              :value="item.value"
+            >
+            </el-option>
+          </el-select>
+        </el-form-item>
+
+        <el-form-item>
+          <el-button
+            type="primary"
+            icon="el-icon-search"
+            size="medium"
+            @click="handleQuery(1)"
+            >鎼滅储</el-button
+          >
+          <el-button icon="el-icon-refresh" size="medium" @click="resetQuery"
+            >閲嶇疆</el-button
+          >
+        </el-form-item>
+      </el-form>
+      <el-divider></el-divider>
+      <el-row :gutter="10" class="mb8">
+        <el-col :span="1.5">
+          <div class="documentf">
+            <div class="document">
+              <el-button
+                type="warning"
+                plain
+                icon="el-icon-upload2"
+                size="medium"
+                @click="handleExport"
+                >瀵煎嚭</el-button
+              >
+            </div>
+          </div>
+        </el-col>
+        <el-col :span="1.5">
+          <el-button
+            type="primary"
+                        icon="el-icon-plus"
+            size="medium"
+            @click="handleAdd"
+            >鏂板</el-button
+          >
+        </el-col>
+
+        <el-col :span="1.5">
+          <div class="documentf">
+            <div class="document">
+              <el-button
+                type="warning"
+                plain
+                icon="el-icon-warning-outline"
+                size="medium"
+                @click="toleadExport(1)"
+                >鎵ц澶辫触</el-button
+              >
+            </div>
+          </div>
+        </el-col>
+        <el-col :span="1.5">
+          <div class="documentf">
+            <div class="document">
+              <el-button
+                type="danger"
+                plain
+                icon="el-icon-warning"
+                size="medium"
+                @click="toleadExport(2)"
+                >缁撴灉寮傚父</el-button
+              >
+            </div>
+          </div>
+        </el-col>
+        <el-col :span="1.5">
+          <div class="documentf">
+            <div class="document">
+              <el-button
+                type="success"
+                plain
+                size="medium"
+                @click="buidegetTasklist()"
+                >寰呭姙鏈嶅姟</el-button
+              >
+            </div>
+          </div>
+        </el-col>
+        <el-col :span="1.5">
+          <div class="documentf">
+            <div class="document">
+              <el-button
+                type="primary"
+                plain
+                size="medium"
+                @click="affiliation()"
+                >鏈汉鎵�灞炴湇鍔�</el-button
+              >
+            </div>
+          </div>
+        </el-col>
+        <el-col :span="1.5">
+          <div class="documentf">
+            <div class="document">
+              <el-button type="success" size="medium" @click="onthatday()"
+                >浠婃棩鏈嶅姟</el-button
+              >
+            </div>
+          </div>
+        </el-col>
+      </el-row>
+      <el-table
+        v-loading="loading"
+        :data="userList"
+        :row-class-name="tableRowClassName"
+        @selection-change="handleSelectionChange"
+      >
+        <el-table-column type="selection" width="50" align="center" />
+        <el-table-column
+          label="浠诲姟鍚嶇О"
+          fixed
+          width="150"
+          show-overflow-tooltip
+          align="center"
+          key="taskName"
+          prop="taskName"
+        />
+        <!-- <el-table-column label="搴忓彿" fixed align="center" key="id" prop="id" /> -->
+        <el-table-column
+          label="濮撳悕"
+          width="100"
+          align="center"
+          key="sendname"
+          prop="sendname"
+        >
+          <template slot-scope="scope">
+            <el-button
+              size="medium"
+              type="text"
+              @click="
+                gettoken360(scope.row.sfzh, scope.row.drcode, scope.row.drname)
+              "
+              ><span class="button-textsc">{{
+                scope.row.sendname
+              }}</span></el-button
+            >
+          </template>
+        </el-table-column>
+        <el-table-column
+          label="浠诲姟鐘舵��"
+          align="center"
+          key="sendstate"
+          prop="sendstate"
+          width="120"
+        >
+          <template slot-scope="scope">
+            <el-tooltip
+              class="item"
+              effect="dark"
+              :content="scope.row.remark"
+              placement="top-start"
+            >
+              <div v-if="scope.row.sendstate == 1">
+                <el-tag type="primary" :disable-transitions="false"
+                  >琛ㄥ崟宸查鍙�</el-tag
+                >
+              </div>
+              <div v-if="scope.row.sendstate == 2">
+                <el-tag type="primary" :disable-transitions="false"
+                  >寰呴殢璁�</el-tag
+                >
+              </div>
+              <div v-if="scope.row.sendstate == 3">
+                <el-tag type="success" :disable-transitions="false"
+                  >琛ㄥ崟宸插彂閫�</el-tag
+                >
+              </div>
+              <div v-if="scope.row.sendstate == 4">
+                <el-tag type="info" :disable-transitions="false">涓嶆墽琛�</el-tag>
+              </div>
+              <div v-if="scope.row.sendstate == 5">
+                <el-tag type="danger" :disable-transitions="false"
+                  >鍙戦�佸け璐�</el-tag
+                >
+              </div>
+            <div v-if="scope.row.sendstate == 6">
+                <el-tag type="success" :disable-transitions="false"
+                  >宸插畬鎴�</el-tag
+                >
+              </div>
+              <div v-if="scope.row.sendstate == 7">
+                <el-tag type="danger" :disable-transitions="false"
+                  >瓒呮椂</el-tag
+                >
+              </div>
+            </el-tooltip>
+          </template>
+        </el-table-column>
+        <!-- <el-table-column
+          label="浠诲姟寮傚父璇存槑"
+          width="120"
+          align="center"
+          key="remark"
+          prop="remark" -->
+        />
+
+        <el-table-column
+          label="澶勭悊鎰忚"
+          align="center"
+          key="suggest"
+          prop="suggest"
+          width="120"
+        >
+          <template slot-scope="scope">
+            <dict-tag
+              :options="dict.type.sys_suggest"
+              :value="scope.row.suggest"
+            />
+          </template>
+        </el-table-column>
+
+        <el-table-column
+          label="闅忚瀹屾垚鏃堕棿"
+          sortable
+          align="center"
+          prop="finishtime"
+          width="160"
+        >
+          <template slot-scope="scope">
+            <span>{{ parseTime(scope.row.finishtime) }}</span>
+          </template>
+        </el-table-column>
+        <el-table-column
+          label="灏辫瘖鏃ユ湡"
+          width="200"
+          align="center"
+          key="endtime"
+          prop="endtime"
+        >
+          <template slot-scope="scope">
+            <span>{{ formatTime(scope.row.endtime) }}</span>
+          </template></el-table-column
+        >
+        <el-table-column
+          label="搴旈殢璁挎棩鏈�"
+          width="200"
+          align="center"
+          key="visitTime"
+          prop="visitTime"
+        >
+          <template slot-scope="scope">
+            <span>{{ formatTime(scope.row.visitTime) }}</span>
+          </template></el-table-column
+        >
+        <el-table-column
+          label="涓绘不鍖荤敓"
+          width="120"
+          align="center"
+          key="drname"
+          prop="drname"
+        />
+
+        <!-- <el-table-column
+          label="寤剁画鎶ょ悊澶╂暟"
+          width="120"
+          align="center"
+          key="endDay"
+          prop="endDay"
+        >
+          <template slot-scope="scope">
+            <span>{{ scope.row.endDay ? scope.row.endDay + "澶�" : "" }}</span>
+          </template>
+        </el-table-column> -->
+        <el-table-column
+          label="韬唤璇佸彿鐮�"
+          width="200"
+          align="center"
+          key="sfzh"
+          prop="sfzh"
+        />
+        <el-table-column
+          label="鑱旂郴鐢佃瘽"
+          width="200"
+          align="center"
+          key="phone"
+          prop="phone"
+        />
+        <el-table-column
+          label="璐d换鎶ゅ+"
+          width="120"
+          align="center"
+          key="nurseName"
+          prop="nurseName"
+        />
+
+        <!-- <el-table-column
+          label="鐥呭巻鍙�"
+          align="center"
+          sortable
+          key="medicalRecordNo"
+          prop="medicalRecordNo"
+          width="120"
+        /> -->
+
+        <!-- <el-table-column label="骞撮緞" align="center" key="age" prop="age" /> -->
+        <!-- <el-table-column label="鎬у埆"width="100" align="center" key="sex" prop="sex" /> -->
+        <!-- <el-table-column label="搴婂彿" align="center" key="badNo" prop="badNo" /> -->
+        <el-table-column
+          label="棣栨闅忚绉戝"
+          align="center"
+          key="deptname"
+          prop="deptname"
+          width="120"
+        >
+        </el-table-column>
+        <el-table-column
+          label="鏈绉戝"
+          align="center"
+          key="visitDeptName"
+          prop="visitDeptName"
+          width="120"
+        >
+        </el-table-column>
+        <el-table-column
+          label="鐥呭尯"
+          align="center"
+          key="leavehospitaldistrictname"
+          prop="leavehospitaldistrictname"
+          width="120"
+        >
+        </el-table-column>
+
+        <el-table-column
+          label="璇婃柇鍚嶇О"
+          align="center"
+          key="leavediagname"
+          prop="leavediagname"
+          width="120"
+          :show-overflow-tooltip="true"
+        >
+        </el-table-column>
+        <el-table-column
+          label="闅忚浜哄憳"
+          align="center"
+          key="updateBy"
+          prop="updateBy"
+          width="120"
+        />
+
+        <el-table-column
+          label="寤剁画鎶ょ悊闅忚妯℃澘鍚嶇О"
+          align="center"
+          key="templatename"
+          prop="templatename"
+          width="200"
+        />
+        <el-table-column
+          label="浠诲姟鎵ц鏂瑰紡"
+          align="center"
+          key="preachform"
+          prop="preachform"
+          width="160"
+          :show-overflow-tooltip="true"
+        >
+          <template slot-scope="scope">
+            <span v-for="item in scope.row.preachform">{{ item }}銆� </span>
+          </template>
+        </el-table-column>
+        <!-- <el-table-column
+          label="浠诲姟鍙戦�佹祦绋�"
+          align="center"
+          key="serviceSubtaskRecordList"
+          prop="serviceSubtaskRecordList"
+          width="160"
+          :show-overflow-tooltip="true"
+        >
+          <template slot-scope="scope">
+            <span v-for="item in scope.row.serviceSubtaskRecordList"
+              >{{ item.remark }}銆�
+            </span>
+          </template>
+        </el-table-column> -->
+        <el-table-column
+          label="浠诲姟缁撴灉璇存槑"
+          width="220"
+          align="center"
+          key="remark"
+          prop="remark"
+        >
+          <template slot-scope="scope" v-if="scope.row.remark">
+            <el-tooltip
+              :content="scope.row.remark"
+              placement="top"
+              effect="dark"
+            >
+              <el-tag
+                type="warning"
+                v-if="scope.row.sendstate != 5 && scope.row.sendstate != 4"
+                >{{ scope.row.remark }}</el-tag
+              >
+              <el-tag type="warning" v-else>{{ scope.row.remark }}</el-tag>
+            </el-tooltip>
+          </template>
+        </el-table-column>
+        <el-table-column
+          label="鎿嶄綔"
+          align="center"
+          fixed="right"
+          width="300"
+          class-name="small-padding fixed-width"
+        >
+          <template slot-scope="scope">
+            <!-- <el-tooltip
+              class="item"
+              effect="dark"
+              content="鍐嶆闅忚"
+              placement="top"
+            >
+              <el-button
+                size="medium"
+                type="text"
+                v-if="scope.row.isVisitAgain!=2"
+                @click="followupvisit(scope.row)"
+                ><span class="button-bb"
+                  ><i class="el-icon-s-promotion"></i>鍐嶆闅忚</span
+                ></el-button
+              >
+            </el-tooltip>
+            <el-tooltip
+              v-if="scope.row.sendstate == 1 || scope.row.sendstate == 2"
+              class="item"
+              effect="dark"
+              content="鏆傚仠鏈嶅姟"
+              placement="top"
+            >
+              <el-button
+                size="medium"
+                type="text"
+                @click="handlestop(scope.row)"
+                v-hasPermi="['system:user:edit']"
+                ><span class="button-sc"
+                  ><i class="el-icon-remove-outline"></i>鏆傚仠鏈嶅姟</span
+                ></el-button
+              >
+            </el-tooltip> -->
+            <el-button size="medium" type="text" @click="Seedetails(scope.row)"
+              ><span class="button-zx"
+                ><i class="el-icon-s-order"></i>鏌ョ湅璇︽儏</span
+              ></el-button
+            >
+            <el-button
+              size="medium"
+              type="text"
+              @click="handleUpdate(scope.row)"
+              ><span class="button-textxga"
+                ><i class="el-icon-edit"></i>鎮h�呰繃婊�</span
+              ></el-button
+            >
+          </template>
+        </el-table-column>
+      </el-table>
+
+      <pagination
+        v-show="total > 0"
+        :total="total"
+        :page.sync="topqueryParams.pageNum"
+        :limit.sync="topqueryParams.pageSize"
+        @pagination="getList"
+      />
+    </el-row>
+    <!-- 娣诲姞鎴栦慨鏀瑰奖鍍忛殢璁垮璇濇 -->
+    <el-dialog
+      :title="amendtag ? '淇敼鎮h�呬俊鎭�' : '鏂板鎮h��'"
+      :visible.sync="Labelchange"
+      width="900px"
+    >
+      <el-form ref="form" :model="form" :rules="rules" label-width="100px">
+        <el-row>
+          <el-col :span="8">
+            <el-form-item label="濮撳悕" width="100" prop="name">
+              <el-input
+                v-model="form.name"
+                placeholder="璇疯緭鍏ュ鍚�"
+                maxlength="30"
+              />
+            </el-form-item>
+          </el-col>
+          <el-col :span="8">
+            <el-form-item label="鎬у埆" width="100" prop="sex">
+              <el-select v-model="form.sex" placeholder="璇烽�夋嫨鎬у埆">
+                <el-option
+                  v-for="dict in sextype"
+                  :key="dict.value"
+                  :label="dict.label"
+                  :value="dict.value"
+                ></el-option>
+              </el-select>
+            </el-form-item>
+          </el-col>
+          <el-col :span="8">
+            <el-form-item label="骞撮緞" prop="age">
+              <el-input
+                v-model="form.age"
+                placeholder="璇疯緭鍏ュ勾榫�"
+                maxlength="30"
+              />
+            </el-form-item>
+          </el-col>
+        </el-row>
+<el-row >
+          <el-col :span="8">
+            <el-form-item label="杩囨护鍖荤敓" width="100" prop="filterDrname">
+              <el-input
+                v-model="form.filterDrname"
+                placeholder="璇疯緭鍏ュ尰鐢熷鍚�"
+                maxlength="30"
+              />
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row>
+          <el-col :span="24">
+            <el-form-item label="杩囨护鍘熷洜">
+              <el-input
+                v-model="form.notrequiredreason"
+                type="textarea"
+                placeholder="璇疯緭鍏ヨ繃婊ゅ師鍥�"
+              ></el-input>
+            </el-form-item>
+          </el-col>
+        </el-row>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="submitForm">纭� 瀹�</el-button>
+        <el-button @click="cancel">鍙� 娑�</el-button>
+      </div>
+    </el-dialog>
+    <!-- 淇敼鍙戦�佹椂闂村璇濇 -->
+    <el-dialog
+      title="鍙戦�佹椂闂磋缃�"
+      :visible.sync="modificationVisible"
+      width="45%"
+    >
+      <div style="margin-bottom: 20px; color: red">
+        缁熶竴淇敼褰撳ぉ鏈彂閫佺殑浠诲姟鏃堕棿
+      </div>
+
+      <el-form
+        :model="ruleForm"
+        :rules="rules"
+        ref="ruleForm"
+        label-width="120px"
+        class="demo-ruleForm"
+      >
+        <el-form-item label="鍙戦�佹棩鏈�">
+          <el-date-picker
+            v-model="ruleForm.value1"
+            type="date"
+            placeholder="閫夋嫨鏃ユ湡"
+          >
+          </el-date-picker>
+        </el-form-item>
+
+        <el-form-item label="鏃堕棿娈�" prop="type">
+          <el-checkbox-group v-model="ruleForm.type">
+            <el-checkbox label="涓婂崍" name="type"></el-checkbox>
+            <el-checkbox label="涓嬪崍" name="type"></el-checkbox>
+            <el-checkbox label="鏅氫笂" name="type"></el-checkbox>
+          </el-checkbox-group>
+        </el-form-item>
+        <el-form-item label="涓婂崍鏃堕棿鍖洪棿" required>
+          <el-time-picker
+            is-range
+            v-model="ruleForm.value2"
+            range-separator="鑷�"
+            start-placeholder="寮�濮嬫椂闂�"
+            end-placeholder="缁撴潫鏃堕棿"
+            placeholder="閫夋嫨鏃堕棿鑼冨洿"
+          >
+          </el-time-picker>
+        </el-form-item>
+        <el-form-item label="涓嬪崍鏃堕棿鍖洪棿" required>
+          <el-time-picker
+            is-range
+            v-model="ruleForm.value3"
+            range-separator="鑷�"
+            start-placeholder="寮�濮嬫椂闂�"
+            end-placeholder="缁撴潫鏃堕棿"
+            placeholder="閫夋嫨鏃堕棿鑼冨洿"
+          >
+          </el-time-picker>
+        </el-form-item>
+        <el-form-item label="鏅氫笂鏃堕棿鍖洪棿" required>
+          <el-time-picker
+            is-range
+            v-model="ruleForm.value4"
+            range-separator="鑷�"
+            start-placeholder="寮�濮嬫椂闂�"
+            end-placeholder="缁撴潫鏃堕棿"
+            placeholder="閫夋嫨鏃堕棿鑼冨洿"
+          >
+          </el-time-picker>
+        </el-form-item>
+      </el-form>
+
+      <span slot="footer" class="dialog-footer">
+        <el-button @click="modificationVisible = false">鍙� 娑�</el-button>
+        <el-button type="primary" @click="modificationVisible = false"
+          >纭� 瀹�</el-button
+        >
+      </span>
+    </el-dialog>
+    <!-- 鍐嶆闅忚 -->
+    <el-dialog title="鎮h�呭啀娆¢殢璁�" :visible.sync="dialogFormVisible">
+      <el-form ref="zcform" :rules="zcrules" :model="zcform" label-width="80px">
+        <el-form-item label="浠诲姟鍚嶇О">
+          <el-input
+            style="width: 400px"
+            disabled
+            v-model="zcform.taskName"
+          ></el-input>
+        </el-form-item>
+        <el-form-item label="鎮h�呭悕绉�">
+          <el-input
+            style="width: 400px"
+            disabled
+            v-model="zcform.sendname"
+          ></el-input>
+        </el-form-item>
+        <el-form-item label="骞撮緞">
+          <el-input
+            style="width: 400px"
+            disabled
+            v-model="zcform.age"
+          ></el-input>
+        </el-form-item>
+        <el-form-item label="绉戝">
+          <el-input
+            style="width: 400px"
+            disabled
+            v-model="zcform.deptname"
+          ></el-input>
+        </el-form-item>
+        <el-form-item label="鐥呭尯">
+          <el-input
+            style="width: 400px"
+            disabled
+            v-model="zcform.leavehospitaldistrictname"
+          ></el-input>
+        </el-form-item>
+
+        <el-form-item label="闅忚鏂瑰紡" prop="resource">
+          <el-radio-group v-model="zcform.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="寤剁画鎶ょ悊鏃堕棿">
+          <el-input
+            style="width: 400px"
+            disabled
+            v-model="zcform.endtime"
+          ></el-input>
+        </el-form-item>
+        <el-form-item label="闅忚瀹屾垚鏃堕棿" prop="date1">
+          <el-date-picker
+            type="date"
+            placeholder="閫夋嫨鏃ユ湡"
+            v-model="zcform.date1"
+            style="width: 100%"
+          ></el-date-picker>
+        </el-form-item>
+        <el-form-item label="闅忚璁板綍">
+          <el-input type="textarea" v-model="zcform.remark"></el-input>
+        </el-form-item>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button @click="dialogFormVisible = false">鍙� 娑�</el-button>
+        <el-button type="primary" @click="setupsubtask">纭鍒涘缓鏈嶅姟</el-button>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import {
+  delUser,
+  addUser,
+  updateUser,
+  resetUserPwd,
+  changeUserStatus,
+} from "@/api/system/user";
+import {
+  getTaskservelist,
+  buidegetTasklist,
+  addserviceSubtask,
+  query360PatInfo,
+} from "@/api/AiCentre/index";
+import { alterpatient, particularpatient } from "@/api/patient/homepage";
+import Treeselect from "@riophae/vue-treeselect";
+import store from "@/store";
+import "@riophae/vue-treeselect/dist/vue-treeselect.css";
+
+export default {
+  name: "Discharge",
+  dicts: ["sys_normal_disable", "sys_user_sex", "sys_yujing", "sys_suggest"],
+  components: { Treeselect },
+  data() {
+    return {
+      // 閬僵灞�
+      loading: true,
+      // 閫変腑鏁扮粍
+      ids: [],
+      // 闈炲崟涓鐢�
+      single: true,
+      // 闈炲涓鐢�
+      multiple: true,
+      // 鏄剧ず鎼滅储鏉′欢
+      showSearch: true,
+      dialogFormVisible: false,
+      // 鎬绘潯鏁�
+      total: 0,
+      // 鐢ㄦ埛琛ㄦ牸鏁版嵁
+      userList: null,
+      // 寮瑰嚭灞傛爣棰�
+      title: "鏂板褰卞儚闅忚",
+      // 鏄惁鏄剧ず淇敼銆佹坊鍔犲脊鍑哄眰
+      addalteropen: false,
+      // 淇敼鍙戦�佹椂闂村璇濇
+      modificationVisible: false,
+      // 閮ㄩ棬鍚嶇О
+      deptName: undefined,
+      // 榛樿瀵嗙爜
+      initPassword: undefined,
+      // 鏃ユ湡鑼冨洿
+      dateRange: [],
+      dateRangefs: [],
+      // 宀椾綅閫夐」
+      postOptions: [],
+      ruleForm: {
+        type: [],
+      },
+      zcform: {},
+      dynamicTags: ["閫夐」涓�", "閫夐」浜�", "閫夐」涓�"], //閫夐」
+      inputVisible: false,
+      Labelchange: false,
+      ycvalue: "",
+      yfsvalue: "",
+      inputValue: "",
+      preachform: "",
+      previewVisible: false, //褰卞儚闅忚棰勮寮规
+      radio: "",
+      radios: [],
+      total: 0, // 鎬绘潯鏁�
+      ImportQuantity: 999, //瀵煎奖鍍忛殢璁挎暟閲�
+      //棰勮褰卞儚闅忚淇℃伅
+      previewvalue: {
+        username: "杩欎釜鍖荤敓瀵逛綘鎬庝箞鏍�",
+      },
+      value: [],
+      list: [],
+
+      sourcetype: [
+        {
+          value: 1,
+          label: "绉戝",
+          children: [],
+        },
+        {
+          value: 2,
+          label: "鐥呭尯",
+          children: [],
+        },
+        {
+          value: 3,
+          label: "鍏ㄩ儴",
+        },
+      ],
+      loading: false,
+      cardlist: [
+        {
+          name: "寤剁画鎶ょ悊鏈嶅姟鎬婚噺",
+          value: 0,
+        },
+        // {
+        //   name: "鎮h�呰繃婊�",
+        //   value: 0,
+        // },
+        {
+          name: "闇�闅忚",
+          value: 0,
+        },
+        {
+          name: "鍙戦�佸け璐�",
+          value: 0,
+        },
+        {
+          name: "寰呴殢璁�",
+          value: 0,
+        },
+        // {
+        //   name: "宸插彂閫�",
+        //   value: 0,
+        // },
+
+        // {
+        //   name: "琛ㄥ崟宸插彂閫�",
+        //   value: 0,
+        // },
+      ],
+      zcrules: {
+        date1: [
+          { required: true, message: "璇烽�夋嫨闅忚鏂瑰紡", trigger: "change" },
+        ],
+        resource: [
+          { required: true, message: "璇烽�夋嫨闅忚鏃堕棿", trigger: "blur" },
+        ],
+      },
+      // 琛ㄥ崟鍙傛暟
+      form: {
+        phonenumber: "",
+        totagid: "",
+        types: "",
+        nickName: "",
+        qystatus: "",
+        btstatus: "",
+      },
+      topicoptionssort: [
+        {
+          value: 0,
+          label: "寤剁画鎶ょ悊鏃堕棿(姝e簭)",
+        },
+        {
+          value: 1,
+          label: "寤剁画鎶ょ悊鏃堕棿(鍊掑簭)",
+        },
+        {
+          value: 2,
+          label: "鍙戦�佹椂闂�(姝e簭)",
+        },
+        {
+          value: 3,
+          label: "鍙戦�佹椂闂�(鍊掑簭)",
+        },
+        {
+          value: 7,
+          label: "搴旈殢璁挎棩鏈�(姝e簭)",
+        },
+        {
+          value: 8,
+          label: "搴旈殢璁挎棩鏈�(鍊掑簭)",
+        },
+      ],
+      // 鏌ヨ鍙傛暟
+      topqueryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        sendstate: 2,
+        sort: localStorage.getItem("orgname") == "涓芥按甯備腑鍖婚櫌" ? 8 : 2, //0 寤剁画鎶ょ悊鏃堕棿(姝e簭)    1 寤剁画鎶ょ悊鏃堕棿(鍊掑簭)   2 鍙戦�佹椂闂�(姝e簭)    3 鍙戦�佹椂闂�(鍊掑簭)  7搴旈殢璁挎棩鏈�(鍊掑簭) 搴旈殢璁挎棩鏈�(姝e簭)
+        serviceType: 3,
+        searchscope: 3,
+        visitCount: 2,
+        scopetype: [],
+        visitDeptCodes: [],
+        leaveldeptcodes:[],
+        leavehospitaldistrictcodes: [],
+      },
+      propss: { multiple: true },
+      options: [],
+
+      topicoptions: [
+        {
+          value: null,
+          label: "鍏ㄩ儴",
+        },
+        {
+          value: 1,
+          label: "琛ㄥ崟宸查鍙�",
+        },
+        {
+          value: 2,
+          label: "寰呴殢璁�",
+        },
+        {
+          value: 3,
+          label: "琛ㄥ崟宸插彂閫�",
+        },
+        {
+          value: 4,
+          label: "涓嶆墽琛�",
+        },
+         {
+          value: 5,
+          label: "鍙戦�佸け璐�",
+        },
+        {
+          value: 6,
+          label: "宸插畬鎴�",
+        },
+         {
+          value: 7,
+          label: "瓒呮椂",
+        },
+      ],
+      sextype: [
+        {
+          value: 1,
+          label: "鐢�",
+        },
+        {
+          value: 2,
+          label: "濂�",
+        },
+      ],
+      topicoptionsyj: [
+        {
+          value: 1,
+          label: "寮傚父",
+        },
+        {
+          value: 0,
+          label: "姝e父",
+        },
+      ],
+      url: "http://9.208.2.190:8090/smartor/serviceExternal/query360PatInfo",
+      postData: {
+        XiaoXiTou: {
+          FaSongFCSJC: "ZJHES",
+          FaSongJGID: localStorage.getItem("orgid"),
+          FaSongJGMC: localStorage.getItem("orgname"),
+          FaSongSJ: "2025-01-09聽17:29:36",
+          FaSongXTJC: "SUIFANGXT",
+          FaSongXTMC: "闅忚绯荤粺",
+          XiaoXiID: "5FA92AFB-9833-4608-87C7-F56A654AC171",
+          XiaoXiLX: "SC_LC_360STCX",
+          XiaoXiMC: "360聽瑙嗗浘鏌ヨ",
+          ZuHuID: localStorage.getItem("ZuHuID"),
+          ZuHuMC: localStorage.getItem("orgname"),
+        },
+        YeWuXX: {
+          BingRenXX: {
+            ZhengJianHM: "",
+            ZhengJianLXDM: "01",
+            ZhengJianLXMC: "灞呮皯韬唤璇�",
+            ZuZhiJGID: localStorage.getItem("orgid"),
+            ZuZhiJGMC: localStorage.getItem("orgname"),
+          },
+          YongHuXX: {
+            XiTongID: "SUIFANGXT",
+            XiTongMC: "闅忚绯荤粺",
+            YongHuID: localStorage.getItem("YongHuID"),
+            YongHuXM: localStorage.getItem("YongHuXM"),
+            ZuZhiJGID: localStorage.getItem("orgid"),
+            ZuZhiJGMC: localStorage.getItem("orgname"),
+            idp: "lyra",
+          },
+        },
+      },
+      amendtag: false,
+      errtype: "",
+      leavehospitaldistrictcode: "",
+      serviceState: [],
+      checkboxlist: [],
+      // 琛ㄥ崟鏍¢獙
+      rules: {},
+    };
+  },
+  watch: {},
+  created() {
+    this.serviceState = store.getters.serviceState;
+    this.checkboxlist = store.getters.checkboxlist;
+    this.errtype = this.$route.query.errtype;
+    this.leavehospitaldistrictcode =
+      this.$route.query.leavehospitaldistrictcode;
+    this.sourcetype[0].children = store.getters.belongDepts.map((dept) => {
+      return {
+        label: dept.deptName,
+        value: dept.deptCode,
+      };
+    });
+    this.sourcetype[1].children = store.getters.belongWards.map((dept) => {
+      return {
+        label: dept.districtName,
+        value: dept.districtCode,
+      };
+    });
+    if (this.errtype) {
+      this.toleadExport(2);
+    } else {
+      this.getList(1);
+    }
+    this.getConfigKey("sys.user.initPassword").then((response) => {
+      this.initPassword = response.msg;
+    });
+  },
+  activated() {
+    this.getList(1);
+  },
+  methods: {
+    /** 鏌ヨ闅忚鏈嶅姟鍒楄〃 */
+    getList(refresh) {
+      // 榛樿鍏ㄩ儴
+
+      if (this.topqueryParams.searchscope == 3) {
+        this.topqueryParams.visitDeptCodes = store.getters.belongDepts.map(
+          (obj) => obj.deptCode
+        );
+        this.topqueryParams.leaveldeptcodes = store.getters.belongDepts.map(
+          (obj) => obj.deptCode
+        );
+        this.topqueryParams.leavehospitaldistrictcodes =
+          store.getters.belongWards.map((obj) => obj.districtCode);
+      }
+      // 鎺ュ彈寮傚父璺宠浆
+      if (this.errtype) {
+        this.topqueryParams.leavehospitaldistrictcodes.push(
+          this.leavehospitaldistrictcode
+        );
+        console.log(this.topqueryParams.leavehospitaldistrictcodes, "11");
+      }
+      this.loading = true;
+      if (
+        this.topqueryParams.leavehospitaldistrictcodes[0] &&
+        this.topqueryParams.visitDeptCodes[0]&&this.topqueryParams.leaveldeptcodes[0]
+      ) {
+        this.topqueryParams.deptOrDistrict = 2;
+      } else {
+        this.topqueryParams.deptOrDistrict = 1;
+      }
+      getTaskservelist(this.topqueryParams).then((response) => {
+        this.userList = response.rows[0].serviceSubtaskList;
+        this.total = response.total;
+        if (refresh) {
+          this.cardlist[0].value =
+            Number(response.rows[0].wzx) + Number(response.rows[0].ysf);
+          // this.cardlist[1].value = response.rows[0].wzx;
+          this.cardlist[1].value = response.rows[0].ysf;
+          this.ycvalue = response.rows[0].yc;
+          this.cardlist[2].value = response.rows[0].fssb;
+          this.cardlist[3].value = response.rows[0].dsf;
+          // this.cardlist[4].value = response.rows[0].yfs2;
+          this.yfsvalue = response.rows[0].yfs;
+        }
+        this.loading = false;
+        this.userList.forEach((item) => {
+          let idArray = null;
+          if (item.endtime) {
+            item.endDay = this.daysBetween(item.endtime);
+          }
+
+          if (item.preachform) {
+            if (item.endtime) {
+              item.preachformson = item.preachform;
+              idArray = item.preachform.split(",");
+            }
+
+            item.preachform = idArray.map((value) => {
+              // 鏌ユ壘id瀵瑰簲鐨勫璞�
+              const item = this.checkboxlist.find(
+                (item) => item.value == value
+              );
+              // 濡傛灉鎵惧埌瀵瑰簲鐨刬d锛岃繑鍥瀕abel鍊硷紝鍚﹀垯杩斿洖null
+              return item ? item.label : null;
+            });
+          }
+        });
+        this.total = response.total;
+      });
+    },
+    affiliation() {
+      this.topqueryParams.managementDoctorCode= store.getters.hisUserId;
+
+      this.getList(1);
+    },
+    onthatday() {
+      this.topqueryParams.startSendDateTime = this.getCurrentDate();
+      this.topqueryParams.endSendDateTime = this.getCurrentDate();
+      this.getList(1);
+    },
+    getCurrentDate() {
+      const now = new Date();
+      return now.toISOString().slice(0, 10); // 鎴彇鍓�10涓瓧绗︼紝鍗� YYYY-MM-DD
+    },
+    buidegetTasklist(type) {
+      if (this.topqueryParams.searchscope == 3) {
+        this.topqueryParams.visitDeptCodes = store.getters.belongDepts.map(
+          (obj) => obj.deptCode
+        );
+          this.topqueryParams.leaveldeptcodes = store.getters.belongDepts.map(
+          (obj) => obj.deptCode
+        );
+        this.topqueryParams.leavehospitaldistrictcodes =
+          store.getters.belongWards.map((obj) => obj.districtCode);
+      }
+      // 鎺ュ彈寮傚父璺宠浆
+      if (this.errtype) {
+        this.topqueryParams.leavehospitaldistrictcodes.push(
+          this.leavehospitaldistrictcode
+        );
+      }
+      let obj = {
+        pageNum: 1,
+        pageSize: 10,
+        leavehospitaldistrictcodes:
+          this.topqueryParams.leavehospitaldistrictcodes,
+        sendstates: [2, 3],
+        visitDeptCodes: this.topqueryParams.visitDeptCodes,
+        leaveldeptcodes: this.topqueryParams.leaveldeptcodes,
+      };
+      buidegetTasklist(obj).then((response) => {
+        this.userList = response.rows[0].serviceSubtaskList;
+        this.total = response.total;
+        if (refresh) {
+          this.cardlist[0].value =
+            Number(response.rows[0].wzx) + Number(response.rows[0].ysf);
+          this.cardlist[1].value = response.rows[0].wzx;
+          this.cardlist[2].value = response.rows[0].ysf;
+          this.ycvalue = response.rows[0].yc;
+          this.cardlist[3].value = response.rows[0].fssb;
+          this.cardlist[4].value = response.rows[0].dsf;
+          // this.cardlist[5].value = response.rows[0].yfs2;
+          this.yfsvalue = response.rows[0].yfs;
+        }
+        this.loading = false;
+        this.userList.forEach((item) => {
+          let idArray = null;
+          if (item.endtime) {
+            item.endDay = this.daysBetween(item.endtime);
+          }
+
+          if (item.preachform) {
+            if (item.endtime) {
+              item.preachformson = item.preachform;
+              idArray = item.preachform.split(",");
+            }
+
+            item.preachform = idArray.map((value) => {
+              // 鏌ユ壘id瀵瑰簲鐨勫璞�
+              const item = this.checkboxlist.find(
+                (item) => item.value == value
+              );
+              // 濡傛灉鎵惧埌瀵瑰簲鐨刬d锛岃繑鍥瀕abel鍊硷紝鍚﹀垯杩斿洖null
+              return item ? item.label : null;
+            });
+          }
+        });
+        this.total = response.total;
+      });
+    },
+    // 鏌ョ湅寤剁画鎶ょ悊闅忚璇︽儏
+    Referencequestion(row) {
+      this.previewVisible = true;
+    },
+    // 娣诲姞寮规鎼滅储
+    remoteMethod(query) {
+      if (query !== "") {
+        this.loading = true;
+        setTimeout(() => {
+          this.loading = false;
+          this.options = this.list.filter((item) => {
+            return item.label.toLowerCase().indexOf(query.toLowerCase()) > -1;
+          });
+        }, 200);
+      } else {
+        this.options = [];
+      }
+    },
+    // 褰卞儚闅忚鐘舵�佷慨鏀�
+    handleStatusChange(row) {
+      let text = row.status === "0" ? "鍚敤" : "鍋滅敤";
+      this.$modal
+        .confirm('纭瑕�"' + text + '""' + row.userName + '"鐢ㄦ埛鍚楋紵')
+        .then(function () {
+          return changeUserStatus(row.userId, row.status);
+        })
+        .then(() => {
+          this.$modal.msgSuccess(text + "鎴愬姛");
+        })
+        .catch(function () {
+          row.status = row.status === "0" ? "1" : "0";
+        });
+    },
+
+    // 琛ㄥ崟閲嶇疆
+    reset() {
+      this.form = {
+        userId: undefined,
+        deptId: undefined,
+        userName: undefined,
+        nickName: undefined,
+        password: undefined,
+        phonenumber: undefined,
+        email: undefined,
+        sex: undefined,
+        status: "0",
+        remark: undefined,
+        postIds: [],
+        roleIds: [],
+      };
+      this.resetForm("form");
+    },
+    /** 鎼滅储鎸夐挳鎿嶄綔 */
+    handleQuery(refresh) {
+      if (this.topqueryParams.searchscope == 3) {
+        this.topqueryParams.visitDeptCodes = store.getters.belongDepts.map(
+          (obj) => obj.deptCode
+        );
+        this.topqueryParams.leaveldeptcodes = store.getters.belongDepts.map(
+          (obj) => obj.deptCode
+        );
+        this.topqueryParams.leavehospitaldistrictcodes =
+          store.getters.belongWards.map((obj) => obj.districtCode);
+      }
+      this.topqueryParams.pageNum = 1;
+      this.topqueryParams.startOutHospTime = this.dateRange[0];
+      this.topqueryParams.endOutHospTime = this.dateRange[1];
+      this.topqueryParams.startSendDateTime = this.dateRangefs[0];
+      this.topqueryParams.endSendDateTime = this.dateRangefs[1];
+      console.log("2");
+      this.getList(refresh);
+    },
+    // 鎮h�呰寖鍥村鐞�
+    handleChange(value) {
+      let type = value[0];
+      let code = value.slice(-1)[0];
+      this.topqueryParams.leavehospitaldistrictcodes = [];
+      this.topqueryParams.visitDeptCodes = [];
+      this.topqueryParams.leaveldeptcodes = [];
+      if (type == 1) {
+        this.topqueryParams.visitDeptCodes.push(code);
+        this.topqueryParams.leaveldeptcodes.push(code);
+        this.topqueryParams.leavehospitaldistrictcodes = [];
+        this.topqueryParams.searchscope = 1;
+      } else if (type == 2) {
+        this.topqueryParams.leavehospitaldistrictcodes.push(code);
+        this.topqueryParams.visitDeptCodes = [];
+        this.topqueryParams.leaveldeptcodes = [];
+        this.topqueryParams.searchscope = 2;
+      } else {
+        this.topqueryParams.searchscope = 3;
+      }
+    },
+    /** 閲嶇疆鎸夐挳鎿嶄綔 */
+    resetQuery() {
+      this.dateRange = [];
+      this.dateRangefs = [];
+      this.topqueryParams = {
+        pageNum: 1,
+        pageSize: 10,
+        sendstate: 2,
+        sort: 2, //0 寤剁画鎶ょ悊鏃堕棿(姝e簭)    1 寤剁画鎶ょ悊鏃堕棿(鍊掑簭)   2 鍙戦�佹椂闂�(姝e簭)    3 鍙戦�佹椂闂�(鍊掑簭)
+        serviceType: 3,
+        searchscope: 3,
+        visitCount: 2,
+        scopetype: [],
+        visitDeptCodes: [],
+        leaveldeptcodes:[],
+        leavehospitaldistrictcodes: [],
+      };
+      this.handleQuery(1);
+    },
+    // 澶氶�夋閫変腑鏁版嵁
+    handleSelectionChange(selection) {
+      this.ids = selection.map((item) => item.userId);
+      this.single = selection.length != 1;
+      this.multiple = !selection.length;
+    },
+    //鍒犻櫎閫夐」
+    handleClose(tag) {
+      this.dynamicTags.splice(this.dynamicTags.indexOf(tag), 1);
+    },
+    //瑙﹀彂鏂板杈撳叆
+    showInput() {
+      this.inputVisible = true;
+      this.$nextTick((_) => {
+        this.$refs.saveTagInput.$refs.input.focus();
+      });
+    },
+    //鑾峰彇澶卞幓鐒︾偣瑙﹀彂
+    handleInputConfirm() {
+      let inputValue = this.inputValue;
+      if (inputValue) {
+        this.dynamicTags.push(inputValue);
+      }
+      this.inputVisible = false;
+      this.inputValue = "";
+    },
+    /** 鏂板鎸夐挳鎿嶄綔 */
+    handleAdd() {
+      this.$router.push({
+        path: "/followvisit/QuestionnaireTask",
+        query: {
+          type: 2,
+          serviceType: 3,
+        },
+      });
+    },
+    //鎮h��360璺宠浆
+    gettoken360(sfzh, drcode, drname) {
+      // // this.$modal.msgWarning('360鍔熻兘鏆傛湭寮�閫�');
+
+      this.postData.YeWuXX.BingRenXX.ZhengJianHM = sfzh;
+
+      query360PatInfo(this.postData).then((res) => {
+        if (res.data.url) {
+          window.open(res.data.url, "_blank");
+          // this.linkUrl = res.data.url;
+        } else {
+          this.$modal.msgWarning("360鏌ヨ鏃犵粨鏋�");
+        }
+      });
+    },
+
+    /** 閲嶇疆瀵嗙爜鎸夐挳鎿嶄綔 */
+    handleResetPwd(row) {
+      this.$prompt('璇疯緭鍏�"' + row.userName + '"鐨勬柊瀵嗙爜', "鎻愮ず", {
+        confirmButtonText: "纭畾",
+        cancelButtonText: "鍙栨秷",
+        closeOnClickModal: false,
+        inputPattern: /^.{5,20}$/,
+        inputErrorMessage: "鐢ㄦ埛瀵嗙爜闀垮害蹇呴』浠嬩簬 5 鍜� 20 涔嬮棿",
+      })
+        .then(({ value }) => {
+          resetUserPwd(row.userId, value).then((response) => {
+            this.$modal.msgSuccess("淇敼鎴愬姛锛屾柊瀵嗙爜鏄細" + value);
+          });
+        })
+        .catch(() => {});
+    },
+    // 鍙栨秷鎸夐挳
+    cancel() {
+      this.Labelchange = false;
+      this.reset();
+    },
+    /** 鎻愪氦鎸夐挳 */
+    submitForm: function () {
+      this.$refs["form"].validate((valid) => {
+        if (valid) {
+          this.form.isoperation = 2;
+          this.form.notrequiredFlag = 1;
+          alterpatient(this.form)
+            .then((response) => {
+              console.log(response);
+            })
+              .then(() => {
+              this.getList(1);
+              this.$modal.msgSuccess("鎮h�呰繃婊ゆ垚鍔�");
+            });
+
+          this.reset();
+          this.Labelchange = false;
+        }
+      });
+    },
+    /** 鍒犻櫎鎸夐挳鎿嶄綔 */
+    handleDelete(row) {
+      const userIds = row.userId || this.ids;
+      this.$modal
+        .confirm('鏄惁纭鍒犻櫎鐢ㄦ埛缂栧彿涓�"' + userIds + '"鐨勬暟鎹」锛�')
+        .then(function () {
+          return delUser(userIds);
+        })
+        .then(() => {
+          this.getList(1);
+          this.$modal.msgSuccess("鍒犻櫎鎴愬姛");
+        })
+        .catch(() => {});
+    },
+    // 鍏ㄩ儴鍋滄
+    AllStop() {
+      this.$modal
+        .confirm("鏄惁鍋滄鍏ㄩ儴浠诲姟锛�")
+        .then(function () {
+          return console.log("鍋滄鎴愬姛");
+        })
+        .then(() => {
+          this.getList(1);
+          this.$modal.msgWarning("鍋滄鎴愬姛");
+        })
+        .catch(() => {});
+    },
+    // 鍏ㄩ儴寮�濮�
+    AllStarted() {
+      this.$modal
+        .confirm("鏄惁寮�鍚叏閮ㄤ换鍔★紵")
+        .then(function () {
+          return console.log("寮�鍚垚鍔�");
+        })
+        .then(() => {
+          this.getList(1);
+          this.$modal.msgSuccess("寮�鍚垚鍔�");
+        })
+        .catch(() => {});
+    },
+    // 浠诲姟閲嶇疆
+    TaskReset() {
+      this.$modal
+        .confirm("鏄惁閲嶇疆閫変腑鐨勪换鍔¢」锛�")
+        .then(function () {
+          return console.log("閫変腑鎴愬姛");
+        })
+        .then(() => {
+          this.getList(1);
+          this.$modal.msgSuccess("閲嶇疆鎴愬姛");
+        })
+        .catch(() => {});
+    },
+    // 璁剧疆鍙戦�佹椂闂�
+    Sendtimesetting() {
+      this.modificationVisible = true;
+    },
+    // 璺宠浆璇︽儏椤�
+    Seedetails(row) {
+    let type = "";
+      console.log(row, "rwo");
+        if (row.type == 1) {
+          type = 1;
+        }
+      this.$router.push({
+        path: "/followvisit/record/detailpage/",
+        query: {
+          taskid: row.taskid,
+          patid: row.patid,
+          id: row.id,
+          Voicetype: type,
+          visitCount: this.topqueryParams.visitCount,
+        },
+      });
+    },
+    // 鍐嶆闅忚
+    followupvisit(row) {
+      this.zcform = row;
+      this.zcform.endtime = this.formatTime(this.zcform.endtime);
+      this.dialogFormVisible = true;
+    },
+    onSubmit() {},
+    // 鏆傚仠鏈嶅姟
+    handlestop(row) {
+      let objson = row;
+      this.$modal
+        .confirm(
+          '鏄惁纭鏆傚仠浠诲姟鍚嶇О涓�"' +
+            row.taskName +
+            '鎮h�呭悕绉颁负"' +
+            row.sendname +
+            '"鐨勬暟鎹」锛�'
+        )
+        .then(() => {
+          getTaskservelist({
+            patid: row.patid,
+            taskid: row.taskid,
+          }).then((res) => {
+            if (res.code == 200) {
+              objson.sendstate = 4;
+              objson.remark = "鏈嶅姟鏆傚仠";
+              Editsingletaskson(objson).then((res) => {
+                if (res.code) {
+                  this.$modal.msgSuccess("璁板綍鎴愬姛");
+                  this.getList(1);
+                }
+              });
+            }
+          });
+        })
+        .catch(() => {});
+    },
+    // 鎮h�呰繃婊よЕ鍙�
+    handleUpdate(row) {
+      particularpatient(row.patid).then((response) => {
+        this.form = response.data;
+        this.form.filterDrname = store.getters.nickName;
+      });
+      this.amendtag = true;
+      this.Labelchange = true;
+    },
+    // 渚挎嵎鎸夐挳
+    toleadExport(too) {
+      if (too == 1) {
+        this.topqueryParams.sendstate = 4;
+        this.topqueryParams.excep = null;
+      } else if (too == 2) {
+        this.topqueryParams.excep = 1;
+      }
+      this.handleQuery();
+    },
+    /** 瀵煎嚭鎸夐挳鎿嶄綔 */
+    handleExport() {
+      this.topqueryParams.pageNum = null;
+      this.topqueryParams.pageSize = null;
+      this.download(
+        "smartor/serviceSubtask/patItemExport",
+        {
+          ...this.topqueryParams,
+        },
+        `user_${new Date().getTime()}.xlsx`
+      );
+    },
+    // 寮傚父鍒楁覆鏌�
+    tableRowClassName({ row, rowIndex }) {
+      if (row.excep == 1) {
+        return "warning-row";
+      }
+      return "";
+    },
+    // 鍒涘缓鍐嶆闅忚鏈嶅姟
+    setupsubtask() {
+      this.$refs["zcform"].validate((valid) => {
+        if (valid) {
+          this.zcform.remark =
+            this.zcform.remark + "銆�" + this.getCurrentTime() + "銆�";
+          let form = structuredClone(this.zcform);
+          form.visitTime = this.formatTime(form.date1);
+          form.finishtime = "";
+          if (form.resource) {
+            if (form.resource == 2) {
+              form.serviceType = 13;
+            }
+          } else {
+            this.$modal.msgError("鏈�夋嫨闅忚鏂瑰紡");
+          }
+          form.id = null;
+          form.sendstate = 2;
+          form.preachform = form.preachformson;
+          form.longTask = 0;
+          addserviceSubtask(form).then((res) => {
+            if (res.code == 200) {
+              this.$modal.msgSuccess("鍒涘缓鎴愬姛");
+            } else {
+              this.$modal.msgError("鍒涘缓澶辫触");
+            }
+            this.dialogFormVisible = false;
+          });
+        }
+      });
+    },
+    getCurrentTime() {
+      const now = new Date();
+      const year = now.getFullYear();
+      const month = String(now.getMonth() + 1).padStart(2, "0");
+      const day = String(now.getDate()).padStart(2, "0");
+      const hours = String(now.getHours()).padStart(2, "0");
+      const minutes = String(now.getMinutes()).padStart(2, "0");
+      const seconds = String(now.getSeconds()).padStart(2, "0");
+
+      return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
+    },
+  },
+};
+</script>
+
+<style lang="scss" scoped>
+.el-button--primary.is-plain {
+  color: #ffffff;
+  background: #409eff;
+  border-color: #4fabe9;
+}
+
+.document {
+  // width: 100px;
+  height: 50px;
+}
+::v-deep.el-table .warning-row {
+  background: #eec4c4;
+}
+
+.documentf {
+  display: flex;
+  justify-content: flex-end;
+}
+
+.download {
+  text-align: center;
+
+  .el-upload__tip {
+    font-size: 23px;
+  }
+
+  .el-upload__text {
+    font-size: 23px;
+  }
+}
+
+.uploading {
+  margin-top: 20px;
+  margin: 20px;
+  padding: 30px;
+  background: #ffffff;
+  border: 1px solid #dcdfe6;
+  -webkit-box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.12),
+    0 0 6px 0 rgba(0, 0, 0, 0.04);
+}
+
+.el-tag + .el-tag {
+  margin-left: 10px;
+}
+
+.button-new-tag {
+  margin-left: 10px;
+  height: 32px;
+  line-height: 30px;
+  padding-top: 0;
+  padding-bottom: 0;
+}
+
+.input-new-tag {
+  width: 90px;
+  margin-left: 10px;
+  vertical-align: bottom;
+}
+
+.drexamine {
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  padding: 30px;
+  background: #daeaf5;
+
+  img {
+    width: 100px;
+    height: 100px;
+  }
+}
+
+.qrcode-dialo {
+  // text-align: center;
+  //   display: flex;
+  margin: 20px;
+  padding: 30px;
+  background: #edf1f7;
+  border: 1px solid #dcdfe6;
+  -webkit-box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.12),
+    0 0 6px 0 rgba(0, 0, 0, 0.04);
+
+  .topic-dev {
+    margin-bottom: 25px;
+    font-size: 20px !important;
+
+    .dev-text {
+      margin-bottom: 10px;
+    }
+  }
+}
+::v-deep.leftvlue .el-card__body {
+  background: #F2F8FF;
+  color: #324A9B;
+}
+::v-deep.leftvlue .el-card__body:hover {
+  background: #3664D9;
+  color: #fff;
+  cursor: pointer; /* 榧犳爣鎮诞鏃跺彉涓烘墜褰� */
+}
+::v-deep.errleftvlue .el-card__body {
+  background: #fdd0d7;
+}
+::v-deep.errleftvlue .el-card__body:hover {
+  background: #f88d96;
+  cursor: pointer; /* 榧犳爣鎮诞鏃跺彉涓烘墜褰� */
+}
+
+::v-deep.ysfleftvlue .el-card__body {
+  background: #d0fdd8;
+}
+::v-deep.ysfleftvlue .el-card__body:hover {
+  background: #8df8a4;
+  cursor: pointer; /* 榧犳爣鎮诞鏃跺彉涓烘墜褰� */
+}
+.button-bb {
+  font-weight: 500;
+  background-color: #2ba05c;
+  padding: 5px;
+  border-radius: 1px;
+  color: #ffffff;
+}
+.button-xq {
+  font-weight: 500;
+  background-color: #409eff;
+  padding: 5px;
+  border-radius: 1px;
+  color: #ffffff;
+}
+.button-sc {
+  font-weight: 500;
+  background-color: #b3a21f;
+  padding: 5px;
+  border-radius: 1px;
+  color: #ffffff;
+}
+.button-zx {
+  background: #4fabe9;
+  padding: 5px;
+  border-radius: 1px;
+  color: #ffffff;
+}
+.button-textxga {
+  color: #de7897;
+}
+::v-deep.el-radio-group {
+  span {
+    font-size: 24px;
+  }
+}
+
+// 閫夐」瀛椾綋鏀惧ぇ
+// ::v-deep.el-checkbox-group {
+//   span {
+//     font-size: 24px;
+//   }
+// }
+</style>
diff --git a/src/views/followvisit/again/index.vue b/src/views/followvisit/again/index.vue
index a6aed6b..5a959d1 100644
--- a/src/views/followvisit/again/index.vue
+++ b/src/views/followvisit/again/index.vue
@@ -325,9 +325,14 @@
                   >鍙戦�佸け璐�</el-tag
                 >
               </div>
-              <div v-if="scope.row.sendstate == 6">
+            <div v-if="scope.row.sendstate == 6">
                 <el-tag type="success" :disable-transitions="false"
                   >宸插畬鎴�</el-tag
+                >
+              </div>
+              <div v-if="scope.row.sendstate == 7">
+                <el-tag type="danger" :disable-transitions="false"
+                  >瓒呮椂</el-tag
                 >
               </div>
             </el-tooltip>
@@ -382,11 +387,11 @@
           label="搴旈殢璁挎棩鏈�"
           width="200"
           align="center"
-          key="longSendTime"
-          prop="longSendTime"
+          key="visitTime"
+          prop="visitTime"
         >
           <template slot-scope="scope">
-            <span>{{ formatTime(scope.row.longSendTime) }}</span>
+            <span>{{ formatTime(scope.row.visitTime) }}</span>
           </template></el-table-column
         >
         <el-table-column
@@ -1003,7 +1008,7 @@
         visitCount: 2,
         scopetype: [],
         visitDeptCodes: [],
-        leaveldeptcodes:[],
+        // leaveldeptcodes:[],
         leavehospitaldistrictcodes: [],
       },
       propss: { multiple: true },
@@ -1030,13 +1035,17 @@
           value: 4,
           label: "涓嶆墽琛�",
         },
-        {
+         {
           value: 5,
           label: "鍙戦�佸け璐�",
         },
         {
           value: 6,
           label: "宸插畬鎴�",
+        },
+         {
+          value: 7,
+          label: "瓒呮椂",
         },
       ],
       sextype: [
@@ -1142,9 +1151,9 @@
         this.topqueryParams.visitDeptCodes = store.getters.belongDepts.map(
           (obj) => obj.deptCode
         );
-        this.topqueryParams.leaveldeptcodes = store.getters.belongDepts.map(
-          (obj) => obj.deptCode
-        );
+        // this.topqueryParams.leaveldeptcodes = store.getters.belongDepts.map(
+        //   (obj) => obj.deptCode
+        // );
         this.topqueryParams.leavehospitaldistrictcodes =
           store.getters.belongWards.map((obj) => obj.districtCode);
       }
@@ -1158,9 +1167,9 @@
       this.loading = true;
       if (
         this.topqueryParams.leavehospitaldistrictcodes[0] &&
-        this.topqueryParams.visitDeptCodes[0]&&this.topqueryParams.leaveldeptcodes[0]
+        this.topqueryParams.visitDeptCodes[0]
       ) {
-        this.topqueryParams.deptOrDistrict = 2;
+        this.topqueryParams.deptOrDistrict = 4;
       } else {
         this.topqueryParams.deptOrDistrict = 1;
       }
@@ -1223,9 +1232,9 @@
         this.topqueryParams.visitDeptCodes = store.getters.belongDepts.map(
           (obj) => obj.deptCode
         );
-          this.topqueryParams.leaveldeptcodes = store.getters.belongDepts.map(
-          (obj) => obj.deptCode
-        );
+        //   this.topqueryParams.leaveldeptcodes = store.getters.belongDepts.map(
+        //   (obj) => obj.deptCode
+        // );
         this.topqueryParams.leavehospitaldistrictcodes =
           store.getters.belongWards.map((obj) => obj.districtCode);
       }
@@ -1242,7 +1251,7 @@
           this.topqueryParams.leavehospitaldistrictcodes,
         sendstates: [2, 3],
         visitDeptCodes: this.topqueryParams.visitDeptCodes,
-        leaveldeptcodes: this.topqueryParams.leaveldeptcodes,
+        // leaveldeptcodes: this.topqueryParams.leaveldeptcodes,
       };
       buidegetTasklist(obj).then((response) => {
         this.userList = response.rows[0].serviceSubtaskList;
@@ -1342,9 +1351,9 @@
         this.topqueryParams.visitDeptCodes = store.getters.belongDepts.map(
           (obj) => obj.deptCode
         );
-        this.topqueryParams.leaveldeptcodes = store.getters.belongDepts.map(
-          (obj) => obj.deptCode
-        );
+        // this.topqueryParams.leaveldeptcodes = store.getters.belongDepts.map(
+        //   (obj) => obj.deptCode
+        // );
         this.topqueryParams.leavehospitaldistrictcodes =
           store.getters.belongWards.map((obj) => obj.districtCode);
       }
@@ -1362,16 +1371,16 @@
       let code = value.slice(-1)[0];
       this.topqueryParams.leavehospitaldistrictcodes = [];
       this.topqueryParams.visitDeptCodes = [];
-      this.topqueryParams.leaveldeptcodes = [];
+      // this.topqueryParams.leaveldeptcodes = [];
       if (type == 1) {
         this.topqueryParams.visitDeptCodes.push(code);
-        this.topqueryParams.leaveldeptcodes.push(code);
+        // this.topqueryParams.leaveldeptcodes.push(code);
         this.topqueryParams.leavehospitaldistrictcodes = [];
         this.topqueryParams.searchscope = 1;
       } else if (type == 2) {
         this.topqueryParams.leavehospitaldistrictcodes.push(code);
         this.topqueryParams.visitDeptCodes = [];
-        this.topqueryParams.leaveldeptcodes = [];
+        // this.topqueryParams.leaveldeptcodes = [];
         this.topqueryParams.searchscope = 2;
       } else {
         this.topqueryParams.searchscope = 3;
@@ -1391,7 +1400,7 @@
         visitCount: 2,
         scopetype: [],
         visitDeptCodes: [],
-        leaveldeptcodes:[],
+        // leaveldeptcodes:[],
         leavehospitaldistrictcodes: [],
       };
       this.handleQuery(1);
@@ -1646,7 +1655,7 @@
           this.zcform.remark =
             this.zcform.remark + "銆�" + this.getCurrentTime() + "銆�";
           let form = structuredClone(this.zcform);
-          form.longSendTime = this.formatTime(form.date1);
+          form.visitTime = this.formatTime(form.date1);
           form.finishtime = "";
           if (form.resource) {
             if (form.resource == 2) {
diff --git a/src/views/followvisit/complaint/index.vue b/src/views/followvisit/complaint/index.vue
index 116f649..9a05c21 100644
--- a/src/views/followvisit/complaint/index.vue
+++ b/src/views/followvisit/complaint/index.vue
@@ -335,9 +335,14 @@
                   >鍙戦�佸け璐�</el-tag
                 >
               </div>
-              <div v-if="scope.row.sendstate == 6">
+            <div v-if="scope.row.sendstate == 6">
                 <el-tag type="success" :disable-transitions="false"
                   >宸插畬鎴�</el-tag
+                >
+              </div>
+              <div v-if="scope.row.sendstate == 7">
+                <el-tag type="danger" :disable-transitions="false"
+                  >瓒呮椂</el-tag
                 >
               </div>
             </el-tooltip>
@@ -1123,7 +1128,7 @@
           value: 4,
           label: "涓嶆墽琛�",
         },
-        {
+         {
           value: 5,
           label: "鍙戦�佸け璐�",
         },
@@ -1131,6 +1136,10 @@
           value: 6,
           label: "宸插畬鎴�",
         },
+         {
+          value: 7,
+          label: "瓒呮椂",
+        },
       ],
       sextype: [
         {
diff --git a/src/views/followvisit/discharge/index.vue b/src/views/followvisit/discharge/index.vue
index b2cd766..f4d568f 100644
--- a/src/views/followvisit/discharge/index.vue
+++ b/src/views/followvisit/discharge/index.vue
@@ -60,6 +60,25 @@
             </el-card>
           </div>
         </el-col>
+        <el-col :span="2.5" v-if="orgname == '鐪佺珛鍚屽痉缈犺嫅闄㈠尯'">
+          <div class="jgleftvlue">
+            <el-card shadow="hover ">
+              <div style="padding: 8px">
+                <span>璀﹀憡</span>
+                <div
+                  style="
+                    text-align: center;
+                    font-size: 18px;
+                    margin-top: 10px;
+                    font-weight: 600;
+                  "
+                >
+                  {{ jgvalue }}
+                </div>
+              </div>
+            </el-card>
+          </div>
+        </el-col>
       </el-row>
     </div>
     <el-row :gutter="20">
@@ -274,7 +293,7 @@
             </div>
           </div>
         </el-col>
-        <el-col :span="1.5">
+        <el-col :span="1.5" v-if="orgname == '鏅畞鐣叉棌鑷不鍘夸汉姘戝尰闄�'">
           <div class="documentf">
             <div class="document">
               <el-tooltip
@@ -386,6 +405,11 @@
                   >宸插畬鎴�</el-tag
                 >
               </div>
+              <div v-if="scope.row.sendstate == 7">
+                <el-tag type="danger" :disable-transitions="false"
+                  >瓒呮椂</el-tag
+                >
+              </div>
             </el-tooltip>
           </template>
         </el-table-column>
@@ -438,13 +462,14 @@
           label="搴旈殢璁挎棩鏈�"
           width="200"
           align="center"
-          key="longSendTime"
-          prop="longSendTime"
+          key="visitTime"
+          prop="visitTime"
         >
           <template slot-scope="scope">
-            <span>{{ formatTime(scope.row.longSendTime) }}</span>
+            <span>{{ formatTime(scope.row.visitTime) }}</span>
           </template></el-table-column
         >
+        <!-- 鍘� -->
         <el-table-column
           label="涓绘不鍖荤敓"
           width="120"
@@ -1107,6 +1132,7 @@
       inputVisible: false,
       Labelchange: false,
       ycvalue: "",
+      jgvalue: "",
       yfsvalue: "",
       inputValue: "",
       preachform: "",
@@ -1224,12 +1250,17 @@
           value: 8,
           label: "搴旈殢璁挎棩鏈�(鍊掑簭)",
         },
+         {
+          value: 9,
+          label: "鎸夌収鎮h�呮帓搴�",
+        },
       ],
       // 鏌ヨ鍙傛暟
       topqueryParams: {
         pageNum: 1,
         pageSize: 10,
-        sendstate: 2,
+        sendstate:
+          localStorage.getItem("orgname") == "鐪佺珛鍚屽痉缈犺嫅闄㈠尯" ? null : 2,
         sort: localStorage.getItem("orgname") == "涓芥按甯備腑鍖婚櫌" ? 8 : 2, //0 鍑洪櫌鏃堕棿(姝e簭)    1 鍑洪櫌鏃堕棿(鍊掑簭)   2 鍙戦�佹椂闂�(姝e簭)    3 鍙戦�佹椂闂�(鍊掑簭)  7搴旈殢璁挎棩鏈�(鍊掑簭) 搴旈殢璁挎棩鏈�(姝e簭)
         serviceType: 2,
         searchscope: 3,
@@ -1271,6 +1302,10 @@
           value: 6,
           label: "宸插畬鎴�",
         },
+         {
+          value: 7,
+          label: "瓒呮椂",
+        },
       ],
       sextype: [
         {
@@ -1287,7 +1322,7 @@
           value: 1,
           label: "寮傚父",
         },
-         {
+        {
           value: 2,
           label: "璀﹀憡",
         },
@@ -1339,12 +1374,25 @@
       rules: {},
     };
   },
-  watch: {},
+  watch: {
+    // 鐩戝惉璺敱鍙傛暟鍙樺寲
+    "$route.query": {
+      handler(newQuery, oldQuery) {
+        if (newQuery.errtype !== oldQuery.errtype) {
+          console.log(22);
+
+          this.loadData(); // 閲嶆柊鍔犺浇鏁版嵁
+        }
+      },
+      immediate: true,
+    },
+  },
   created() {
     this.serviceState = store.getters.serviceState;
     this.checkboxlist = store.getters.checkboxlist;
-    this.errtype = this.$route.query.errtype;
     this.orgname = localStorage.getItem("orgname");
+    this.errtype = this.$route.query.errtype;
+
     this.leavehospitaldistrictcode =
       this.$route.query.leavehospitaldistrictcode;
     this.sourcetype[0].children = store.getters.belongDepts.map((dept) => {
@@ -1359,8 +1407,20 @@
         value: dept.districtCode,
       };
     });
-    if (this.errtype) {
+    if (this.errtype == 1) {
       this.toleadExport(2);
+    } else if (this.errtype == 2) {
+      // 寰呴殢璁�
+      this.toleadExport(3);
+    } else if (this.errtype == 3) {
+      // 澶辫触
+      this.toleadExport(4);
+    } else if (this.errtype == 4) {
+      // 寮傚父
+      this.toleadExport(2);
+    } else if (this.errtype == 5) {
+      // 鍏ㄩ儴
+      this.toleadExport(5);
     } else {
       this.getList(1);
     }
@@ -1369,7 +1429,24 @@
     });
   },
   activated() {
-    this.getList(1);
+    this.errtype = this.$route.query.errtype;
+    if (this.errtype == 1) {
+      this.toleadExport(2);
+    } else if (this.errtype == 2) {
+      // 寰呴殢璁�
+      this.toleadExport(3);
+    } else if (this.errtype == 3) {
+      // 澶辫触
+      this.toleadExport(4);
+    } else if (this.errtype == 4) {
+      // 寮傚父
+      this.toleadExport(2);
+    } else if (this.errtype == 5) {
+      // 鍏ㄩ儴
+      this.toleadExport(5);
+    } else {
+      this.getList(1);
+    }
   },
   methods: {
     /** 鏌ヨ闅忚鏈嶅姟鍒楄〃 */
@@ -1394,7 +1471,6 @@
         this.topqueryParams.leavehospitaldistrictcodes.push(
           this.leavehospitaldistrictcode
         );
-        console.log(this.topqueryParams.leavehospitaldistrictcodes, "11");
       }
       this.loading = true;
       if (
@@ -1410,10 +1486,13 @@
         this.total = response.total;
         if (refresh) {
           this.cardlist[0].value =
-            Number(response.rows[0].wzx) + Number(response.rows[0].ysf);
+            Number(response.rows[0].wzx) +
+            Number(response.rows[0].ysf) +
+            Number(response.rows[0].fssb);
           // this.cardlist[1].value = response.rows[0].wzx;
           this.cardlist[1].value = response.rows[0].ysf;
           this.ycvalue = response.rows[0].yc;
+          this.jgvalue = response.rows[0].jg;
           this.cardlist[2].value = response.rows[0].fssb;
           this.cardlist[3].value = response.rows[0].dsf;
           // this.cardlist[4].value = response.rows[0].yfs2;
@@ -1444,6 +1523,26 @@
         });
         this.total = response.total;
       });
+    },
+    loadData() {
+      this.errtype = this.$route.query.errtype;
+      if (this.errtype == 1) {
+        this.toleadExport(2);
+      } else if (this.errtype == 2) {
+        // 寰呴殢璁�
+        this.toleadExport(3);
+      } else if (this.errtype == 3) {
+        // 澶辫触
+        this.toleadExport(4);
+      } else if (this.errtype == 4) {
+        // 寮傚父
+        this.toleadExport(2);
+      } else if (this.errtype == 5) {
+        // 鍏ㄩ儴
+        this.toleadExport(5);
+      } else {
+        this.getList(1);
+      }
     },
     // 鏃堕棿
     getEndOfDay() {
@@ -1499,17 +1598,16 @@
       buidegetTasklist(obj).then((response) => {
         this.userList = response.rows[0].serviceSubtaskList;
         this.total = response.total;
-        if (refresh) {
-          this.cardlist[0].value =
-            Number(response.rows[0].wzx) + Number(response.rows[0].ysf);
-          this.cardlist[1].value = response.rows[0].wzx;
-          this.cardlist[2].value = response.rows[0].ysf;
-          this.ycvalue = response.rows[0].yc;
-          this.cardlist[3].value = response.rows[0].fssb;
-          this.cardlist[4].value = response.rows[0].dsf;
-          // this.cardlist[5].value = response.rows[0].yfs2;
-          this.yfsvalue = response.rows[0].yfs;
-        }
+        this.cardlist[0].value =
+          Number(response.rows[0].wzx) + Number(response.rows[0].ysf);
+        this.cardlist[1].value = response.rows[0].wzx;
+        this.cardlist[2].value = response.rows[0].ysf;
+        this.ycvalue = response.rows[0].yc;
+        this.jgvalue = response.rows[0].jg;
+        this.cardlist[3].value = response.rows[0].fssb;
+        this.cardlist[4].value = response.rows[0].dsf;
+        // this.cardlist[5].value = response.rows[0].yfs2;
+        this.yfsvalue = response.rows[0].yfs;
         this.loading = false;
         this.userList.forEach((item) => {
           let idArray = null;
@@ -1598,10 +1696,13 @@
           store.getters.belongWards.map((obj) => obj.districtCode);
       }
       this.topqueryParams.pageNum = 1;
-      this.topqueryParams.startOutHospTime = this.dateRange[0];
-      this.topqueryParams.endOutHospTime = this.dateRange[1];
-      this.topqueryParams.startSendDateTime = this.dateRangefs[0];
-      this.topqueryParams.endSendDateTime = this.dateRangefs[1];
+      // 鍒ゆ柇鏄笉鏄伐浣滃彴蹇嵎鏌ヨ
+      if (this.errtype != 2) {
+        this.topqueryParams.startOutHospTime = this.dateRange[0];
+        this.topqueryParams.endOutHospTime = this.dateRange[1];
+        this.topqueryParams.startSendDateTime = this.dateRangefs[0];
+        this.topqueryParams.endSendDateTime = this.dateRangefs[1];
+      }
       this.getList(refresh);
     },
     // 鎮h�呰寖鍥村鐞�
@@ -1847,9 +1948,9 @@
     Seedetails(row) {
       let type = "";
       console.log(row, "rwo");
-        if (row.type == 1) {
-          type = 1;
-        }
+      if (row.type == 1) {
+        type = 1;
+      }
       this.$router.push({
         path: "/followvisit/record/detailpage/",
         query: {
@@ -1909,13 +2010,33 @@
     },
     // 渚挎嵎鎸夐挳
     toleadExport(too) {
+      console.log(too, "too");
+
       if (too == 1) {
         this.topqueryParams.sendstate = 4;
         this.topqueryParams.excep = null;
       } else if (too == 2) {
         this.topqueryParams.excep = 1;
+        this.topqueryParams.sendstate = null;
+      } else if (too == 3) {
+        this.topqueryParams.endSendDateTime = this.formatDateToYYYYMMDDHHMMSS(
+          this.getEndOfDay()
+        );
+        console.log(1111, this.topqueryParams.endSendDateTime);
+
+        this.topqueryParams.excep = null;
+        this.topqueryParams.sendstate = 2;
+        this.topqueryParams.scopetype = null;
+      } else if (too == 4) {
+        this.topqueryParams.excep = null;
+        this.topqueryParams.sendstate = 5;
+        this.topqueryParams.scopetype = null;
+      } else if (too == 5) {
+        this.topqueryParams.excep = null;
+        this.topqueryParams.sendstate = null;
+        this.topqueryParams.scopetype = null;
       }
-      this.handleQuery();
+      this.handleQuery(1);
     },
     /** 瀵煎嚭鎸夐挳鎿嶄綔 */
     handleExport() {
@@ -1945,7 +2066,7 @@
           this.zcform.remark =
             this.zcform.remark + "銆�" + this.getCurrentTime() + "銆�";
           let form = structuredClone(this.zcform);
-          form.longSendTime = this.formatTime(form.date1);
+          form.visitTime = this.formatTime(form.date1);
           form.finishtime = "";
           if (form.resource) {
             if (form.resource == 2) {
@@ -2095,6 +2216,10 @@
   background: #f88d96;
   cursor: pointer; /* 榧犳爣鎮诞鏃跺彉涓烘墜褰� */
 }
+::v-deep.jgleftvlue .el-card__body:hover {
+  background: #f7f075;
+  cursor: pointer; /* 榧犳爣鎮诞鏃跺彉涓烘墜褰� */
+}
 
 ::v-deep.ysfleftvlue .el-card__body {
   background: #d0fdd8;
diff --git a/src/views/followvisit/discharge/js/prototype.js b/src/views/followvisit/discharge/js/prototype.js
index 0a83a4b..a02fc31 100644
--- a/src/views/followvisit/discharge/js/prototype.js
+++ b/src/views/followvisit/discharge/js/prototype.js
@@ -4871,4 +4871,4 @@
 
 Object.extend(Element.ClassNames.prototype, Enumerable);
 
-/*--------------------------------------------------------------------------*/
\ No newline at end of file
+/*--------------------------------------------------------------------------*/
diff --git a/src/views/followvisit/discharge/outpatientService.vue b/src/views/followvisit/discharge/outpatientService.vue
index 53a4c79..98e33c4 100644
--- a/src/views/followvisit/discharge/outpatientService.vue
+++ b/src/views/followvisit/discharge/outpatientService.vue
@@ -331,9 +331,14 @@
                   >鍙戦�佸け璐�</el-tag
                 >
               </div>
-              <div v-if="scope.row.sendstate == 6">
+            <div v-if="scope.row.sendstate == 6">
                 <el-tag type="success" :disable-transitions="false"
                   >宸插畬鎴�</el-tag
+                >
+              </div>
+              <div v-if="scope.row.sendstate == 7">
+                <el-tag type="danger" :disable-transitions="false"
+                  >瓒呮椂</el-tag
                 >
               </div>
             </el-tooltip>
@@ -389,11 +394,11 @@
           label="搴旈殢璁挎棩鏈�"
           width="200"
           align="center"
-          key="longSendTime"
-          prop="longSendTime"
+          key="visitTime"
+          prop="visitTime"
         >
           <template slot-scope="scope">
-            <span>{{ formatTime(scope.row.longSendTime) }}</span>
+            <span>{{ formatTime(scope.row.visitTime) }}</span>
           </template></el-table-column
         >
         <el-table-column
@@ -1016,13 +1021,17 @@
           value: 4,
           label: "涓嶆墽琛�",
         },
-        {
+         {
           value: 5,
           label: "鍙戦�佸け璐�",
         },
         {
           value: 6,
           label: "宸插畬鎴�",
+        },
+         {
+          value: 7,
+          label: "瓒呮椂",
         },
       ],
       sextype: [
@@ -1617,7 +1626,7 @@
           this.zcform.remark =
             this.zcform.remark + "銆�" + this.getCurrentTime() + "銆�";
           let form = structuredClone(this.zcform);
-          form.longSendTime = this.formatTime(form.date1);
+          form.visitTime = this.formatTime(form.date1);
           form.finishtime = "";
           if (form.resource) {
             if (form.resource == 2) {
diff --git a/src/views/followvisit/mzsatisfaction/index.vue b/src/views/followvisit/mzsatisfaction/index.vue
index 0fbc077..751fcbe 100644
--- a/src/views/followvisit/mzsatisfaction/index.vue
+++ b/src/views/followvisit/mzsatisfaction/index.vue
@@ -334,9 +334,14 @@
                   >鍙戦�佸け璐�</el-tag
                 >
               </div>
-              <div v-if="scope.row.sendstate == 6">
+            <div v-if="scope.row.sendstate == 6">
                 <el-tag type="success" :disable-transitions="false"
                   >宸插畬鎴�</el-tag
+                >
+              </div>
+              <div v-if="scope.row.sendstate == 7">
+                <el-tag type="danger" :disable-transitions="false"
+                  >瓒呮椂</el-tag
                 >
               </div>
             </el-tooltip>
@@ -1167,7 +1172,7 @@
           value: 4,
           label: "涓嶆墽琛�",
         },
-        {
+         {
           value: 5,
           label: "鍙戦�佸け璐�",
         },
@@ -1175,6 +1180,10 @@
           value: 6,
           label: "宸插畬鎴�",
         },
+         {
+          value: 7,
+          label: "瓒呮椂",
+        },
       ],
       sextype: [
         {
diff --git a/src/views/followvisit/outpatient/index.vue b/src/views/followvisit/outpatient/index.vue
index f253049..e571a3a 100644
--- a/src/views/followvisit/outpatient/index.vue
+++ b/src/views/followvisit/outpatient/index.vue
@@ -334,11 +334,11 @@
           label="搴旈殢璁挎棩鏈�"
           width="200"
           align="center"
-          key="longSendTime"
-          prop="longSendTime"
+          key="visitTime"
+          prop="visitTime"
         >
           <template slot-scope="scope">
-            <span>{{ formatTime(scope.row.longSendTime) }}</span>
+            <span>{{ formatTime(scope.row.visitTime) }}</span>
           </template></el-table-column
         >
         <el-table-column
@@ -803,7 +803,7 @@
           value: 4,
           label: "涓嶆墽琛�",
         },
-        {
+         {
           value: 5,
           label: "鍙戦�佸け璐�",
         },
@@ -811,6 +811,10 @@
           value: 6,
           label: "宸插畬鎴�",
         },
+         {
+          value: 7,
+          label: "瓒呮椂",
+        },
       ],
       topicoptionsyj: [
         {
diff --git a/src/views/followvisit/record/TracingInfo/index.vue b/src/views/followvisit/record/TracingInfo/index.vue
new file mode 100644
index 0000000..90bfb77
--- /dev/null
+++ b/src/views/followvisit/record/TracingInfo/index.vue
@@ -0,0 +1,2971 @@
+<template>
+  <!-- 鑱婅繛椤甸潰璁板綍 -->
+  <div class="Followupdetailspage" id="app-container">
+    <div class="Followuserinfo">
+      <div>
+        <div class="userinfo-text">
+          <!-- <span>鎮h�呮湇鍔¤鎯�</span> -->
+          <div class="headline">
+            <div>鎮h�呮湇鍔¤鎯�</div>
+            <div style="margin-left: 20px">
+              <el-button
+                v-if="!Whetherall"
+                type="primary"
+                @click="getTaskservelist()"
+                >鏌ョ湅鎮h�呭叏閮ㄦ湇鍔�</el-button
+              >
+              <el-button v-else type="success" @click="getTaskservelist(id)"
+                >鍙睍绀烘湰娆℃湇鍔′俊鎭�</el-button
+              >
+            </div>
+            <!-- <div style="margin-left: 20px; color: #59a0f0">
+              <el-link
+                href="https://9.208.2.207:6060/search-homepage"
+                target="_blank"
+                :underline="true"
+              >
+                鍓嶅線CDSS鏌ヨ
+              </el-link>
+            </div> -->
+            <div class="merge-controls" v-if="Whetherall">
+              <el-button
+                type="primary"
+                @click="toggleMergeMode"
+                :disabled="selectedServices.length < 2"
+              >
+                {{ isMergeMode ? "鍙栨秷鍚堝苟" : "鍚堝苟缂栬緫闂嵎" }}
+              </el-button>
+              <el-button
+                v-if="isMergeMode"
+                type="success"
+                @click="openMergeDialog"
+                :disabled="selectedServices.length < 2"
+              >
+                寮�濮嬪悎骞� (宸查�� {{ selectedServices.length }} 涓湇鍔�)
+              </el-button>
+            </div>
+          </div>
+          <!-- <el-button type="success">闅忚鍚庣煭淇�</el-button> -->
+        </div>
+      </div>
+      <div>
+        <el-table
+          :data="logsheetlist"
+          :row-class-name="tableRowClassName"
+          :max-height="350"
+          style="width: 100%"
+          @selection-change="handleSelectionChange"
+        >
+          <el-table-column
+            type="selection"
+            width="55"
+            :selectable="checkSelectable"
+            v-if="Whetherall"
+          ></el-table-column>
+          <el-table-column
+            prop="sendname"
+            align="center"
+            label="濮撳悕"
+            width="100"
+          >
+            <template slot-scope="scope">
+              <el-button
+                size="medium"
+                type="text"
+                @click="
+                  gettoken360(
+                    scope.row.sfzh,
+                    scope.row.drcode,
+                    scope.row.drname
+                  )
+                "
+                ><span class="button-textsc">{{
+                  scope.row.sendname
+                }}</span></el-button
+              >
+            </template>
+          </el-table-column>
+          <el-table-column
+            prop="taskName"
+            align="center"
+            width="200"
+            show-overflow-tooltip
+            label="浠诲姟鍚嶇О"
+          >
+          </el-table-column>
+          <el-table-column
+            prop="sendstate"
+            align="center"
+            width="200"
+            label="浠诲姟鐘舵��"
+          >
+            <template slot-scope="scope">
+              <div v-if="scope.row.sendstate == 1">
+                <el-tag type="primary" :disable-transitions="false"
+                  >琛ㄥ崟宸查鍙�</el-tag
+                >
+              </div>
+              <div v-if="scope.row.sendstate == 2">
+                <el-tag type="primary" :disable-transitions="false"
+                  >寰呴殢璁�</el-tag
+                >
+              </div>
+              <div v-if="scope.row.sendstate == 3">
+                <el-tag type="success" :disable-transitions="false"
+                  >琛ㄥ崟宸插彂閫�</el-tag
+                >
+              </div>
+              <div v-if="scope.row.sendstate == 4">
+                <el-tag type="info" :disable-transitions="false">涓嶆墽琛�</el-tag>
+              </div>
+              <div v-if="scope.row.sendstate == 5">
+                <el-tag type="danger" :disable-transitions="false"
+                  >鍙戦�佸け璐�</el-tag
+                >
+              </div>
+              <div v-if="scope.row.sendstate == 6">
+                <el-tag type="success" :disable-transitions="false"
+                  >宸插畬鎴�</el-tag
+                >
+              </div>
+            </template>
+          </el-table-column>
+          <el-table-column
+            prop="finishtime"
+            align="center"
+            label="闅忚瀹屾垚鏃堕棿"
+            width="200"
+            show-overflow-tooltip
+          >
+          </el-table-column>
+          <el-table-column
+            label="鍑洪櫌鏃ユ湡"
+            width="200"
+            align="center"
+            key="endtime"
+            prop="endtime"
+          >
+            <template slot-scope="scope">
+              <span>{{ formatTime(scope.row.endtime) }}</span>
+            </template></el-table-column
+          >
+          <el-table-column
+            label="璐d换鎶ゅ+"
+            width="120"
+            align="center"
+            key="nurseName"
+            prop="nurseName"
+          />
+          <el-table-column
+            label="涓绘不鍖荤敓"
+            width="120"
+            align="center"
+            key="drname"
+            prop="drname"
+          />
+
+          <el-table-column
+            label="缁撴灉鐘舵��"
+            align="center"
+            key="excep"
+            prop="excep"
+            width="120"
+          >
+            <template slot-scope="scope">
+              <dict-tag
+                :options="dict.type.sys_yujing"
+                :value="scope.row.excep"
+              />
+            </template>
+          </el-table-column>
+          <el-table-column
+            label="澶勭悊鎰忚"
+            align="center"
+            key="suggest"
+            prop="suggest"
+            width="120"
+          >
+            <template slot-scope="scope">
+              <dict-tag
+                :options="dict.type.sys_suggest"
+                :value="scope.row.suggest"
+              />
+            </template>
+          </el-table-column>
+
+          <el-table-column
+            prop="templatename"
+            align="center"
+            label="鏈嶅姟妯℃澘"
+            width="200"
+            show-overflow-tooltip
+          >
+          </el-table-column>
+          <el-table-column
+            prop="remark"
+            align="center"
+            label="鏈嶅姟璁板綍"
+            width="200"
+            show-overflow-tooltip
+          >
+          </el-table-column>
+
+          <el-table-column
+            prop="bankcardno"
+            align="center"
+            label="鍛煎彨鐘舵��"
+            width="210"
+          >
+          </el-table-column>
+          <el-table-column
+            label="鎿嶄綔"
+            fixed="right"
+            align="center"
+            width="200"
+            class-name="small-padding fixed-width"
+          >
+            <template slot-scope="scope">
+              <el-button
+                size="medium"
+                type="text"
+                @click="Seedetails(scope.row)"
+                ><span class="button-zx"
+                  ><i class="el-icon-s-order"></i>鏌ョ湅</span
+                ></el-button
+              >
+            </template>
+          </el-table-column>
+        </el-table>
+      </div>
+    </div>
+
+    <div class="action-container">
+      <!-- 闅忚鍐呭 -->
+      <div class="call-action">
+        <div class="call-container">
+          <!-- <div class="call-header">
+            <h2>涓�閿懠鍙姛鑳�</h2>
+          </div> -->
+
+          <div class="headline">
+            <div>闅忚鍐呭</div>
+          </div>
+          <div>
+            <el-tabs v-model="activeName" type="border-card">
+              <el-tab-pane name="wj">
+                <span class="mulsz" slot="label"
+                  ><i class="el-icon-notebook-1"></i> 闂嵎闅忚缁撴灉</span
+                >
+                <div class="CONTENT">
+                  <div class="title">{{ taskname ? taskname : "闂嵎" }}</div>
+
+                  <div class="preview-left" v-if="!Voicetype">
+                    <div
+                      class="topic-dev"
+                      v-for="(item, index) in tableDatatop"
+                      :key="item.id"
+                    >
+                      <!-- 鍗曢�� -->
+                      <div
+                        :class="getTopicClass(item)"
+                        :key="index"
+                        v-if="item.scriptType == 1 && !item.astrict"
+                      >
+                        <div class="dev-text">
+                          {{ index + 1 }}銆乕鍗曢�塢<span>{{
+                            item.scriptContent
+                          }}</span>
+                        </div>
+                        <div class="dev-xx">
+                          <el-radio-group v-model="item.scriptResult">
+                            <el-radio
+                              v-for="(
+                                items, indexs
+                              ) in item.svyTaskTemplateTargetoptions"
+                              :class="getOptionClass(items)"
+                              :key="indexs"
+                              :label="items.optioncontent"
+                              @click.native.prevent="
+                                handleRadioToggle(
+                                  item,
+                                  index,
+                                  item.svyTaskTemplateTargetoptions,
+                                  items.optioncontent
+                                )
+                              "
+                              >{{ items.optioncontent }}</el-radio
+                            >
+                          </el-radio-group>
+                        </div>
+                        <div
+                          v-if="item.showAppendInput || item.answerps"
+                          class="append-input-container"
+                        >
+                          <el-input
+                            type="textarea"
+                            :rows="2"
+                            placeholder="璇疯緭鍏ュ叿浣撲俊鎭�"
+                            v-model="item.answerps"
+                            clearable
+                          ></el-input>
+                        </div>
+                        <div v-show="item.prompt">
+                          <el-alert :title="item.prompt" type="warning">
+                          </el-alert>
+                        </div>
+                      </div>
+                      <!-- 澶氶�� -->
+                      <div
+                        :class="
+                          item.isabnormal
+                            ? 'scriptTopic-isabnormal'
+                            : 'scriptTopic-dev'
+                        "
+                        :key="index"
+                        v-if="item.scriptType == 2 && !item.astrict"
+                      >
+                        <div class="dev-text">
+                          {{ index + 1 }}銆乕澶氶�塢<span>{{
+                            item.scriptContent
+                          }}</span>
+                        </div>
+                        <div class="dev-xx">
+                          <el-checkbox-group
+                            v-model="item.scriptResult"
+                            @change="updateScore($event, index, item)"
+                          >
+                            <el-checkbox
+                              :class="items.isabnormal ? 'red-star' : ''"
+                              @change="$forceUpdate()"
+                              v-for="(
+                                items, indexs
+                              ) in item.svyTaskTemplateTargetoptions"
+                              :key="indexs"
+                              :label="items.optioncontent"
+                            >
+                              {{ items.optioncontent }}
+                            </el-checkbox>
+                          </el-checkbox-group>
+                        </div>
+                        <div v-show="item.prompt && item.scriptResult[0]">
+                          <el-alert :title="item.prompt" type="warning">
+                          </el-alert>
+                        </div>
+                      </div>
+                      <!-- 濉┖ -->
+                      <div
+                        class="scriptTopic-dev"
+                        :key="index"
+                        v-if="item.scriptType == 4 && !item.astrict"
+                      >
+                        <div class="dev-text">
+                          {{ index + 1 }}銆乕闂瓟]<span>{{
+                            item.scriptContent
+                          }}</span>
+                          <span v-if="item.valueType == 3">(鍙兘杈撳叆鏁板瓧)</span>
+                        </div>
+                        <div class="dev-xx" v-if="item.valueType == 3">
+                          <el-input
+                            type="text"
+                            v-numeric-only
+                            placeholder="璇疯緭鍏ョ瓟妗�"
+                            v-model="item.scriptResult"
+                          >
+                          </el-input>
+                        </div>
+                        <div class="dev-xx" v-else>
+                          <el-input
+                            type="textarea"
+                            :rows="2"
+                            placeholder="璇疯緭鍏ョ瓟妗�"
+                            v-model="item.scriptResult"
+                            clearable
+                          >
+                          </el-input>
+                        </div>
+                      </div>
+                    </div>
+                  </div>
+
+                  <div class="preview-left" v-else>
+                    <div
+                      class="topic-dev"
+                      v-for="(item, index) in tableDatatop"
+                      :key="item.id"
+                    >
+                      <div v-if="item.targetvalue">
+                        <div class="dev-text">
+                          {{ index + 1 }}銆乕鍗曢�塢<span>{{
+                            item.questiontext
+                          }}</span>
+                        </div>
+                        <div class="dev-xx">
+                          <el-radio-group
+                            v-model="item.matchedtext"
+                            @change="
+                              handleOptionChange(
+                                $event,
+                                index,
+                                item.ivrTaskScriptTargetoptionList,
+                                item
+                              )
+                            "
+                          >
+                            <el-radio
+                              v-for="(items, index) in item.scriptResult"
+                              :key="index"
+                              :label="items"
+                              :class="items.isabnormal ? 'red-star' : ''"
+                              >{{ items }}</el-radio
+                            >
+                          </el-radio-group>
+                        </div>
+                        <div v-show="item.prompt">
+                          <el-alert :title="item.prompt" type="warning">
+                          </el-alert>
+                        </div>
+                      </div>
+
+                      <div class="scriptTopic-dev" :key="index" v-else>
+                        <div class="dev-text">
+                          {{ index + 1 }}銆乕闂瓟]<span>{{
+                            item.scriptContent
+                          }}</span>
+                          <span v-if="item.valueType == 3">(鍙兘杈撳叆鏁板瓧)</span>
+                        </div>
+                        <div class="dev-xx" v-if="item.valueType == 3">
+                          <el-input
+                            type="text"
+                            v-numeric-only
+                            placeholder="璇疯緭鍏ョ瓟妗�"
+                            v-model="item.scriptResult"
+                          >
+                          </el-input>
+                        </div>
+                        <div class="dev-xx" v-else>
+                          <el-input
+                            type="textarea"
+                            :rows="2"
+                            placeholder="璇疯緭鍏ョ瓟妗�"
+                            v-model="item.scriptResult"
+                            clearable
+                          >
+                          </el-input>
+                        </div>
+                      </div>
+                    </div>
+                  </div>
+                  <el-button
+                    v-if="Voicetype"
+                    type="primary"
+                    @click="yuyingetdetail"
+                    >淇濆瓨鏈嶅姟璇︽儏</el-button
+                  >
+                  <el-button v-else type="primary" @click="getdetail"
+                    >淇濆瓨鏈嶅姟璇︽儏</el-button
+                  >
+                </div>
+              </el-tab-pane>
+
+              <el-tab-pane name="yy">
+                <span class="mulsz" slot="label"
+                  ><i class="el-icon-headset"></i> 璇煶闅忚璇︽儏</span
+                >
+                <div class="borderdiv">
+                  <div class="title">{{ taskname ? taskname : "闂嵎" }}</div>
+                  <div
+                    style="
+                      display: flex;
+                      text-align: center;
+                      align-items: center;
+                      color: #59a0f0;
+                    "
+                  >
+                    瀹屾暣璇煶锛�
+                    <mini-audio
+                      :audio-source="
+                        voice ? voice : '@assets/order/example.mp3'
+                      "
+                    ></mini-audio>
+                  </div>
+                  <div class="preview-left">
+                    <div v-for="item in voiceDatatop">
+                      <div class="leftside">
+                        <i class="el-icon-phone-outline"></i
+                        ><span>{{ item.questiontext }}</span>
+                      </div>
+                      <div class="offside">
+                        <i class="el-icon-user"></i>
+                        <div class="offside-value">
+                          <el-input
+                            type="textarea"
+                            :autosize="{ minRows: 1 }"
+                            v-model="item.asrtext"
+                          ></el-input>
+
+                          <div>
+                            <mini-audio
+                              :audio-source="
+                                item.questionvoice
+                                  ? item.questionvoice
+                                  : '@assets/order/example.mp3'
+                              "
+                            ></mini-audio>
+                          </div>
+                        </div>
+                      </div>
+                    </div>
+                  </div>
+                  <el-button
+                    v-if="Voicetype"
+                    type="primary"
+                    @click="yuyingetdetail"
+                    >淇濆瓨闅忚璇︽儏</el-button
+                  >
+                  <el-button v-else type="primary" @click="getdetail"
+                    >淇濆瓨闅忚璇︽儏</el-button
+                  >
+                </div>
+              </el-tab-pane>
+            </el-tabs>
+          </div>
+        </div>
+      </div>
+      <!-- 浜哄伐澶勭悊 -->
+      <div class="manual-action">
+        <div class="Followuserinfos">
+          <div>
+            <el-form
+              ref="userform"
+              :model="form"
+              :rules="userrules"
+              label-width="120px"
+            >
+              <div class="headline">
+                <div>浜哄伐澶勭悊</div>
+                <div style="margin: 0 30px">
+                  <el-button
+                    type="primary"
+                    plain
+                    @click="Editsingletasksonyic('')"
+                    >淇濆瓨鍩虹淇℃伅</el-button
+                  >
+                </div>
+                <div>
+                  <el-button
+                    type="primary"
+                    round
+                    v-if="this.form.isVisitAgain != 2"
+                    @click="sendAgain()"
+                    >鍐嶆闅忚</el-button
+                  >
+                </div>
+                <div class="tag-selector-container">
+                  <el-select
+                    v-model="selectedTag"
+                    placeholder="璇烽�夋嫨寮傚父鐘舵��"
+                    clearable
+                    style="width: 150px; margin-right: 10px"
+                  >
+                    <el-option
+                      v-for="item in tagOptions"
+                      :key="item.value"
+                      :label="item.label"
+                      :value="item.value"
+                    >
+                      <span style="display: flex; align-items: center">
+                        <span
+                          class="color-indicator"
+                          :style="{ backgroundColor: item.color }"
+                        ></span>
+                        <span>{{ item.label }}</span>
+                      </span>
+                    </el-option>
+                  </el-select>
+
+                  <!-- 褰撳墠閫夋嫨鐨勯鑹叉寚绀哄櫒 -->
+                  <div
+                    v-if="selectedTag"
+                    class="color-indicator selected-indicator"
+                    :style="{ backgroundColor: getSelectedTagColor() }"
+                  ></div>
+
+                  <!-- 鏍囪璇存槑鎻愮ず -->
+                  <el-tooltip
+                    v-if="selectedTag"
+                    effect="light"
+                    :content="getSelectedDescription()"
+                    placement="top"
+                  >
+                    <i class="el-icon-info tag-info-icon"></i>
+                  </el-tooltip>
+                </div>
+              </div>
+              <el-row>
+                <el-col :span="14"
+                  ><el-form-item label="鑱旂郴鐢佃瘽">
+                    <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-row>
+              <el-row>
+                <el-col :span="14"
+                  ><el-form-item label="鑱旂郴浜虹數璇�">
+                    <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="10"
+                  ><el-form-item label="鑱旂郴浜哄叧绯�">
+                    <el-input
+                      placeholder="鑱旂郴浜哄叧绯荤己澶�"
+                      v-model="userform.relation"
+                    ></el-input> </el-form-item
+                ></el-col>
+              </el-row>
+              <div class="call-controls">
+                <CallButton
+                  ref="callButton"
+                  :phoneNumber="currentPhoneNumber"
+                  style="display: none"
+                />
+
+                <div v-if="callStatus === 'connected'" class="hangup-btn">
+                  <el-button
+                    type="danger"
+                    icon="el-icon-phone"
+                    @click="endCurrentCall"
+                    :loading="isEndingCall"
+                  >
+                    鎸傛柇鐢佃瘽
+                  </el-button>
+                </div>
+                <div class="call-status" v-if="callStatus !== 'idle'">
+                  <el-alert
+                    :title="callStatusText"
+                    :type="callStatusType"
+                    :closable="false"
+                    show-icon
+                  />
+                </div>
+              </div>
+              <el-form-item label="闅忚鍐呭" v-if="orgname == '涓芥按甯備腑鍖婚櫌'">
+                <el-input type="textarea" v-model="form.remark"></el-input>
+              </el-form-item>
+              <el-form-item label="闅忚璁板綍" v-else>
+                <el-input type="textarea" v-model="form.remark"></el-input>
+              </el-form-item>
+
+              <el-form-item label="闅忚鎯呭喌" v-if="orgname == '涓芥按甯備腑鍖婚櫌'">
+                <el-radio-group v-model="form.taskSituation">
+                  <el-radio
+                    v-for="city in cities"
+                    :label="city.value"
+                    :value="city.value"
+                    :key="city.value"
+                    >{{ city.label }}</el-radio
+                  >
+                </el-radio-group>
+              </el-form-item>
+              <el-form-item label="澶勭悊鎰忚">
+                <div>
+                  <el-button
+                    plain
+                    type="warning"
+                    @click="Editsingletaskson('1')"
+                    >鏆備笉澶勭悊</el-button
+                  >
+                  <el-button
+                    plain
+                    type="success"
+                    @click="Editsingletaskson('2')"
+                    >鐥呮儏绋冲畾</el-button
+                  >
+                  <el-button
+                    plain
+                    type="primary"
+                    @click="Editsingletaskson('3')"
+                    >閫氱煡灏辫瘖</el-button
+                  >
+                  <el-button plain type="info" @click="Editsingletaskson('5')"
+                    >涓績闅忚</el-button
+                  >
+                  <el-button type="primary" round @click="sendAgainmsg"
+                    >鐭俊鍙戦��</el-button
+                  >
+                </div>
+              </el-form-item>
+            </el-form>
+
+            <div class="detailed">
+              <h3>鎮h�呮。妗堜俊鎭�</h3>
+              <el-form ref="userform" :model="userform" label-width="100px">
+                <el-row :gutter="20">
+                  <el-col :span="12">
+                    <el-form-item label="鎮h�呭鍚�" prop="name">
+                      <el-input
+                        v-model="userform.name"
+                        placeholder="璇疯緭鍏ュ鍚�"
+                        maxlength="30"
+                      ></el-input> </el-form-item
+                  ></el-col>
+                </el-row>
+                <el-row :gutter="20">
+                  <el-col :span="12"
+                    ><el-form-item label="鎬у埆" prop="telcode">
+                      <el-select v-model="userform.sex" placeholder="璇烽�夋嫨">
+                        <el-option label="鐢�" :value="1"> </el-option>
+                        <el-option label="濂�" :value="2"> </el-option>
+                      </el-select> </el-form-item
+                  ></el-col>
+                  <el-col :span="12">
+                    <el-form-item label="骞撮緞" prop="name">
+                      <el-input
+                        v-model="userform.age"
+                        placeholder="璇疯緭鍏ュ鍚�"
+                        maxlength="20"
+                      ></el-input> </el-form-item
+                  ></el-col>
+                </el-row>
+
+                <el-row :gutter="20">
+                  <el-col :span="12"
+                    ><el-form-item label="鑱旂郴鏂瑰紡" prop="telcode">
+                      <el-input
+                        v-model="userform.telcode"
+                        placeholder="璇疯緭鍏ヨ仈绯绘柟寮�"
+                        maxlength="20"
+                      /> </el-form-item
+                  ></el-col>
+                  <el-col :span="12">
+                    <el-form-item label="浜插睘鑱旂郴鏂瑰紡" prop="name">
+                      <el-input
+                        v-model="userform.relativetelcode"
+                        placeholder="璇疯緭鍏ュ鍚�"
+                        maxlength="20"
+                      ></el-input> </el-form-item
+                  ></el-col>
+                </el-row>
+                <el-row :gutter="20">
+                  <el-col :span="24">
+                    <el-form-item label="璇婃柇鍚嶇О" prop="name">
+                      <el-input
+                        v-model="form.leavediagname"
+                        placeholder="璇疯緭鍏ヨ瘖鏂�"
+                        maxlength="50"
+                      ></el-input> </el-form-item
+                  ></el-col>
+                </el-row>
+                <el-row :gutter="20">
+                  <el-col :span="24">
+                    <el-form-item label="鍑虹敓鍦�" prop="birthplace">
+                      <el-input
+                        v-model="userform.birthplace"
+                        placeholder="鍥姐�佺渷銆佸湴甯傘�佸尯鍘裤�佽閬撶瓑璇︾粏淇℃伅"
+                        maxlength="50"
+                      /> </el-form-item
+                  ></el-col>
+                </el-row>
+                <el-row :gutter="20">
+                  <el-col :span="24"
+                    ><el-form-item label="灞呬綇鍦�" prop="placeOfResidence">
+                      <el-input
+                        v-model="userform.placeOfResidence"
+                        placeholder="鍥姐�佺渷銆佸湴甯傘�佸尯鍘裤�佽閬撶瓑璇︾粏淇℃伅"
+                        maxlength="50"
+                      /> </el-form-item
+                  ></el-col>
+                </el-row>
+              </el-form>
+            </div>
+          </div>
+        </div>
+      </div>
+    </div>
+    <!-- 鐭俊鍙戦�佸璇濇 -->
+    <el-dialog title="鐭俊鍙戦��" :visible.sync="smsDialogVisible">
+      <!-- 娉ㄦ剰杩欓噷浣跨敤浜� smsDialogVisible 浠ュ尯鍒嗗凡鏈夌殑 dialogFormVisible -->
+      <el-form ref="smsForm" :model="form" label-width="80px">
+        <el-form-item label="鎮h�呭悕绉�">
+          <el-input
+            style="width: 400px"
+            disabled
+            v-model="form.sendname"
+          ></el-input>
+        </el-form-item>
+        <el-form-item label="骞撮緞">
+          <el-input style="width: 400px" disabled v-model="form.age"></el-input>
+        </el-form-item>
+        <el-form-item label="鐢佃瘽">
+          <el-input
+            style="width: 400px"
+            disabled
+            v-model="userform.telcode"
+          ></el-input>
+          <!-- 娉ㄦ剰杩欓噷鍙兘浣跨敤 userform.telcode -->
+        </el-form-item>
+        <el-form-item label="绉戝">
+          <el-input
+            style="width: 400px"
+            disabled
+            v-model="form.deptname"
+          ></el-input>
+        </el-form-item>
+        <el-form-item label="鐥呭尯">
+          <el-input
+            style="width: 400px"
+            disabled
+            v-model="form.leavehospitaldistrictname"
+          ></el-input>
+        </el-form-item>
+        <el-form-item label="鐭俊鍐呭">
+          <el-input type="textarea" v-model="smsContent"></el-input>
+          <!-- 寤鸿浣跨敤鐙珛鐨� smsContent 鍙橀噺 -->
+        </el-form-item>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button @click="smsDialogVisible = false">鍙� 娑�</el-button>
+        <el-button type="primary" @click="sendSms">纭鍙戦��</el-button>
+        <!-- 娉ㄦ剰鏂规硶鍚嶆敼涓� sendSms -->
+      </div>
+    </el-dialog>
+    <el-dialog
+      title="鎮h�呭啀娆¢殢璁�"
+      v-dialogDrags
+      :visible.sync="dialogFormVisible"
+    >
+      <el-form ref="zcform" :rules="zcrules" :model="form" label-width="80px">
+        <el-form-item label="浠诲姟鍚嶇О">
+          <el-input
+            style="width: 400px"
+            disabled
+            v-model="form.taskName"
+          ></el-input>
+        </el-form-item>
+        <el-form-item label="鎮h�呭悕绉�">
+          <el-input
+            style="width: 400px"
+            disabled
+            v-model="form.sendname"
+          ></el-input>
+        </el-form-item>
+        <el-form-item label="骞撮緞">
+          <el-input style="width: 400px" disabled v-model="form.age"></el-input>
+        </el-form-item>
+        <el-form-item label="绉戝">
+          <el-input
+            style="width: 400px"
+            disabled
+            v-model="form.deptname"
+          ></el-input>
+        </el-form-item>
+        <el-form-item label="鐥呭尯">
+          <el-input
+            style="width: 400px"
+            disabled
+            v-model="form.leavehospitaldistrictname"
+          ></el-input>
+        </el-form-item>
+        <el-form-item label="鍑洪櫌鏃堕棿">
+          <el-input
+            style="width: 400px"
+            disabled
+            v-model="form.endtime"
+          ></el-input>
+        </el-form-item>
+        <div class="headline">涓婃闅忚</div>
+        <el-divider></el-divider>
+        <el-row>
+          <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
+                  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="闅忚璁板綍">
+          <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="visitType">
+              <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"
+                value-format="yyyy-MM-dd"
+                @change="checkFollowupDate"
+              ></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-input type="textarea" v-model="form.remark"></el-input>
+        </el-form-item>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="warning" @click="dialogFormVisible = false"
+          >鍙� 娑�</el-button
+        >
+        <el-button type="primary" @click="setupsubtask">纭鍒涘缓鏈嶅姟</el-button>
+      </div>
+    </el-dialog>
+    <div class="main-content" v-if="orgname == '鏅畞鐣叉棌鑷不鍘夸汉姘戝尰闄�'">
+      <!-- <el-button @click="CaldialogVisible = true">鎵撳紑寮规</el-button> -->
+
+      <!-- 寮规璋冪敤 -->
+      <el-dialog
+        title="鍛煎彨鍔熻兘妗�"
+        :visible.sync="CaldialogVisible"
+        width="60%"
+      >
+        <CallCenterLs ref="CallCenterLs" :initial-phone="currentPhoneNumber" />
+      </el-dialog>
+    </div>
+  </div>
+</template>
+
+<script>
+import {
+  getsearchrResults,
+  getPersonVoices,
+  addserviceSubtask,
+  getTaskservelist,
+  getTaskFollowup,
+  Editsingletaskson,
+  serviceSubtaskDetailedit,
+  serviceSubtaskDetailadd,
+  updatePersonVoices,
+  addPersonVoices,
+  query360PatInfo,
+  sendMsg,
+} from "@/api/AiCentre/index";
+import {
+  messagelistpatient,
+  alterpatient,
+  listcontactinformation,
+} from "@/api/patient/homepage";
+import CallButton from "@/components/CallButton";
+import CallCenterLs from "@/components/CallCenterLs";
+export default {
+  components: {
+    CallButton,
+    CallCenterLs,
+  },
+  directives: {
+    numericOnly: {
+      bind(el, binding, vnode) {
+        // 灏濊瘯鑾峰彇瀹為檯鐨刬nput鍏冪礌
+        const input = el.tagName === "INPUT" ? el : el.querySelector("input");
+        if (!input) {
+          console.warn("v-numeric-only: 鏈壘鍒癷nput鍏冪礌");
+          return;
+        }
+
+        const handleInput = function (event) {
+          const oldValue = input.value;
+          const newValue = oldValue.replace(/[^\d]/g, "");
+          if (newValue !== oldValue) {
+            input.value = newValue;
+            // 瑙﹀彂input浜嬩欢锛岄�氱煡v-model鏇存柊
+            input.dispatchEvent(new Event("input", { bubbles: true })); // 娉ㄦ剰bubbles
+          }
+        };
+
+        const handlePaste = function (event) {
+          event.preventDefault();
+          const clipboardData = event.clipboardData || window.clipboardData;
+          const pastedData = clipboardData.getData("text");
+          const numericValue = pastedData.replace(/[^\d]/g, "");
+
+          // 妯℃嫙鍦ㄥ厜鏍囦綅缃彃鍏ョ函鏁板瓧鏂囨湰
+          const start = input.selectionStart;
+          const end = input.selectionEnd;
+          input.value =
+            input.value.substring(0, start) +
+            numericValue +
+            input.value.substring(end);
+          // 璋冩暣鍏夋爣浣嶇疆
+          const newCursorPos = start + numericValue.length;
+          input.setSelectionRange(newCursorPos, newCursorPos);
+
+          // 瑙﹀彂input浜嬩欢
+          input.dispatchEvent(new Event("input", { bubbles: true }));
+        };
+
+        input.addEventListener("input", handleInput);
+        input.addEventListener("paste", handlePaste);
+
+        // 瀛樺偍寮曠敤浠ヤ究瑙g粦
+        el._numericOnly = {
+          inputHandle: handleInput,
+          pasteHandle: handlePaste,
+          inputEl: input,
+        };
+      },
+      unbind(el) {
+        if (el._numericOnly) {
+          const { inputHandle, pasteHandle, inputEl } = el._numericOnly;
+          inputEl.removeEventListener("input", inputHandle);
+          inputEl.removeEventListener("paste", pasteHandle);
+          delete el._numericOnly;
+        }
+      },
+    },
+  },
+  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,
+      CaldialogVisible: false,
+      currentCall: null, // 褰撳墠閫氳瘽瀵硅薄
+      // 璺敱鐩戝惉鐩稿叧
+      routeWatcher: null,
+      lastRoutePath: this.$route.path,
+      input: "浠婂ぉ韬綋杩樹笉閿�",
+      radio: "2",
+      taskname: "",
+      activeName: "wj",
+      voice: "",
+      templateid: "",
+      again: "",
+      orgname: "",
+      zcform: {},
+      form: {},
+      cities: [
+        {
+          label: "姝e父璇煶",
+          value: "1",
+        },
+        {
+          label: "鎮h�呮嫆鎺ユ垨鎷掕",
+          value: "2",
+        },
+        {
+          label: "闈㈣鎴栬�呮帴璇�",
+          value: "3",
+        },
+        {
+          label: "寰俊闅忚",
+          value: "4",
+        },
+        {
+          label: "闅忚鐢佃瘽涓嶆纭�",
+          value: "5",
+        },
+        {
+          label: "涓嶅疁闅忚琚繃婊�",
+          value: "6",
+        },
+        {
+          label: "鍏朵粬",
+          value: "7",
+        },
+      ],
+      tableDatatop: [], //棰樼洰琛�
+      voiceDatatop: [], //棰樼洰琛�
+      dynamicTags: [],
+      isMergeMode: false,
+      mergeDialogVisible: false,
+      selectedServices: [], // 閫変腑鐨勬湇鍔″垪琛�
+      selectedTag: "",
+      tagOptions: [
+        {
+          value: "0",
+          label: "姝e父",
+          type: "normal",
+          color: "#7ff5e1",
+          description: "鎮h�呮儏鍐垫甯革紝鏃犻渶鐗瑰埆鍏虫敞",
+        },
+        {
+          value: "1",
+          label: "寮傚父",
+          type: "abnormal",
+          color: "#f75c5c",
+          description: "鎮h�呭瓨鍦ㄥ紓甯告儏鍐碉紝闇�瑕侀噸鐐瑰叧娉�",
+        },
+        {
+          value: "2",
+          label: "璀﹀憡",
+          type: "warning",
+          color: "#fbfb4a",
+          description: "鎮h�呮儏鍐甸渶瑕佽鍛婃敞鎰忥紝鍙兘瀛樺湪椋庨櫓",
+        },
+      ],
+      zcrules: {
+        resource: [
+          { required: true, message: "璇烽�夋嫨闅忚鏂瑰紡", trigger: "change" },
+        ],
+        date1: [
+          { required: true, message: "璇烽�夋嫨闅忚鏃堕棿", trigger: "blur" },
+          {
+            validator: (rule, value, callback) => {
+              if (!value) {
+                return callback(new Error("璇烽�夋嫨闅忚鏃堕棿"));
+              }
+              const selectedDate = new Date(value);
+              const now = new Date();
+              if (selectedDate < now) {
+                return callback(new Error("闅忚鏃堕棿涓嶈兘鏃╀簬褰撳墠鏃ユ湡"));
+              }
+              callback();
+            },
+            trigger: "change",
+          },
+        ],
+      },
+      userrules: {
+        telcode: [{ validator: validatePhone, trigger: "blur" }],
+        relativetelcode: [{ validator: validatePhone, trigger: "blur" }],
+      },
+      url: "http://9.208.2.190:8090/smartor/serviceExternal/query360PatInfo",
+      postData: {
+        XiaoXiTou: {
+          FaSongFCSJC: "ZJHES",
+          FaSongJGID: localStorage.getItem("orgid"),
+          FaSongJGMC: localStorage.getItem("orgname"),
+          FaSongSJ: "2025-01-09聽17:29:36",
+          FaSongXTJC: "SUIFANGXT",
+          FaSongXTMC: "闅忚绯荤粺",
+          XiaoXiID: "5FA92AFB-9833-4608-87C7-F56A654AC171",
+          XiaoXiLX: "SC_LC_360STCX",
+          XiaoXiMC: "360聽瑙嗗浘鏌ヨ",
+          ZuHuID: localStorage.getItem("ZuHuID"),
+          ZuHuMC: localStorage.getItem("orgname"),
+        },
+        YeWuXX: {
+          BingRenXX: {
+            ZhengJianHM: "",
+            ZhengJianLXDM: "01",
+            ZhengJianLXMC: "灞呮皯韬唤璇�",
+            ZuZhiJGID: localStorage.getItem("orgid"),
+            ZuZhiJGMC: localStorage.getItem("orgname"),
+          },
+          YongHuXX: {
+            XiTongID: "SUIFANGXT",
+            XiTongMC: "闅忚绯荤粺",
+            YongHuID: localStorage.getItem("YongHuID"),
+            YongHuXM: localStorage.getItem("YongHuXM"),
+            ZuZhiJGID: localStorage.getItem("orgid"),
+            ZuZhiJGMC: localStorage.getItem("orgname"),
+            idp: "lyra",
+          },
+        },
+      },
+      pickerOptions: {
+        disabledDate(time) {
+          // 绂佺敤浠婂ぉ鍙婁箣鍓嶇殑鏃ユ湡
+          return time.getTime() < Date.now() - 24 * 60 * 60 * 1000;
+        },
+        // shortcuts: [
+        //   {
+        //     text: "涓冨ぉ鍚�",
+        //     onClick(picker) {
+        //       const date = new Date();
+        //       date.setTime(date.getTime() + 3600 * 1000 * 24 * 7);
+        //       picker.$emit("pick", date);
+        //     },
+        //   },
+        //   {
+        //     text: "15澶╁悗",
+        //     onClick(picker) {
+        //       const date = new Date();
+        //       date.setTime(date.getTime() + 3600 * 1000 * 24 * 15);
+        //       picker.$emit("pick", date);
+        //     },
+        //   },
+        //   {
+        //     text: "涓�涓湀鍚�",
+        //     onClick(picker) {
+        //       const date = new Date();
+        //       date.setTime(date.getTime() + 3600 * 1000 * 24 * 30);
+        //       picker.$emit("pick", date);
+        //     },
+        //   },
+        //   {
+        //     text: "涓変釜鏈堝悗",
+        //     onClick(picker) {
+        //       const date = new Date();
+        //       date.setTime(date.getTime() + 3600 * 1000 * 24 * 90);
+        //       picker.$emit("pick", date);
+        //     },
+        //   },
+        //   {
+        //     text: "鍏釜鏈堝悗",
+        //     onClick(picker) {
+        //       const date = new Date();
+        //       date.setTime(date.getTime() + 3600 * 1000 * 24 * 180);
+        //       picker.$emit("pick", date);
+        //     },
+        //   },
+        //   {
+        //     text: "涓�骞村悗",
+        //     onClick(picker) {
+        //       const date = new Date();
+        //       date.setTime(date.getTime() + 3600 * 1000 * 24 * 365);
+        //       picker.$emit("pick", date);
+        //     },
+        //   },
+        // ],
+      },
+      options: [
+        {
+          value: "涓冨ぉ鍚�",
+          label: "涓冨ぉ鍚�",
+        },
+        {
+          value: "15澶╁悗",
+          label: "15澶╁悗",
+        },
+        {
+          value: "涓�涓湀鍚�",
+          label: "涓�涓湀鍚�",
+        },
+        {
+          value: "涓変釜鏈堝悗",
+          label: "涓変釜鏈堝悗",
+        },
+        {
+          value: "鍏釜鏈堝悗",
+          label: "鍏釜鏈堝悗",
+        },
+        {
+          value: "涓�骞村悗",
+          label: "涓�骞村悗",
+        },
+      ],
+      userform: {},
+      smsDialogVisible: false, // 鎺у埗鐭俊瀵硅瘽妗嗘樉绀�
+      smsContent: "", // 瀛樺偍鐭俊鍐呭
+      Whetherall: true, //鏄惁鍏ㄩ儴璁板綍灞曠ず
+      dialogFormVisible: false,
+      Voicetype: 0, //鏄惁涓鸿闊虫湇鍔�
+      visitCount: null,
+      logsheetlist: [],
+      topicobj: {},
+      sendname: null,
+      serviceType: null,
+      id: null,
+      taskid: null,
+      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;
+    this.sendname = this.$route.query.sendname;
+    this.patid = this.$route.query.patid;
+    this.again = this.$route.query.again;
+    this.Voicetype = this.$route.query.Voicetype;
+    this.visitCount = this.$route.query.visitCount;
+    this.serviceType = this.$route.query.serviceType;
+    this.orgname = localStorage.getItem("orgname");
+
+    this.getTaskservelist();
+  },
+
+  methods: {
+    // 鑾峰彇涓婚鏍峰紡绫�
+    getTopicClass(item) {
+      // 鏍规嵁鐘舵�佸�艰繑鍥炲搴旂殑鏍峰紡绫�
+      if (item.isabnormal == 1) {
+        return "scriptTopic-isabnormal"; // 寮傚父 - 绾㈣壊
+      } else if (item.isabnormal == 2) {
+        return "scriptTopic-warning"; // 璀﹀憡 - 榛勮壊
+      } else {
+        return "scriptTopic-dev"; // 姝e父 - 榛樿鏍峰紡
+      }
+    },
+
+    // 鑾峰彇閫夐」鏍峰紡绫�
+    getOptionClass(items) {
+      if (items.isabnormal == 1) {
+        return "red-star"; // 寮傚父 - 绾㈣壊鏄熷彿
+      } else if (items.isabnormal == 2) {
+        return "yellow-star"; // 璀﹀憡 - 榛勮壊鏄熷彿
+      }
+      return ""; // 姝e父 - 鏃犵壒娈婃牱寮�
+    },
+    // 鑾峰彇闂嵎鏁版嵁
+    getsearchrResults(id) {
+      getsearchrResults({
+        taskid: this.taskid,
+        patid: this.patid,
+        subId: id ? id : this.id,
+        isFinish: false,
+      }).then((res) => {
+        if (res.code === 200) {
+          // 閽堝鍐嶆闅忚鏈嶅姟杩涜鍒犻櫎缁撴灉璧嬪��
+          if (this.again && res.data.upScriptResult) {
+            res.data.upScriptResult.forEach((itemA) => {
+              const itemB = res.data.scriptResult.find(
+                (item) => item.scriptContent === itemA.scriptContent
+              );
+              if (itemB) {
+                itemB.scriptResult = itemA.scriptResult;
+              }
+            });
+          }
+          this.tableDatatop = res.data.scriptResult;
+
+          this.tableDatatop.forEach((item) => {
+            if (item.scriptType == 2) item.scriptResult = [];
+            if (item.scriptResultId && item.scriptType != 2) {
+              item.isoption = 3;
+              item.scriptResult = item.scriptResult;
+            } else if (item.scriptResultId && item.scriptType == 2) {
+              item.scriptResult = item.scriptResult.split("&");
+              item.isoption = 3;
+            }
+          });
+          this.taskname = res.data.taskName;
+          this.overdata();
+        }
+      });
+    },
+    //鎮h��360璺宠浆
+    gettoken360(sfzh, drcode, drname) {
+      // this.$modal.msgWarning("360鍔熻兘鏆傛湭寮�閫�");
+
+      this.postData.YeWuXX.BingRenXX.ZhengJianHM = sfzh;
+
+      query360PatInfo(this.postData).then((res) => {
+        if (res.data.url) {
+          window.open(res.data.url, "_blank");
+          // this.linkUrl = res.data.url;
+        } else {
+          this.$modal.msgWarning("360鏌ヨ鏃犵粨鏋�");
+        }
+      });
+    },
+    // 鑾峰彇鍩虹淇℃伅
+    getuserinfo() {
+      const queryParams = {
+        pid: Number(this.patid),
+        allhosp: "0", //1浣忛櫌2闂ㄨ瘖3浣撴4鍑洪櫌
+      };
+      // 鎮h�呭熀纭�淇℃伅
+      messagelistpatient(queryParams).then((response) => {
+        if (response.rows[0]) {
+          this.userform = response.rows[0];
+          // this.dynamicTags = response.rows[0].tagList.map(this.processElement);
+        }
+      });
+      listcontactinformation({ patid: this.patid }).then((response) => {
+        this.tableData = response.rows;
+        if (this.tableData.length) {
+          this.userform.relativetelcode = this.tableData[0].contactway;
+          this.userform.relation = this.tableData[0].relation;
+        }
+      });
+    },
+    // 鍐嶆闅忚鏃堕棿閫夊彇
+    visitChange(value) {
+      if (!this.form.endtime) {
+        this.$message.warning("璇峰厛纭鍑洪櫌鏃堕棿");
+        this.form.visitType = "";
+        this.$refs.zcform.clearValidate(["visitType"]);
+        return;
+      }
+
+      const dischargeDate = new Date(this.form.endtime);
+      const now = new Date();
+      let followupDate = new Date(dischargeDate);
+
+      // 鏍规嵁閫夋嫨鐨勯殢璁挎柟寮忚绠楅殢璁挎棩鏈�
+      if (value.includes("涓冨ぉ鍚�")) {
+        followupDate.setDate(dischargeDate.getDate() + 7);
+      } else if (value.includes("15澶╁悗")) {
+        followupDate.setDate(dischargeDate.getDate() + 15);
+      } else if (value.includes("涓�涓湀鍚�")) {
+        followupDate.setMonth(dischargeDate.getMonth() + 1);
+      } else if (value.includes("涓変釜鏈堝悗")) {
+        followupDate.setMonth(dischargeDate.getMonth() + 3);
+      } else if (value.includes("鍏釜鏈堝悗")) {
+        followupDate.setMonth(dischargeDate.getMonth() + 6);
+      } else if (value.includes("涓�骞村悗")) {
+        followupDate.setFullYear(dischargeDate.getFullYear() + 1);
+      }
+
+      if (followupDate < now) {
+        this.$message.warning(
+          `璁$畻鍑虹殑闅忚鏃堕棿 ${this.formatTime(followupDate)} 宸茶繃鏈焋
+        );
+        this.form.visitType = "";
+        this.$refs.zcform.clearValidate(["visitType", "date1"]);
+        return;
+      }
+
+      this.form.date1 = this.formatTime(followupDate);
+
+      this.$refs.zcform.clearValidate(["date1"]);
+    },
+    // 妫�鏌ラ殢璁挎棩鏈熸槸鍚︽湁鏁�
+    checkFollowupDate(date) {
+      console.log(date);
+
+      if (!date) {
+        this.form.date1 = "";
+        this.$refs.zcform.clearValidate(["date1"]);
+        return;
+      }
+
+      const selectedDate = new Date(date);
+      const now = new Date();
+
+      if (selectedDate < now) {
+        this.$message.warning("闅忚鏃堕棿涓嶈兘鏃╀簬褰撳墠鏃ユ湡");
+        this.form.date1 = "";
+        this.$refs.zcform.validateField("date1"); // 瑙﹀彂楠岃瘉
+      }
+    },
+    // 鑾峰彇璇煶鏁版嵁
+    getPersonVoices(id) {
+      let obj = {
+        taskid: this.taskid,
+        patid: this.patid,
+        subId: id ? id : this.id,
+      };
+
+      getPersonVoices(obj).then((res) => {
+        if (res.code == 200) {
+          this.voiceDatatop = res.data.serviceSubtaskDetails;
+          this.voice = res.data.voice;
+          this.activeName = "yy";
+          this.taskname = res.data.taskName;
+          // 闂嵎灞曠ず鏁版嵁澶勭悊
+          this.tableDatatop = res.data.filteredDetails;
+          this.tableDatatop.forEach((item) => {
+            if (item.targetvalue) {
+              item.scriptResult = item.targetvalue.split("&");
+            } else {
+              item.scriptResult = [];
+            }
+          });
+
+          if (!this.tableDatatop.length) {
+            this.puttaskid(this.templateid);
+          }
+        }
+      });
+    },
+    // 鑾峰彇闂嵎瀹屾暣鏁版嵁姣斿
+    puttaskid(id) {
+      getTaskFollowup(id).then((res) => {
+        if (res.code == 200) {
+          this.tableDatatop = res.data.ivrTaskTemplateScriptVOList;
+          this.tableDatatop.forEach((item) => {
+            item.id = null;
+            // 绫诲瀷鍒ゆ柇璧嬪��
+            if (item.ivrTaskScriptTargetoptionList) {
+              item.targetvalue = 1;
+              item.questiontext = item.scriptContent;
+              item.targetvalue = item.ivrTaskScriptTargetoptionList
+                .map((obj) => obj.targetvalue)
+                .join("&");
+            }
+            if (item.targetvalue) {
+              item.scriptResult = item.targetvalue.split("&");
+            } else {
+              item.scriptResult = [];
+            }
+          });
+        }
+      });
+    },
+    // 鍖绘姢浜哄憳瀛樺偍鏁版嵁
+    getdetail() {
+      let excep = "";
+      const promises = [];
+      this.tableDatatop.forEach((item) => {
+        if (item.valueType == 3 && item.scriptResult) {
+          // 楠岃瘉鏄惁涓烘湁鏁堟暟瀛�
+          if (!/^\d+$/.test(item.scriptResult)) {
+            this.$message.error(`闂 "${item.scriptContent}" 蹇呴』杈撳叆鏁板瓧`);
+            return;
+          }
+        }
+        var objs = item.svyTaskTemplateTargetoptions.find(
+          (items) => items.optioncontent == item.scriptResult
+        );
+
+        if (objs) {
+          if (excep != 1 && objs.isabnormal) {
+            excep = objs.isabnormal;
+            this.selectedTag = objs.isabnormal;
+          }
+        }
+        console.log(excep, "excep");
+
+        let obj = {
+          asrtext: null,
+          patid: this.patid,
+          subId: this.id,
+          taskid: this.taskid,
+          scriptid: item.id,
+          excep: excep,
+          questiontext: item.scriptContent,
+          answerps: item.answerps || null, // 娣诲姞闄勫姞淇℃伅
+        };
+        if (item.scriptType == 2 && item.scriptResult[0]) {
+          obj.asrtext = item.scriptResult.join("&");
+        } else if (item.scriptType != 2 && item.scriptResult) {
+          obj.asrtext = item.scriptResult;
+        }
+
+        if (item.isoption == 3) {
+          promises.push(serviceSubtaskDetailedit(obj));
+        } else {
+          promises.push(serviceSubtaskDetailadd(obj));
+        }
+      });
+
+      // 浣跨敤 Promise.all 绛夊緟鎵�鏈夊紓姝ユ搷浣滃畬鎴�
+      Promise.all(promises)
+        .then((results) => {
+          // 鎵�鏈夊紓姝ユ搷浣滄垚鍔熷畬鎴愬悗鐨勯�昏緫
+          results.forEach((res) => {
+            if (res.code !== 200) {
+              this.$modal.error("淇敼澶辫触");
+            }
+          });
+          this.Editsingletasksonyic(6);
+
+          this.$modal
+            .confirm(
+              '浠诲姟淇濆瓨鎴愬姛鏄惁閽堝鎮h�咃細"' +
+                this.userform.name +
+                '"鍐嶆闅忚锛�',
+              "纭",
+              {
+                confirmButtonText: "纭畾",
+                cancelButtonText: "鍙栨秷",
+                showCancelButton: true,
+                dangerouslyUseHTMLString: true,
+                confirmButtonClass: "custom-confirm-button", // 鑷畾涔夌‘璁ゆ寜閽殑绫诲悕
+                cancelButtonClass: "custom-cancel-button", // 鑷畾涔夊彇娑堟寜閽殑绫诲悕
+              }
+            )
+            .then(() => {
+              document.querySelector("#app").scrollTo(0, 0);
+              this.formtidy();
+              this.dialogFormVisible = true;
+            })
+            .catch(() => {
+              if (this.form.serviceType == 13) {
+                if (this.visitCount != 1) {
+                  this.$router.push({
+                    path: "/logisticsservice/zbAgain",
+                  });
+                } else {
+                  this.$router.push({
+                    path: "/logisticsservice/record",
+                  });
+                }
+              } else if (this.form.serviceType == 2) {
+                if (this.visitCount != 1) {
+                  this.$router.push({
+                    path: "/logisticsservice/again",
+                  });
+                } else {
+                  this.$router.push({
+                    path: "/followvisit/discharge",
+                  });
+                }
+              }
+            });
+        })
+        .catch((error) => {
+          // 濡傛灉鏈変换浣曚竴涓紓姝ユ搷浣滃け璐ワ紝浼氳繘鍏ヨ繖閲�
+          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;
+      // 鍛煎彨鍒ゆ柇
+      if (this.orgname == "鏅畞鐣叉棌鑷不鍘夸汉姘戝尰闄�") {
+        this.CaldialogVisible = true;
+        return;
+      }
+
+      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() {
+      const dataToSubmit = JSON.parse(JSON.stringify(this.tableDatatop));
+      console.log(dataToSubmit, "dataToSubmit");
+      return;
+      dataToSubmit.forEach((item, index) => {
+        // 瀵规嫹璐濈殑鏁版嵁杩涜鎿嶄綔锛屼笉褰卞搷鍘熷鐨� scriptResult 鏁扮粍
+        item.scriptResult = item.scriptResult.join("&");
+        item.templatequestionnum = index + 1;
+        item.subId = this.id;
+        item.taskid = this.taskid;
+        item.asrtext = item.matchedtext;
+        if (!item.id) {
+          item.isoperation = 1;
+        }
+        item.patid = this.patid;
+        item.templateid = item.templateID;
+      });
+
+      let obj = {
+        serviceSubtaskDetailList: dataToSubmit, // 鎻愪氦澶勭悊鍚庣殑鍓湰
+        param1: this.taskid,
+        param2: this.patid,
+        subId: this.id,
+      };
+
+      addPersonVoices(obj).then((res) => {
+        if (res.code == 200) {
+          this.$modal.msgSuccess("鏈嶅姟淇濆瓨鎴愬姛");
+          this.$modal
+            .confirm(
+              '浠诲姟淇濆瓨鎴愬姛鏄惁閽堝鎮h�咃細"' +
+                this.userform.name +
+                '"鍐嶆闅忚锛�',
+              "纭",
+              {
+                confirmButtonText: "纭畾",
+                cancelButtonText: "鍙栨秷",
+                showCancelButton: true,
+                dangerouslyUseHTMLString: true,
+                confirmButtonClass: "custom-confirm-button", // 鑷畾涔夌‘璁ゆ寜閽殑绫诲悕
+                cancelButtonClass: "custom-cancel-button", // 鑷畾涔夊彇娑堟寜閽殑绫诲悕
+              }
+            )
+            .then(() => {
+              document.querySelector("#app").scrollTo(0, 0);
+              this.formtidy();
+              this.dialogFormVisible = true;
+            })
+            .catch(() => {
+              if (this.form.serviceType == 13) {
+                if (this.visitCount != 1) {
+                  this.$router.push({
+                    path: "/logisticsservice/zbAgain",
+                  });
+                } else {
+                  this.$router.push({
+                    path: "/logisticsservice/record",
+                  });
+                }
+              } else if (form.serviceType == 2) {
+                if (this.visitCount != 1) {
+                  this.$router.push({
+                    path: "/followvisit/again",
+                  });
+                } else {
+                  this.$router.push({
+                    path: "/followvisit/discharge",
+                  });
+                }
+              }
+            });
+        }
+      });
+    },
+    // 鍐嶆闅忚鏁版嵁鏇存浛
+    formtidy() {
+      this.form.visitType2 = this.form.visitType;
+      this.form.date2 = this.form.visitTime;
+      // this.form.date1 = this.setCurrentDate();
+      this.form.remark2 = this.form.remark;
+    },
+    setCurrentDate() {
+      // 鑾峰彇褰撳墠鏃ユ湡骞舵牸寮忓寲涓� yyyy-MM-dd
+      const today = new Date();
+      const year = today.getFullYear();
+      const month = String(today.getMonth() + 1).padStart(2, "0");
+      const day = String(today.getDate()).padStart(2, "0");
+      return `${year}-${month}-${day}`;
+    },
+    // 鑾峰彇鎮h�呰褰�
+    getTaskservelist(id) {
+      if (id) {
+        this.Whetherall = false;
+      } else {
+        this.Whetherall = true;
+      }
+
+      getTaskservelist({
+        patid: this.patid,
+        subId: id,
+        pageSize: 100,
+      }).then((res) => {
+        if (res.code == 200) {
+          this.form = res.rows[0].serviceSubtaskList.find(
+            (item) => item.id == this.id
+          );
+          console.log(this.form, "serviceType");
+
+          this.logsheetlist = res.rows[0].serviceSubtaskList;
+          this.templateid = this.form.templateid;
+          this.selectedTag = this.form.excep;
+          const targetDate = new Date(this.form.visitTime); // 鐩爣鏃ユ湡
+          const now = new Date(); // 褰撳墠鏃堕棿
+          if (now < targetDate && this.form.sendstate == 2) {
+            this.$confirm("褰撳墠鏈嶅姟鏈埌鍙戦�佹椂闂磋璋ㄦ厧淇敼", "鎻愮ず", {
+              confirmButtonText: "纭畾",
+              cancelButtonText: "鍙栨秷",
+              type: "warning",
+            })
+              .then(() => {})
+              .catch(() => {});
+          }
+          this.getuserinfo();
+        }
+        if (this.Voicetype) {
+          this.getPersonVoices();
+        } else {
+          this.getsearchrResults();
+        }
+      });
+    },
+    // 璋冭捣鐭俊鍙戦�佸璇濇
+    sendAgainmsg() {
+      this.smsDialogVisible = true;
+      // 鍙互鍦ㄨ繖閲屽垵濮嬪寲 smsContent锛屼緥濡� this.smsContent = '';
+    },
+
+    // 鍙戦�佺煭淇$殑鏂规硶
+    sendSms() {
+      // 杩欓噷璋冪敤浣犵殑鐭俊鍙戦�� API
+      // 鍋囪 API 涓� sendMsg锛屽弬鏁板彲鑳介渶瑕佹牴鎹疄闄呮儏鍐佃皟鏁�
+      sendMsg({
+        phone: this.userform.telcode, // 纭繚鐢佃瘽鍙风爜瀛楁姝g‘
+        content: this.smsContent,
+      })
+        .then((res) => {
+          if (res.code == 200) {
+            this.$modal.msgSuccess("鍙戦�佹垚鍔�");
+            this.smsDialogVisible = false; // 鍏抽棴瀵硅瘽妗�
+            this.smsContent = ""; // 娓呯┖鍐呭
+          } else {
+            this.$modal.msgError("鍙戦�佸け璐�");
+          }
+        })
+        .catch((error) => {
+          console.error("鍙戦�佺煭淇″け璐�:", error);
+          this.$modal.msgError("鍙戦�佸け璐�");
+        });
+    },
+    Editsingletaskson(son) {
+      let objson = {};
+      getTaskservelist({
+        patid: this.patid,
+        subId: this.id,
+      }).then((res) => {
+        if (res.code == 200) {
+          objson = res.rows[0].serviceSubtaskList[0];
+          objson.suggest = son;
+          Editsingletaskson(objson).then((res) => {
+            if (res.code) {
+              this.$modal.msgSuccess("鏈嶅姟璁板綍鎴愬姛");
+              this.getTaskservelist();
+            }
+          });
+        }
+      });
+    },
+    Editsingletasksonyic(sendstate) {
+      let objson = {};
+      getTaskservelist({
+        patid: this.patid,
+        subId: this.id,
+      }).then((res) => {
+        if (res.code == 200) {
+          objson = res.rows[0].serviceSubtaskList.find(
+            (item) => item.id == this.id
+          );
+          objson.remark = this.form.remark;
+          objson.taskSituation = this.form.taskSituation;
+          objson.excep = this.selectedTag;
+          if (sendstate) objson.sendstate = sendstate;
+          Editsingletaskson(objson).then((res) => {
+            if (res.code) {
+              this.$modal.msgSuccess("鏈嶅姟淇敼鎴愬姛");
+              alterpatient(this.userform).then((res) => {
+                if (res.code == 200) {
+                  this.$modal.msgSuccess("鍩虹淇℃伅淇濆瓨鎴愬姛");
+                } else {
+                  this.$modal.msgError("鍩虹淇℃伅淇敼澶辫触");
+                }
+              });
+              this.getTaskservelist();
+            }
+          });
+        }
+      });
+    },
+    // 寮傚父鍒楁覆鏌�
+    tableRowClassName({ row, rowIndex }) {
+      if (row.id == this.id) {
+        return "warning-row";
+      }
+      return "";
+    },
+    getSelectedTagType() {
+      if (!this.selectedTag) return "";
+      const tag = this.tagOptions.find(
+        (item) => item.value === this.selectedTag
+      );
+      return tag ? tag.type : "";
+    },
+
+    getSelectedTagColor() {
+      if (!this.selectedTag) return "";
+      const tag = this.tagOptions.find(
+        (item) => item.value === this.selectedTag
+      );
+      return tag ? tag.color : "";
+    },
+
+    getSelectedDescription() {
+      if (!this.selectedTag) return "";
+      const tag = this.tagOptions.find(
+        (item) => item.value === this.selectedTag
+      );
+      return tag ? tag.description : "";
+    },
+
+    // 璋冭捣鍐嶆鍙戦��
+    sendAgain() {
+      document.querySelector("#app").scrollTo(0, 0);
+      // scrollTo(0, 0)
+      this.formtidy();
+      this.dialogFormVisible = true;
+    },
+    // 鏌ョ湅璇︽儏
+    Seedetails(row) {
+      this.$modal
+        .confirm('鏄惁鏌ョ湅浠诲姟涓�"' + row.taskName + '"鐨勬湇鍔¤鎯呮暟鎹紵')
+        .then(() => {
+          let type = "";
+          console.log(row, "rwo");
+          if (row.type == 1) {
+            type = 1;
+          }
+          this.taskid = row.taskid;
+          this.id = row.id;
+          this.patid = row.patid;
+          this.serviceType = row.serviceType;
+          this.getTaskservelist();
+        })
+        .catch(() => {});
+    },
+    aahandleOptionChange(a, b, c) {
+      const result = c.find((item) => item.optioncontent == a);
+      if (result.nextQuestion == 0) {
+        this.tableDatatop = this.tableDatatop.reduce((acc, item, i) => {
+          acc.push(i > b ? { ...item, astrict: 1 } : item);
+          return acc;
+        }, []);
+      } else {
+        this.tableDatatop = this.tableDatatop.reduce((acc, item, i) => {
+          acc.push(i > b ? { ...item, astrict: 0 } : item);
+          return acc;
+        }, []);
+      }
+      if (this.Voicetype) {
+        var obj = this.tableDatatop[b].ivrTaskScriptTargetoptionList.find(
+          (item) => item.optioncontent == a
+        );
+      } else {
+        var obj = this.tableDatatop[b].svyTaskTemplateTargetoptions.find(
+          (item) => item.optioncontent == a
+        );
+      }
+      if (obj.isabnormal) {
+        this.tableDatatop[b].isabnormal = true;
+      } else {
+        this.tableDatatop[b].isabnormal = false;
+      }
+      this.$forceUpdate();
+    },
+    handleRadioToggles(questionItem, optionValue) {
+      if (!questionItem.matchedtext) {
+        questionItem.matchedtext == "";
+      }
+      // 濡傛灉鐐瑰嚮鐨勬槸褰撳墠宸查�変腑鐨勯�夐」锛屽垯鍙栨秷閫変腑
+      if (questionItem.matchedtext == optionValue) {
+        this.$set(questionItem, "matchedtext", "");
+        // 鍚屾椂閲嶇疆涓庨�夐」鐩稿叧鐨勭姸鎬�
+        // questionItem.isabnormal = false;
+        questionItem.showAppendInput = false;
+        // 娉ㄦ剰锛氬彇娑堥�変腑鏃讹紝鎴戜滑閫氬父涓嶅笇鏈涜Е鍙戦鐩烦杞�昏緫锛屾墍浠ョ洿鎺ヨ繑鍥�
+        // 濡傛灉闇�瑕侊紝鍙互鍦ㄨ繖閲屾坊鍔犲彇娑堥�変腑鍚庣殑鐗瑰畾閫昏緫锛屼緥濡傞噸缃鐩簭鍒�
+      } else {
+        // 濡傛灉鐐瑰嚮鐨勬槸鏈�変腑鐨勯�夐」锛屽垯閫氳繃鏇存敼缁戝畾鍊兼潵瑙﹀彂鍘熷鐨� handleOptionChange 鏂规硶
+        // 杩欓噷鍙渶瑕佹敼鍙� v-model 缁戝畾鐨勫�硷紝change浜嬩欢浼氳嚜鍔ㄨЕ鍙�
+        this.$set(questionItem, "matchedtext", optionValue); // 鍚庣画鐨勮烦杞瓑澶嶆潅閫昏緫浼氬湪 handleOptionChange 涓甯告墽琛�
+      }
+    },
+    // 鏂板鐨勫垏鎹㈤�変腑/鍙栨秷閫変腑鏂规硶
+    handleRadioToggle(questionItem, index, options, optionValue) {
+      // 濡傛灉鐐瑰嚮鐨勬槸褰撳墠宸查�変腑鐨勯�夐」锛屽垯鍙栨秷閫変腑
+      if (questionItem.scriptResult === optionValue) {
+        questionItem.scriptResult = ""; // 娓呯┖閫変腑鍊�
+        // 鍚屾椂閲嶇疆涓庨�夐」鐩稿叧鐨勭姸鎬�
+        // questionItem.isabnormal = false;
+        questionItem.showAppendInput = false;
+        // 娉ㄦ剰锛氬彇娑堥�変腑鏃讹紝鎴戜滑閫氬父涓嶅笇鏈涜Е鍙戦鐩烦杞�昏緫锛屾墍浠ョ洿鎺ヨ繑鍥�
+        // 濡傛灉闇�瑕侊紝鍙互鍦ㄨ繖閲屾坊鍔犲彇娑堥�変腑鍚庣殑鐗瑰畾閫昏緫锛屼緥濡傞噸缃鐩簭鍒�
+      } else {
+        // 濡傛灉鐐瑰嚮鐨勬槸鏈�変腑鐨勯�夐」锛屽垯閫氳繃鏇存敼缁戝畾鍊兼潵瑙﹀彂鍘熷鐨� handleOptionChange 鏂规硶
+        // 杩欓噷鍙渶瑕佹敼鍙� v-model 缁戝畾鐨勫�硷紝change浜嬩欢浼氳嚜鍔ㄨЕ鍙�
+        questionItem.scriptResult = optionValue;
+        this.handleOptionChange(optionValue, index, options, questionItem);
+        // 鍚庣画鐨勮烦杞瓑澶嶆潅閫昏緫浼氬湪 handleOptionChange 涓甯告墽琛�
+      }
+    },
+
+    // 鍦╩ethods閮ㄥ垎锛屼慨鏀筯andleOptionChange鏂规硶:
+    handleOptionChange(selectedOption, questionIndex, options, a) {
+      console.log(selectedOption, questionIndex, options, a, "888");
+
+      if (document.activeElement) {
+        document.activeElement.blur();
+      }
+
+      // 鎵惧埌琚�変腑鐨勯�夐」瀵硅薄
+      const selectedOptionObj = options.find(
+        (item) => item.optioncontent == selectedOption
+      );
+
+      // 澶勭悊寮傚父鐘舵�侀珮浜�
+      this.tableDatatop[questionIndex].isabnormal =
+        selectedOptionObj.isabnormal;
+      // 澶勭悊闄勫姞杈撳叆妗嗘樉绀�
+
+      this.tableDatatop[questionIndex].showAppendInput =
+        selectedOptionObj.appendflag == 1;
+      console.log(this.tableDatatop);
+
+      // if (!this.tableDatatop[questionIndex].showAppendInput) {
+      //   this.tableDatatop[questionIndex].answerps = ""; // 娓呴櫎闄勫姞淇℃伅
+      // }
+      // 淇濆瓨褰撳墠棰樼洰涔嬪墠宸茬粡闅愯棌鐨勯鐩姸鎬�
+      const previouslyHiddenBeforeCurrent = this.tableDatatop
+        .slice(0, questionIndex)
+        .map((item, index) => (item.astrict ? index : -1))
+        .filter((index) => index !== -1);
+
+      // 淇濆瓨涔嬪墠鍥爊extQuestion=0鑰岄殣钘忕殑棰樼洰鑼冨洿
+      const previouslyHiddenByEnd = this.tableDatatop
+        .map((item, index) => (item.hiddenByEnd ? index : -1))
+        .filter((index) => index !== -1);
+
+      // 濡傛灉branchFlag涓�1锛屽鐞嗛鐩烦杞�
+      if (a.branchFlag == 1) {
+        if (selectedOptionObj.nextQuestion == 0) {
+          // 缁撴潫闂瓟 - 闅愯棌鍚庨潰鎵�鏈夐鐩苟鏍囪
+          this.tableDatatop = this.tableDatatop.map((item, index) => ({
+            ...item,
+            astrict: index > questionIndex,
+            hiddenByEnd: index > questionIndex, // 鏍囪杩欎簺棰樼洰鏄缁撴潫闂瓟闅愯棌鐨�
+          }));
+        } else {
+          // 姝e父璺宠浆閫昏緫
+          const nextQuestionIndex = selectedOptionObj.nextQuestion - 1;
+
+          this.tableDatatop = this.tableDatatop.map((item, index) => {
+            // 淇濈暀褰撳墠棰樼洰涔嬪墠鐨勯殣钘忕姸鎬�
+            if (index < questionIndex) {
+              return {
+                ...item,
+                astrict: previouslyHiddenBeforeCurrent.includes(index),
+                hiddenByEnd: false, // 娓呴櫎缁撴潫鏍囪
+              };
+            }
+
+            // 褰撳墠棰樼洰鎬绘槸鍙
+            if (index === questionIndex) {
+              return { ...item, astrict: 0, hiddenByEnd: false };
+            }
+
+            // 鏄剧ず鐩爣涓嬩竴棰�
+            if (index === nextQuestionIndex) {
+              return { ...item, astrict: 0, hiddenByEnd: false };
+            }
+
+            // 濡傛灉鏄箣鍓嶈缁撴潫闂瓟闅愯棌鐨勯鐩紝鐜板湪搴旇鎭㈠鏄剧ず
+            if (item.hiddenByEnd) {
+              return { ...item, astrict: 0, hiddenByEnd: false };
+            }
+
+            // 闅愯棌褰撳墠棰樺拰鐩爣棰樹箣闂寸殑棰樼洰
+            if (index > questionIndex && index < nextQuestionIndex) {
+              return { ...item, astrict: 1, hiddenByEnd: false };
+            }
+
+            // 鍏朵粬鎯呭喌淇濇寔鍘熺姸
+            return item;
+          });
+        }
+      } else {
+        // 濡傛灉娌℃湁璺宠浆锛屽彧闇�纭繚涓嬩竴棰樺彲瑙�
+        this.tableDatatop = this.tableDatatop.map((item, index) => ({
+          ...item,
+          astrict: index === questionIndex + 1 ? 0 : item.astrict,
+          hiddenByEnd: index === questionIndex + 1 ? false : item.hiddenByEnd,
+        }));
+      }2
+
+      this.$forceUpdate();
+    },
+    overdata() {
+      this.tableDatatop.forEach((item, index) => {
+        var obj = item.svyTaskTemplateTargetoptions.find(
+          (items) => items.optioncontent == item.scriptResult
+        );
+        if (obj) {
+          if (obj.isabnormal) {
+            this.tableDatatop[index].isabnormal = obj.isabnormal;
+          }
+          this.$forceUpdate();
+        }
+      });
+    },
+    // 鍒涘缓鍐嶆闅忚鏈嶅姟
+    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);
+          form.visitTime = this.formatTime(form.date1);
+          form.finishtime = "";
+          if (form.resource) {
+            if (form.resource == 2) {
+              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("鍒涘缓鎴愬姛");
+              if (form.serviceType == 13) {
+                this.$router.push({
+                  path: "/logisticsservice/zbAgain",
+                });
+              } else if (form.serviceType == 2) {
+                this.$router.push({
+                  path: "/logisticsservice/again",
+                });
+              }
+            } else {
+              this.$modal.msgError("鍒涘缓澶辫触");
+            }
+            document.querySelector("#app").scrollTo(0, 0);
+            this.dialogFormVisible = false;
+          });
+        }
+      });
+    },
+    getCurrentTime() {
+      const now = new Date();
+      const year = now.getFullYear();
+      const month = String(now.getMonth() + 1).padStart(2, "0");
+      const day = String(now.getDate()).padStart(2, "0");
+      const hours = String(now.getHours()).padStart(2, "0");
+      const minutes = String(now.getMinutes()).padStart(2, "0");
+      const seconds = String(now.getSeconds()).padStart(2, "0");
+
+      return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
+    },
+    updateScore(a, b, c) {},
+    // 鍚堝苟淇敼鐩稿叧=============================
+    toggleMergeMode() {
+      this.isMergeMode = !this.isMergeMode;
+      if (!this.isMergeMode) {
+        this.selectedServices = [];
+      }
+    },
+
+    handleSelectionChange(selection) {
+      this.selectedServices = selection
+        .filter(
+          (item) => !item.preachformson || !item.preachformson.includes("3")
+        )
+        .map((item) => ({
+          id: item.id,
+          taskid: item.taskid,
+          taskName: item.taskName,
+          sendname: item.sendname,
+        }));
+    },
+    checkSelectable(row, index) {
+      // 褰� sendstate 涓� 6 鏃朵笉鍙��
+      return row.sendstate !== 6;
+    },
+    openMergeDialog() {
+      if (this.selectedServices.length < 2) {
+        this.$message.warning("璇疯嚦灏戦�夋嫨2涓棶鍗锋湇鍔¤繘琛屽悎骞�");
+        return;
+      }
+      this.mergeDialogVisible = true;
+    },
+
+    handleMergeSave(mergedData) {
+      // 澶勭悊鍚堝苟淇濆瓨閫昏緫
+      this.mergeDialogVisible = false;
+      this.isMergeMode = false;
+      this.selectedServices = [];
+
+      // 鏄剧ず淇濆瓨缁撴灉
+      if (mergedData.successCount == mergedData.totalCount) {
+        this.$message.success(`鎴愬姛淇濆瓨 ${mergedData.successCount} 涓棶鍗穈);
+      } else if (mergedData.successCount > 0) {
+        this.$message.warning(
+          `鎴愬姛淇濆瓨 ${mergedData.successCount} 涓棶鍗凤紝澶辫触 ${
+            mergedData.totalCount - mergedData.successCount
+          } 涓猔
+        );
+      } else {
+        this.$message.error("鎵�鏈夐棶鍗蜂繚瀛樺け璐�");
+      }
+
+      // 鍒锋柊鏁版嵁
+      this.getTaskservelist();
+    },
+  },
+  // deactivated() {
+  //   console.log(11);
+  // },
+  beforeRouteLeave(to, from, next) {
+    this.$refs.callButton.cleanupResources();
+    if (this.$refs.CallCenterLs) {
+      console.log(1);
+
+      this.$refs.CallCenterLs.handleSeatLogout();
+    }
+    next(); // 纭繚璋冪敤 nex
+  },
+  // beforeRouteUpdate() {
+  //   console.log(33);
+  // },
+};
+</script>
+
+<style lang="scss" scoped>
+.Followupdetailspage {
+  margin: 10px;
+  display: flex;
+  flex-direction: column;
+  gap: 20px;
+}
+
+.action-container {
+  display: flex;
+  gap: 20px;
+  margin: 0 10px 20px 10px;
+
+  .manual-action {
+    flex: 1;
+    min-width: 0;
+    height: 100%; /* 纭繚楂樺害缁ф壙 */
+  }
+
+  .call-action {
+    width: 60%;
+    min-width: 0;
+    height: 100%; /* 纭繚楂樺害缁ф壙 */
+  }
+}
+.numeric-input {
+  position: relative;
+}
+
+.numeric-input::after {
+  content: "鍙兘杈撳叆鏁板瓧";
+  position: absolute;
+  right: 8px;
+  top: 50%;
+  transform: translateY(-50%);
+  font-size: 12px;
+  color: #999;
+  background: #f5f5f5;
+  padding: 2px 6px;
+  border-radius: 4px;
+}
+.call-container {
+  padding: 20px;
+  background: #fff;
+  border: 1px solid #dcdfe6;
+  box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.12), 0 0 6px 0 rgba(0, 0, 0, 0.04);
+  border-radius: 4px;
+  height: 100%;
+
+  .call-header {
+    margin-bottom: 20px;
+
+    h2 {
+      font-size: 20px;
+      color: #333;
+      margin: 0;
+      padding-bottom: 10px;
+      border-bottom: 1px solid #eee;
+    }
+  }
+
+  .call-status {
+    margin-bottom: 20px;
+  }
+
+  .hangup-btn {
+    text-align: center;
+    margin-top: 20px;
+  }
+}
+.merge-controls {
+  background: #f5f7fa;
+  border-radius: 4px;
+  margin-left: 20px;
+}
+.Followuserinfo {
+  margin: 10px 10px 0 10px;
+  align-items: center;
+  padding: 30px;
+  background: #ffff;
+  border: 1px solid #dcdfe6;
+  box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.12), 0 0 6px 0 rgba(0, 0, 0, 0.04);
+
+  .userinfo-text {
+    font-size: 20px;
+    margin-right: 20px;
+    margin-bottom: 10px;
+  }
+
+  .userinfo-value {
+    color: rgb(15, 139, 211);
+
+    span {
+      margin-right: 20px;
+    }
+  }
+}
+
+::v-deep.el-table .warning-row {
+  background: #c4e2ee;
+}
+
+.Followuserinfos {
+  align-items: center;
+  padding: 30px;
+  background: #ffff;
+  border: 1px solid #dcdfe6;
+  box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.12), 0 0 6px 0 rgba(0, 0, 0, 0.04);
+  height: 100%; /* 纭繚楂樺害缁ф壙 */
+  min-height: 880px; /* 鏈�灏忛珮搴︿笌闅忚鍐呭涓�鑷� */
+  display: flex;
+  flex-direction: column;
+
+  .userinfo-text {
+    font-size: 20px;
+    margin-right: 20px;
+    margin-bottom: 10px;
+  }
+
+  .userinfo-value {
+    color: rgb(15, 139, 211);
+
+    span {
+      margin-right: 20px;
+    }
+  }
+
+  .el-form {
+    flex: 1;
+    overflow-y: auto; /* 鍐呭瓒呰繃楂樺害鏃舵樉绀烘粴鍔ㄦ潯 */
+    max-height: calc(880px - 60px); /* 鍑忓幓padding */
+    padding-right: 10px; /* 闃叉婊氬姩鏉¢伄鎸″唴瀹� */
+  }
+}
+.append-input-container {
+  margin-top: 15px;
+  padding: 10px;
+  background-color: #f5f7fa;
+  border-radius: 4px;
+  border: 1px solid #dcdfe6;
+}
+.borderdiv {
+  min-height: 60vh;
+  font-size: 20px;
+  padding: 30px;
+
+  .title {
+    font-size: 22px;
+    font-weight: bold;
+    margin-bottom: 20px;
+    text-align: center;
+  }
+
+  .leftside {
+    margin: 30px 0;
+
+    span {
+      width: 400px;
+      margin-left: 20px;
+      padding: 10px;
+      color: #fff;
+      background: rgb(110, 196, 247);
+      border-radius: 10px;
+    }
+  }
+
+  .offside {
+    display: flex;
+    flex-direction: row-reverse;
+
+    .offside-value {
+      padding: 10px;
+      background: rgb(217, 173, 253);
+      border-radius: 10px;
+      color: #fff;
+      margin-right: 20px;
+    }
+  }
+}
+.topic-dev[inert] {
+  opacity: 0.5;
+  pointer-events: none;
+}
+.CONTENT {
+  padding: 10px;
+  height: 100%;
+  min-height: 738px; /* 璁剧疆鏈�灏忛珮搴� */
+
+  .title {
+    font-size: 22px;
+    font-weight: bold;
+    margin-bottom: 20px;
+    text-align: center;
+  }
+}
+
+.preview-left {
+  margin: 20px;
+  padding: 30px;
+  border: 1px solid #dcdfe6;
+  box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.12), 0 0 6px 0 rgba(0, 0, 0, 0.04);
+  max-height: 618px; /* 璁剧疆鏈�澶ч珮搴� */
+  overflow-y: auto; /* 鍐呭瓒呰繃楂樺害鏃舵樉绀烘粴鍔ㄦ潯 */
+
+  .topic-dev {
+    margin-bottom: 25px;
+    font-size: 20px !important;
+
+    .dev-text {
+      margin-bottom: 10px;
+    }
+  }
+}
+
+.scriptTopic-isabnormal {
+  color: red;
+}
+
+.detailed {
+  width: 88%;
+  border-radius: 8px;
+  padding: 30px;
+  margin-bottom: 30px;
+  background-color: #ddf0f8;
+
+  .bg-purple {
+    margin-bottom: 20px;
+  }
+
+  .spanvalue {
+    display: inline-block;
+    min-width: 200px;
+    border-bottom: 1px solid rgb(172, 172, 172);
+  }
+}
+
+.headline {
+  font-size: 24px;
+  height: 40px;
+  border-left: 5px solid #41a1be;
+  padding-left: 5px;
+  margin-bottom: 10px;
+  display: flex;
+
+  .Add-details {
+    font-size: 18px;
+    color: #02a7f0;
+    cursor: pointer;
+  }
+}
+
+/* 寮傚父鐘舵�佹牱寮� - 绾㈣壊 (淇濇寔涓嶅彉) */
+.scriptTopic-isabnormal {
+  color: red;
+}
+
+/* 鏂板锛氳鍛婄姸鎬佹牱寮� - 榛勮壊 */
+.scriptTopic-warning {
+  color: #d4be00; /* 鎮ㄦ寚瀹氱殑榛勮壊 */
+
+}
+
+/* 寮傚父閫夐」鏍峰紡 - 绾㈣壊鏄熷彿 (淇濇寔涓嶅彉) */
+.red-star {
+  ::v-deep.el-radio__label {
+    position: relative;
+    padding-right: 10px;
+  }
+
+  ::v-deep.el-radio__label::after {
+    content: "*";
+    color: red;
+    position: absolute;
+    right: -5px;
+    top: 0;
+  }
+}
+
+/* 鏂板锛氳鍛婇�夐」鏍峰紡 - 榛勮壊鏄熷彿 */
+.yellow-star {
+  ::v-deep.el-radio__label {
+    position: relative;
+    padding-right: 10px;
+  }
+
+  ::v-deep.el-radio__label::after {
+    content: "*";
+    color: #ffe202; /* 榛勮壊鏄熷彿 */
+    position: absolute;
+    right: -5px;
+    top: 0;
+    font-weight: bold;
+  }
+}
+
+/* 鍏辩敤鏍峰紡淇濇寔涓嶅彉 */
+::v-deep.el-input-group__textarea {
+  white-space: pre-wrap;
+  word-break: break-all;
+}
+
+::v-deep.el-checkbox__label {
+  position: relative;
+  padding-right: 10px;
+}
+
+::v-deep.el-checkbox__label::after {
+  content: "*";
+  color: red;
+  position: absolute;
+  right: -5px;
+  top: 0;
+}
+.tag-selector-container {
+  display: flex;
+  align-items: center;
+  margin: 0 30px;
+}
+
+.color-indicator {
+  width: 16px;
+  height: 16px;
+  border-radius: 3px;
+  margin-right: 8px;
+  display: inline-block;
+}
+
+.selected-indicator {
+  margin-left: 10px;
+  width: 20px;
+  height: 20px;
+}
+
+.tag-info-icon {
+  margin-left: 10px;
+  color: #909399;
+  cursor: pointer;
+  font-size: 16px;
+}
+
+/* 纭繚閫夋嫨鍣ㄩ�夐」涓篃鏄剧ず棰滆壊鍧� */
+.el-select-dropdown__item {
+  display: flex;
+  align-items: center;
+}
+
+.tag-normal {
+  background-color: #7ff5e1;
+}
+.tag-abnormal {
+  background-color: #f75c5c;
+}
+.tag-warning {
+  background-color: #fbfb4a;
+}
+
+.tag-info {
+  margin-left: 10px;
+  color: #909399;
+  cursor: pointer;
+}
+::v-deep.offside-value .el-radio__label {
+  color: #fff;
+}
+
+::v-deep.el-link.el-link--default {
+  color: #02a7f0 !important;
+}
+
+.el-message-box__btns button:nth-child(2) {
+  margin-left: 10px;
+  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;
+}
+/* 鍘熸湁鐨勬牱寮忎繚鎸佷笉鍙橈紝娣诲姞浠ヤ笅鍝嶅簲寮忎唬鐮� */
+
+.Followupdetailspage {
+  margin: 10px;
+  display: flex;
+  flex-direction: column;
+  gap: 20px;
+}
+
+.action-container {
+  display: flex;
+  flex-direction: row; /* 榛樿妯悜鎺掑垪 */
+  gap: 20px;
+  margin: 0 10px 20px 10px;
+
+  /* 褰撶缉鏀炬瘮渚嬪ぇ浜�100%鎴栧睆骞曞搴﹁緝灏忔椂鏀逛负涓婁笅鎺掑垪 */
+  @media screen and (min-resolution: 1.5dppx) {
+    flex-direction: column;
+
+    .call-action,
+    .manual-action {
+      width: 100% !important;
+    }
+  }
+}
+
+.call-action {
+  width: 65%;
+  min-width: 0;
+}
+
+.manual-action {
+  flex: 1;
+  min-width: 0;
+}
+
+/* 璋冩暣鍐呴儴鍏冪礌鐨勫搷搴斿紡甯冨眬 */
+.Followuserinfos {
+  .el-form {
+    /* 琛ㄥ崟鍝嶅簲寮忚皟鏁� */
+    .el-row {
+      margin: 0 -10px;
+    }
+
+    .el-col {
+      padding: 0 10px;
+    }
+
+    @media screen and (max-width: 768px) {
+      .el-col {
+        width: 100%;
+        margin-bottom: 15px;
+
+        &:last-child {
+          margin-bottom: 0;
+        }
+      }
+    }
+  }
+}
+
+/* 璋冩暣琛ㄦ牸鐨勫搷搴斿紡琛ㄧ幇 */
+.el-table {
+  ::v-deep .el-table__body-wrapper {
+    overflow-x: auto;
+  }
+
+  /* 鍦ㄥ皬灞忓箷涓婅皟鏁磋〃鏍煎垪瀹� */
+  @media screen and (max-width: 992px) {
+    .el-table-column {
+      min-width: 120px;
+    }
+  }
+}
+
+/* 璋冩暣鏍囩閫夋嫨鍣ㄧ殑鍝嶅簲寮忓竷灞� */
+.tag-selector-container {
+  display: flex;
+  align-items: center;
+  flex-wrap: wrap;
+  gap: 10px;
+
+  @media screen and (max-width: 576px) {
+    flex-direction: column;
+    align-items: flex-start;
+
+    .el-select {
+      width: 100%;
+      margin-right: 0 !important;
+    }
+  }
+}
+
+/* 璋冩暣鎸夐挳缁勭殑鍝嶅簲寮忓竷灞� */
+.el-form-item.label-processing-opinion {
+  .el-button-group {
+    display: flex;
+    flex-wrap: wrap;
+    gap: 10px;
+
+    .el-button {
+      flex: 1;
+      min-width: 120px;
+    }
+  }
+}
+
+/* 璋冩暣閫夐」鍗$殑鍝嶅簲寮忚〃鐜� */
+.el-tabs {
+  ::v-deep .el-tabs__nav-wrap {
+    overflow-x: auto;
+    white-space: nowrap;
+
+    &::after {
+      display: none;
+    }
+  }
+}
+
+/* 璋冩暣棰勮鍖哄煙鐨勫搷搴斿紡琛ㄧ幇 */
+.preview-left {
+  @media screen and (max-width: 768px) {
+    margin: 10px;
+    padding: 15px;
+
+    .topic-dev,
+    .scriptTopic-dev {
+      margin-bottom: 15px;
+    }
+  }
+}
+
+/* 璋冩暣瀵硅瘽妗嗙殑鍝嶅簲寮忚〃鐜� */
+.el-dialog {
+  @media screen and (max-width: 992px) {
+    width: 90% !important;
+    margin-top: 5vh !important;
+
+    .el-dialog__body {
+      padding: 15px;
+    }
+  }
+
+  @media screen and (max-width: 576px) {
+    width: 95% !important;
+
+    .el-form-item {
+      margin-bottom: 15px;
+    }
+  }
+}
+
+/* 纭繚鍐呭鍦ㄧ缉鏀炬椂淇濇寔鍙鎬� */
+.headline {
+  font-size: clamp(18px, 2vw, 24px); /* 浣跨敤clamp鍑芥暟纭繚瀛椾綋澶у皬鍦ㄥ悎鐞嗚寖鍥村唴 */
+}
+
+/* 涓虹Щ鍔ㄨ澶囦紭鍖栨粴鍔ㄤ綋楠� */
+@media screen and (max-width: 768px) {
+  .Followuserinfo,
+  .Followuserinfos {
+    padding: 15px;
+    margin: 5px;
+  }
+
+  .CONTENT {
+    min-height: auto;
+    padding: 5px;
+  }
+}
+
+/* 缂╂斁妫�娴嬫牱寮� */
+@media screen and (min-resolution: 1.5dppx),
+  screen and (-webkit-min-device-pixel-ratio: 1.5) {
+  .action-container {
+    flex-direction: column;
+  }
+
+  .call-action,
+  .manual-action {
+    width: 100%;
+  }
+
+  /* 璋冩暣鍐呴儴鍏冪礌闂磋窛 */
+  .call-container,
+  .Followuserinfos {
+    margin-bottom: 20px;
+  }
+}
+</style>
diff --git a/src/views/followvisit/record/detailpage/index copy.vue b/src/views/followvisit/record/detailpage/index copy.vue
new file mode 100644
index 0000000..e06e792
--- /dev/null
+++ b/src/views/followvisit/record/detailpage/index copy.vue
@@ -0,0 +1,3703 @@
+<template>
+  <!-- 鑱婅繛椤甸潰璁板綍 -->
+  <div class="Followupdetailspage" id="app-container">
+    <div class="Followuserinfo">
+      <div>
+        <div class="userinfo-text">
+          <!-- <span>鎮h�呮湇鍔¤鎯�</span> -->
+          <div class="headline">
+            <div>鎮h�呮湇鍔¤鎯�</div>
+            <div style="margin-left: 20px">
+              <el-button
+                v-if="!Whetherall"
+                type="primary"
+                @click="getTaskservelist()"
+                >鏌ョ湅鎮h�呭叏閮ㄦ湇鍔�</el-button
+              >
+              <el-button v-else type="success" @click="getTaskservelist(id)"
+                >鍙睍绀烘湰娆℃湇鍔′俊鎭�</el-button
+              >
+            </div>
+            <!-- <div style="margin-left: 20px; color: #59a0f0">
+              <el-link
+                href="https://9.208.2.207:6060/search-homepage"
+                target="_blank"
+                :underline="true"
+              >
+                鍓嶅線CDSS鏌ヨ
+              </el-link>
+            </div> -->
+            <div class="merge-controls" v-if="Whetherall">
+              <el-button
+                type="primary"
+                @click="toggleMergeMode"
+                :disabled="selectedServices.length < 2"
+              >
+                {{ isMergeMode ? "鍙栨秷鍚堝苟" : "鍚堝苟缂栬緫闂嵎" }}
+              </el-button>
+              <el-button
+                v-if="isMergeMode"
+                type="success"
+                @click="openMergeDialog"
+                :disabled="selectedServices.length < 2"
+              >
+                寮�濮嬪悎骞� (宸查�� {{ selectedServices.length }} 涓湇鍔�)
+              </el-button>
+            </div>
+          </div>
+          <!-- <el-button type="success">闅忚鍚庣煭淇�</el-button> -->
+        </div>
+      </div>
+      <div>
+        <el-table
+          :data="logsheetlist"
+          :row-class-name="tableRowClassName"
+          :max-height="350"
+          style="width: 100%"
+          @selection-change="handleSelectionChange"
+        >
+          <el-table-column
+            type="selection"
+            width="55"
+            :selectable="checkSelectable"
+            v-if="Whetherall"
+          ></el-table-column>
+          <el-table-column
+            prop="sendname"
+            align="center"
+            label="濮撳悕"
+            width="100"
+          >
+            <template slot-scope="scope">
+              <el-button
+                size="medium"
+                type="text"
+                @click="
+                  gettoken360(
+                    scope.row.sfzh,
+                    scope.row.drcode,
+                    scope.row.drname
+                  )
+                "
+                ><span class="button-textsc">{{
+                  scope.row.sendname
+                }}</span></el-button
+              >
+            </template>
+          </el-table-column>
+          <el-table-column
+            prop="taskName"
+            align="center"
+            width="200"
+            show-overflow-tooltip
+            label="浠诲姟鍚嶇О"
+          >
+          </el-table-column>
+          <el-table-column
+            prop="sendstate"
+            align="center"
+            width="200"
+            label="浠诲姟鐘舵��"
+          >
+            <template slot-scope="scope">
+              <div v-if="scope.row.sendstate == 1">
+                <el-tag type="primary" :disable-transitions="false"
+                  >琛ㄥ崟宸查鍙�</el-tag
+                >
+              </div>
+              <div v-if="scope.row.sendstate == 2">
+                <el-tag type="primary" :disable-transitions="false"
+                  >寰呴殢璁�</el-tag
+                >
+              </div>
+              <div v-if="scope.row.sendstate == 3">
+                <el-tag type="success" :disable-transitions="false"
+                  >琛ㄥ崟宸插彂閫�</el-tag
+                >
+              </div>
+              <div v-if="scope.row.sendstate == 4">
+                <el-tag type="info" :disable-transitions="false">涓嶆墽琛�</el-tag>
+              </div>
+              <div v-if="scope.row.sendstate == 5">
+                <el-tag type="danger" :disable-transitions="false"
+                  >鍙戦�佸け璐�</el-tag
+                >
+              </div>
+              <div v-if="scope.row.sendstate == 6">
+                <el-tag type="success" :disable-transitions="false"
+                  >宸插畬鎴�</el-tag
+                >
+              </div>
+              <div v-if="scope.row.sendstate == 7">
+                <el-tag type="danger" :disable-transitions="false">瓒呮椂</el-tag>
+              </div>
+            </template>
+          </el-table-column>
+          <el-table-column
+            prop="finishtime"
+            align="center"
+            label="闅忚瀹屾垚鏃堕棿"
+            width="200"
+            show-overflow-tooltip
+          >
+          </el-table-column>
+          <el-table-column
+            label="鍑洪櫌鏃ユ湡"
+            width="200"
+            align="center"
+            key="endtime"
+            prop="endtime"
+          >
+            <template slot-scope="scope">
+              <span>{{ formatTime(scope.row.endtime) }}</span>
+            </template></el-table-column
+          >
+          <el-table-column
+            label="璐d换鎶ゅ+"
+            width="120"
+            align="center"
+            key="nurseName"
+            prop="nurseName"
+          />
+          <el-table-column
+            label="涓绘不鍖荤敓"
+            width="120"
+            align="center"
+            key="drname"
+            prop="drname"
+          />
+
+          <el-table-column
+            label="缁撴灉鐘舵��"
+            align="center"
+            key="excep"
+            prop="excep"
+            width="120"
+          >
+            <template slot-scope="scope">
+              <dict-tag
+                :options="dict.type.sys_yujing"
+                :value="scope.row.excep"
+              />
+            </template>
+          </el-table-column>
+          <el-table-column
+            label="澶勭悊鎰忚"
+            align="center"
+            key="suggest"
+            prop="suggest"
+            width="120"
+          >
+            <template slot-scope="scope">
+              <dict-tag
+                :options="dict.type.sys_suggest"
+                :value="scope.row.suggest"
+              />
+            </template>
+          </el-table-column>
+
+          <el-table-column
+            prop="templatename"
+            align="center"
+            label="鏈嶅姟妯℃澘"
+            width="200"
+            show-overflow-tooltip
+          >
+          </el-table-column>
+          <el-table-column
+            prop="remark"
+            align="center"
+            label="鏈嶅姟璁板綍"
+            width="200"
+            show-overflow-tooltip
+          >
+          </el-table-column>
+
+          <el-table-column
+            prop="bankcardno"
+            align="center"
+            label="鍛煎彨鐘舵��"
+            width="210"
+          >
+          </el-table-column>
+          <el-table-column
+            label="鎿嶄綔"
+            fixed="right"
+            align="center"
+            width="200"
+            class-name="small-padding fixed-width"
+          >
+            <template slot-scope="scope">
+              <el-button
+                size="medium"
+                type="text"
+                @click="Seedetails(scope.row)"
+                ><span class="button-zx"
+                  ><i class="el-icon-s-order"></i>鏌ョ湅</span
+                ></el-button
+              >
+            </template>
+          </el-table-column>
+        </el-table>
+      </div>
+    </div>
+    <!-- 娣诲姞鍚堝苟缂栬緫瀵硅瘽妗� -->
+    <el-dialog
+      title="鍚堝苟缂栬緫闂嵎"
+      :visible.sync="mergeDialogVisible"
+      width="80%"
+      top="5vh"
+      v-dialogDrag
+    >
+      <MergeAndModify
+        v-if="mergeDialogVisible"
+        :selected-services="selectedServices"
+        :patid="patid"
+        @save="handleMergeSave"
+        @cancel="mergeDialogVisible = false"
+      />
+    </el-dialog>
+    <div class="action-container">
+      <!-- 闅忚鍐呭 -->
+      <div class="call-action">
+        <div class="call-container">
+          <!-- <div class="call-header">
+            <h2>涓�閿懠鍙姛鑳�</h2>
+          </div> -->
+
+          <div class="headline">
+            <div>闅忚鍐呭</div>
+          </div>
+          <div>
+            <el-tabs v-model="activeName" type="border-card">
+              <el-tab-pane name="wj">
+                <span class="mulsz" slot="label"
+                  ><i class="el-icon-notebook-1"></i> 闂嵎闅忚缁撴灉</span
+                >
+                <div class="CONTENT">
+                  <div class="title">{{ taskname ? taskname : "闂嵎" }}</div>
+
+                  <div class="preview-left" v-if="!Voicetype">
+                    <div
+                      class="topic-dev"
+                      v-for="(item, index) in tableDatatop"
+                      :key="item.id"
+                    >
+                      <!-- 鍗曢�� -->
+                      <div
+                        :class="getTopicClass(item)"
+                        :key="index"
+                        v-if="item.scriptType == 1 && !item.astrict"
+                      >
+                        <div class="dev-text">
+                          {{ index + 1 }}銆乕鍗曢�塢<span>{{
+                            item.scriptContent
+                          }}</span>
+                        </div>
+                        <div class="dev-xx">
+                          <el-radio-group v-model="item.scriptResult">
+                            <el-radio
+                              v-for="(
+                                items, indexs
+                              ) in item.svyTaskTemplateTargetoptions"
+                              :class="getOptionClass(items)"
+                              :key="indexs"
+                              :label="items.optioncontent"
+                              @click.native.prevent="
+                                handleRadioToggle(
+                                  item,
+                                  index,
+                                  item.svyTaskTemplateTargetoptions,
+                                  items.optioncontent
+                                )
+                              "
+                              >{{ items.optioncontent }}</el-radio
+                            >
+                          </el-radio-group>
+                        </div>
+                        <div
+                          v-if="item.showAppendInput || item.answerps"
+                          class="append-input-container"
+                        >
+                          <el-input
+                            type="textarea"
+                            :rows="2"
+                            placeholder="璇疯緭鍏ュ叿浣撲俊鎭�"
+                            v-model="item.answerps"
+                            clearable
+                          ></el-input>
+                        </div>
+                        <div v-show="item.prompt">
+                          <el-alert :title="item.prompt" type="warning">
+                          </el-alert>
+                        </div>
+                      </div>
+                      <!-- 澶氶�� -->
+                      <div
+                        :class="
+                          item.isabnormal
+                            ? 'scriptTopic-isabnormal'
+                            : 'scriptTopic-dev'
+                        "
+                        :key="index"
+                        v-if="item.scriptType == 2 && !item.astrict"
+                      >
+                        <div class="dev-text">
+                          {{ index + 1 }}銆乕澶氶�塢<span>{{
+                            item.scriptContent
+                          }}</span>
+                        </div>
+                        <div class="dev-xx">
+                          <el-checkbox-group
+                            v-model="item.scriptResult"
+                            @change="updateScore($event, index, item)"
+                          >
+                            <el-checkbox
+                              :class="items.isabnormal ? 'red-star' : ''"
+                              @change="$forceUpdate()"
+                              v-for="(
+                                items, indexs
+                              ) in item.svyTaskTemplateTargetoptions"
+                              :key="indexs"
+                              :label="items.optioncontent"
+                            >
+                              {{ items.optioncontent }}
+                            </el-checkbox>
+                          </el-checkbox-group>
+                        </div>
+                        <div v-show="item.prompt && item.scriptResult[0]">
+                          <el-alert :title="item.prompt" type="warning">
+                          </el-alert>
+                        </div>
+                      </div>
+                      <!-- 濉┖ -->
+                      <div
+                        class="scriptTopic-dev"
+                        :key="index"
+                        v-if="item.scriptType == 4 && !item.astrict"
+                      >
+                        <div class="dev-text">
+                          {{ index + 1 }}銆乕闂瓟]<span>{{
+                            item.scriptContent
+                          }}</span>
+                          <span v-if="item.valueType == 3">(鍙兘杈撳叆鏁板瓧)</span>
+                        </div>
+                        <div class="dev-xx" v-if="item.valueType == 3">
+                          <el-input
+                            type="text"
+                            v-numeric-only
+                            placeholder="璇疯緭鍏ョ瓟妗�"
+                            v-model="item.scriptResult"
+                          >
+                          </el-input>
+                        </div>
+                        <div class="dev-xx" v-else>
+                          <el-input
+                            type="textarea"
+                            :rows="2"
+                            placeholder="璇疯緭鍏ョ瓟妗�"
+                            v-model="item.scriptResult"
+                            clearable
+                          >
+                          </el-input>
+                        </div>
+                      </div>
+                    </div>
+                  </div>
+
+                  <div class="preview-left" v-else>
+                    <div
+                      class="topic-dev"
+                      v-for="(item, index) in tableDatatop"
+                      :key="item.id"
+                    >
+                      <div v-if="item.targetvalue">
+                        <div class="dev-text">
+                          {{ index + 1 }}銆乕鍗曢�塢<span>{{
+                            item.questiontext
+                          }}</span>
+                        </div>
+                        <div class="dev-xx">
+                          <el-radio-group
+                            v-model="item.matchedtext"
+                            @change="
+                              handleOptionChange(
+                                $event,
+                                index,
+                                item.ivrTaskScriptTargetoptionList,
+                                item
+                              )
+                            "
+                          >
+                            <el-radio
+                              v-for="(items, index) in item.scriptResult"
+                              :key="index"
+                              :label="items"
+                              :class="items.isabnormal ? 'red-star' : ''"
+                              >{{ items }}</el-radio
+                            >
+                          </el-radio-group>
+                        </div>
+                        <div v-show="item.prompt">
+                          <el-alert :title="item.prompt" type="warning">
+                          </el-alert>
+                        </div>
+                      </div>
+
+                      <div class="scriptTopic-dev" :key="index" v-else>
+                        <div class="dev-text">
+                          {{ index + 1 }}銆乕闂瓟]<span>{{
+                            item.scriptContent
+                          }}</span>
+                          <span v-if="item.valueType == 3">(鍙兘杈撳叆鏁板瓧)</span>
+                        </div>
+                        <div class="dev-xx" v-if="item.valueType == 3">
+                          <el-input
+                            type="text"
+                            v-numeric-only
+                            placeholder="璇疯緭鍏ョ瓟妗�"
+                            v-model="item.scriptResult"
+                          >
+                          </el-input>
+                        </div>
+                        <div class="dev-xx" v-else>
+                          <el-input
+                            type="textarea"
+                            :rows="2"
+                            placeholder="璇疯緭鍏ョ瓟妗�"
+                            v-model="item.scriptResult"
+                            clearable
+                          >
+                          </el-input>
+                        </div>
+                      </div>
+                    </div>
+                  </div>
+                  <el-button
+                    v-if="Voicetype"
+                    type="primary"
+                    @click="yuyingetdetail"
+                    >淇濆瓨鏈嶅姟璇︽儏</el-button
+                  >
+                  <el-button v-else type="primary" @click="getdetail"
+                    >淇濆瓨鏈嶅姟璇︽儏</el-button
+                  >
+                </div>
+              </el-tab-pane>
+
+              <el-tab-pane name="yy">
+                <span class="mulsz" slot="label"
+                  ><i class="el-icon-headset"></i> 璇煶闅忚璇︽儏</span
+                >
+                <div class="borderdiv">
+                  <div class="title">{{ taskname ? taskname : "闂嵎" }}</div>
+                  <div
+                    style="
+                      display: flex;
+                      text-align: center;
+                      align-items: center;
+                      color: #59a0f0;
+                    "
+                  >
+                    瀹屾暣璇煶锛�
+                    <mini-audio
+                      :audio-source="
+                        voice ? voice : '@assets/order/example.mp3'
+                      "
+                    ></mini-audio>
+                  </div>
+                  <div class="preview-left">
+                    <div v-for="item in voiceDatatop">
+                      <div class="leftside">
+                        <i class="el-icon-phone-outline"></i
+                        ><span>{{ item.questiontext }}</span>
+                      </div>
+                      <div class="offside">
+                        <i class="el-icon-user"></i>
+                        <div class="offside-value">
+                          <el-input
+                            type="textarea"
+                            :autosize="{ minRows: 1 }"
+                            v-model="item.asrtext"
+                          ></el-input>
+
+                          <div>
+                            <mini-audio
+                              :audio-source="
+                                item.questionvoice
+                                  ? item.questionvoice
+                                  : '@assets/order/example.mp3'
+                              "
+                            ></mini-audio>
+                          </div>
+                        </div>
+                      </div>
+                    </div>
+                  </div>
+                  <el-button
+                    v-if="Voicetype"
+                    type="primary"
+                    @click="yuyingetdetail"
+                    >淇濆瓨闅忚璇︽儏</el-button
+                  >
+                  <el-button v-else type="primary" @click="getdetail"
+                    >淇濆瓨闅忚璇︽儏</el-button
+                  >
+                </div>
+              </el-tab-pane>
+            </el-tabs>
+          </div>
+        </div>
+      </div>
+      <!-- 浜哄伐澶勭悊 -->
+      <div class="manual-action">
+        <div class="Followuserinfos">
+          <!-- 椤堕儴鎿嶄綔鍖哄煙 -->
+          <div class="section-header">
+            <h3><i class="el-icon-s-operation"></i> 浜哄伐澶勭悊</h3>
+            <div class="header-actions">
+              <!-- 鍩虹鎿嶄綔鎸夐挳缁� -->
+              <div class="action-group basic-actions">
+                <el-button
+                  type="primary"
+                  plain
+                  @click="Editsingletasksonyic('')"
+                >
+                  淇濆瓨鍩虹淇℃伅
+                </el-button>
+
+                <!-- 鏂板锛氬欢缁姢鐞嗘寜閽� -->
+                <el-button
+                  type="success"
+                  plain
+                  @click="handleContinuationCare"
+                  v-if="showContinuationCareBtn"
+                >
+                  寤剁画鎶ょ悊
+                </el-button>
+
+                <el-button
+                  type="primary"
+                  round
+                  @click="sendAgain"
+                  v-if="form.isVisitAgain != 2"
+                >
+                  鍐嶆闅忚
+                </el-button>
+              </div>
+
+              <!-- 寮傚父鐘舵�侀�夋嫨鍣� -->
+              <div class="action-group tag-selector">
+                <el-select
+                  v-model="selectedTag"
+                  placeholder="璇烽�夋嫨寮傚父鐘舵��"
+                  clearable
+                  style="width: 150px; margin-right: 10px"
+                >
+                  <el-option
+                    v-for="item in tagOptions"
+                    :key="item.value"
+                    :label="item.label"
+                    :value="item.value"
+                  >
+                    <span style="display: flex; align-items: center">
+                      <span
+                        class="color-indicator"
+                        :style="{ backgroundColor: item.color }"
+                      ></span>
+                      <span>{{ item.label }}</span>
+                    </span>
+                  </el-option>
+                </el-select>
+
+                <!-- 褰撳墠閫夋嫨鐨勯鑹叉寚绀哄櫒 -->
+                <div
+                  v-if="selectedTag"
+                  class="color-indicator selected-indicator"
+                  :style="{ backgroundColor: getSelectedTagColor() }"
+                ></div>
+
+                <!-- 鏍囪璇存槑鎻愮ず -->
+                <el-tooltip
+                  v-if="selectedTag"
+                  effect="light"
+                  :content="getSelectedDescription()"
+                  placement="top"
+                >
+                  <i class="el-icon-info tag-info-icon"></i>
+                </el-tooltip>
+              </div>
+            </div>
+          </div>
+
+          <!-- 琛ㄥ崟鍖哄煙 -->
+          <div class="form-content">
+            <el-form
+              ref="userform"
+              :model="form"
+              :rules="userrules"
+              label-width="100px"
+            >
+              <!-- 鑱旂郴淇℃伅琛� -->
+              <el-row>
+                <el-col :span="14">
+                  <el-form-item label="鑱旂郴鐢佃瘽">
+                    <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="10">
+                  <el-form-item
+                    label="鐭彿鐢佃瘽"
+                    v-if="orgname == '鏅畞鐣叉棌鑷不鍘夸汉姘戝尰闄�'"
+                  >
+                    <el-input
+                      placeholder="鑱旂郴鐢佃瘽缂哄け"
+                      v-model="userform.telshortcode"
+                    >
+                      <el-button
+                        slot="append"
+                        icon="el-icon-phone"
+                        @click="handleCall(userform.telshortcode, 'tel', true)"
+                      ></el-button>
+                    </el-input>
+                  </el-form-item>
+                </el-col>
+              </el-row>
+
+              <!-- 鑱旂郴浜轰俊鎭 -->
+              <el-row>
+                <el-col :span="14">
+                  <el-form-item label="鑱旂郴浜虹數璇�">
+                    <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="9">
+                  <el-form-item label="鍏崇郴">
+                    <el-input
+                      placeholder="鑱旂郴浜哄叧绯荤己澶�"
+                      v-model="userform.relation"
+                    ></el-input>
+                  </el-form-item>
+                </el-col>
+              </el-row>
+
+              <!-- 閫氳瘽鎺у埗鍖哄煙 -->
+              <div class="call-controls">
+                <CallButton
+                  ref="callButton"
+                  :phoneNumber="currentPhoneNumber"
+                  style="display: none"
+                />
+
+                <!-- 鎸傛柇鎸夐挳鏍峰紡浼樺寲 -->
+                <div v-if="callStatus === 'connected'" class="hangup-container">
+                  <el-button
+                    type="danger"
+                    icon="el-icon-phone"
+                    @click="endCurrentCall"
+                    :loading="isEndingCall"
+                    class="hangup-btn"
+                    size="medium"
+                  >
+                    {{ isEndingCall ? "鎸傛柇涓�..." : "鎸傛柇鐢佃瘽" }}
+                  </el-button>
+
+                  <!-- 閫氳瘽璁℃椂鏄剧ず -->
+                  <div class="call-timer" v-if="callStartTime">
+                    閫氳瘽鏃堕暱: {{ formatCallTime }}
+                  </div>
+                </div>
+
+                <!-- 鐘舵�佹彁绀轰紭鍖� -->
+                <div class="call-status-container" v-if="callStatus !== 'idle'">
+                  <el-alert
+                    :title="callStatusText"
+                    :type="callStatusType"
+                    :closable="false"
+                    show-icon
+                    :class="['status-alert', `status-${callStatus}`]"
+                  />
+                </div>
+
+                <!-- SIP娉ㄥ唽鐘舵�佹彁绀� -->
+                <div
+                  v-if="isSipRegistering && orgname == '涓芥按甯備腑鍖婚櫌'"
+                  class="sip-registering"
+                >
+                  <el-alert
+                    title="鍛煎彨搴ф満鍒濆鍖栦腑锛岃绋嶅��..."
+                    type="info"
+                    :closable="false"
+                    show-icon
+                    class="registering-alert"
+                  />
+                </div>
+              </div>
+
+              <!-- 闅忚鍐呭/璁板綍 -->
+              <el-form-item
+                :label="orgname == '涓芥按甯備腑鍖婚櫌' ? '闅忚鍐呭' : '闅忚璁板綍'"
+              >
+                <el-input type="textarea" v-model="form.remark"></el-input>
+              </el-form-item>
+
+              <!-- 闅忚鎯呭喌 -->
+              <el-form-item label="闅忚鎯呭喌" v-if="orgname == '涓芥按甯備腑鍖婚櫌'">
+                <el-radio-group v-model="form.taskSituation">
+                  <el-radio
+                    v-for="city in cities"
+                    :label="city.value"
+                    :value="city.value"
+                    :key="city.value"
+                  >
+                    {{ city.label }}
+                  </el-radio>
+                </el-radio-group>
+              </el-form-item>
+
+              <!-- 澶勭悊鎰忚 -->
+              <el-form-item label="澶勭悊鎰忚">
+                <div class="opinion-buttons">
+                  <el-button
+                    plain
+                    type="warning"
+                    @click="Editsingletaskson('1')"
+                  >
+                    鏆備笉澶勭悊
+                  </el-button>
+                  <el-button
+                    plain
+                    type="success"
+                    @click="Editsingletaskson('2')"
+                  >
+                    鐥呮儏绋冲畾
+                  </el-button>
+                  <el-button
+                    plain
+                    type="primary"
+                    @click="Editsingletaskson('3')"
+                  >
+                    閫氱煡灏辫瘖
+                  </el-button>
+                  <el-button plain type="info" @click="Editsingletaskson('5')">
+                    浜哄伐闅忚
+                  </el-button>
+                  <el-button type="primary" round @click="sendAgainmsg">
+                    鐭俊鍙戦��
+                  </el-button>
+                </div>
+              </el-form-item>
+            </el-form>
+          </div>
+
+          <!-- 鎮h�呮。妗堜俊鎭� -->
+          <div class="detailed">
+            <h3>鎮h�呮。妗堜俊鎭�</h3>
+            <el-form ref="userform" :model="userform" label-width="100px">
+              <el-row :gutter="20">
+                <el-col :span="12">
+                  <el-form-item label="鎮h�呭鍚�" prop="name">
+                    <el-input
+                      v-model="userform.name"
+                      placeholder="璇疯緭鍏ュ鍚�"
+                      maxlength="30"
+                    ></el-input>
+                  </el-form-item>
+                </el-col>
+              </el-row>
+              <el-row :gutter="20">
+                <el-col :span="12">
+                  <el-form-item label="鎬у埆" prop="sex">
+                    <el-select v-model="userform.sex" placeholder="璇烽�夋嫨">
+                      <el-option label="鐢�" :value="1"> </el-option>
+                      <el-option label="濂�" :value="2"> </el-option>
+                    </el-select>
+                  </el-form-item>
+                </el-col>
+                <el-col :span="12">
+                  <el-form-item label="骞撮緞" prop="age">
+                    <el-input
+                      v-model="userform.age"
+                      placeholder="璇疯緭鍏ュ勾榫�"
+                      maxlength="20"
+                    ></el-input>
+                  </el-form-item>
+                </el-col>
+              </el-row>
+
+              <el-row :gutter="20">
+                <el-col :span="12">
+                  <el-form-item label="鑱旂郴鏂瑰紡" prop="telcode">
+                    <el-input
+                      v-model="userform.telcode"
+                      placeholder="璇疯緭鍏ヨ仈绯绘柟寮�"
+                      maxlength="20"
+                    />
+                  </el-form-item>
+                </el-col>
+                <el-col :span="12">
+                  <el-form-item label="浜插睘鑱旂郴鏂瑰紡" prop="relativetelcode">
+                    <el-input
+                      v-model="userform.relativetelcode"
+                      placeholder="璇疯緭鍏ヤ翰灞炶仈绯绘柟寮�"
+                      maxlength="20"
+                    ></el-input>
+                  </el-form-item>
+                </el-col>
+              </el-row>
+              <el-row :gutter="20">
+                <el-col :span="24">
+                  <el-form-item label="璇婃柇鍚嶇О" prop="leavediagname">
+                    <el-input
+                      v-model="form.leavediagname"
+                      placeholder="璇疯緭鍏ヨ瘖鏂�"
+                      maxlength="50"
+                    ></el-input>
+                  </el-form-item>
+                </el-col>
+              </el-row>
+              <el-row :gutter="20">
+                <el-col :span="24">
+                  <el-form-item label="鍑虹敓鍦�" prop="birthplace">
+                    <el-input
+                      v-model="userform.birthplace"
+                      placeholder="鍥姐�佺渷銆佸湴甯傘�佸尯鍘裤�佽閬撶瓑璇︾粏淇℃伅"
+                      maxlength="50"
+                    />
+                  </el-form-item>
+                </el-col>
+              </el-row>
+              <el-row :gutter="20">
+                <el-col :span="24">
+                  <el-form-item label="灞呬綇鍦�" prop="placeOfResidence">
+                    <el-input
+                      v-model="userform.placeOfResidence"
+                      placeholder="鍥姐�佺渷銆佸湴甯傘�佸尯鍘裤�佽閬撶瓑璇︾粏淇℃伅"
+                      maxlength="50"
+                    />
+                  </el-form-item>
+                </el-col>
+              </el-row>
+            </el-form>
+          </div>
+        </div>
+      </div>
+    </div>
+    <!-- 鐭俊鍙戦�佸璇濇 -->
+    <el-dialog title="鐭俊鍙戦��" :visible.sync="smsDialogVisible">
+      <!-- 娉ㄦ剰杩欓噷浣跨敤浜� smsDialogVisible 浠ュ尯鍒嗗凡鏈夌殑 dialogFormVisible -->
+      <el-form ref="smsForm" :model="form" label-width="80px">
+        <el-form-item label="鎮h�呭悕绉�">
+          <el-input
+            style="width: 400px"
+            disabled
+            v-model="form.sendname"
+          ></el-input>
+        </el-form-item>
+        <el-form-item label="骞撮緞">
+          <el-input style="width: 400px" disabled v-model="form.age"></el-input>
+        </el-form-item>
+        <el-form-item label="鐢佃瘽">
+          <el-input
+            style="width: 400px"
+            disabled
+            v-model="userform.telcode"
+          ></el-input>
+          <!-- 娉ㄦ剰杩欓噷鍙兘浣跨敤 userform.telcode -->
+        </el-form-item>
+        <el-form-item label="绉戝">
+          <el-input
+            style="width: 400px"
+            disabled
+            v-model="form.deptname"
+          ></el-input>
+        </el-form-item>
+        <el-form-item label="鐥呭尯">
+          <el-input
+            style="width: 400px"
+            disabled
+            v-model="form.leavehospitaldistrictname"
+          ></el-input>
+        </el-form-item>
+        <el-form-item label="鐭俊鍐呭">
+          <el-input type="textarea" v-model="smsContent"></el-input>
+          <!-- 寤鸿浣跨敤鐙珛鐨� smsContent 鍙橀噺 -->
+        </el-form-item>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button @click="smsDialogVisible = false">鍙� 娑�</el-button>
+        <el-button type="primary" @click="sendSms">纭鍙戦��</el-button>
+        <!-- 娉ㄦ剰鏂规硶鍚嶆敼涓� sendSms -->
+      </div>
+    </el-dialog>
+    <el-dialog
+      title="鎮h�呭啀娆¢殢璁�"
+      v-dialogDrags
+      :visible.sync="dialogFormVisible"
+    >
+      <el-form ref="zcform" :rules="zcrules" :model="form" label-width="80px">
+        <el-form-item label="浠诲姟鍚嶇О">
+          <el-input
+            style="width: 400px"
+            disabled
+            v-model="form.taskName"
+          ></el-input>
+        </el-form-item>
+        <el-form-item label="鎮h�呭悕绉�">
+          <el-input
+            style="width: 400px"
+            disabled
+            v-model="form.sendname"
+          ></el-input>
+        </el-form-item>
+        <el-form-item label="骞撮緞">
+          <el-input style="width: 400px" disabled v-model="form.age"></el-input>
+        </el-form-item>
+        <el-form-item label="绉戝">
+          <el-input
+            style="width: 400px"
+            disabled
+            v-model="form.deptname"
+          ></el-input>
+        </el-form-item>
+        <el-form-item label="鐥呭尯">
+          <el-input
+            style="width: 400px"
+            disabled
+            v-model="form.leavehospitaldistrictname"
+          ></el-input>
+        </el-form-item>
+        <el-form-item label="鍑洪櫌鏃堕棿">
+          <el-input
+            style="width: 400px"
+            disabled
+            v-model="form.endtime"
+          ></el-input>
+        </el-form-item>
+        <div class="headline">涓婃闅忚</div>
+        <el-divider></el-divider>
+        <el-row>
+          <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
+                  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="闅忚璁板綍">
+          <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="visitType">
+              <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"
+                value-format="yyyy-MM-dd hh:mm:ss"
+                @change="checkFollowupDate"
+              ></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="闅忚璁板綍" :required="form.resource == '2'">
+          <el-input type="textarea" v-model="form.remark"></el-input>
+        </el-form-item>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="warning" @click="dialogFormVisible = false"
+          >鍙� 娑�</el-button
+        >
+        <el-button type="primary" @click="setupsubtask">纭鍒涘缓鏈嶅姟</el-button>
+      </div>
+    </el-dialog>
+    <div class="main-content" v-if="orgname == '鏅畞鐣叉棌鑷不鍘夸汉姘戝尰闄�'">
+      <!-- <el-button @click="CaldialogVisible = true">鎵撳紑寮规</el-button> -->
+
+      <!-- 寮规璋冪敤 -->
+      <el-dialog
+        title="鍛煎彨鍔熻兘妗�"
+        :visible.sync="CaldialogVisible"
+        width="60%"
+      >
+        <CallCenterLs ref="CallCenterLs" :initial-phone="currentPhoneNumber" />
+      </el-dialog>
+    </div>
+  </div>
+</template>
+
+<script>
+import {
+  getsearchrResults,
+  getPersonVoices,
+  addserviceSubtask,
+  getTaskservelist,
+  getTaskFollowup,
+  Editsingletaskson,
+  serviceSubtaskDetailedit,
+  serviceSubtaskDetailadd,
+  updatePersonVoices,
+  addPersonVoices,
+  query360PatInfo,
+  sendMsg,
+} from "@/api/AiCentre/index";
+import {
+  messagelistpatient,
+  alterpatient,
+  listcontactinformation,
+} from "@/api/patient/homepage";
+import CallButton from "@/components/CallButton";
+import MergeAndModify from "./MergeAndModify.vue";
+import CallCenterLs from "@/components/CallCenterLs";
+export default {
+  components: {
+    CallButton,
+    MergeAndModify,
+    CallCenterLs,
+  },
+  directives: {
+    numericOnly: {
+      bind(el, binding, vnode) {
+        // 灏濊瘯鑾峰彇瀹為檯鐨刬nput鍏冪礌
+        const input = el.tagName === "INPUT" ? el : el.querySelector("input");
+        if (!input) {
+          console.warn("v-numeric-only: 鏈壘鍒癷nput鍏冪礌");
+          return;
+        }
+
+        const handleInput = function (event) {
+          const oldValue = input.value;
+          const newValue = oldValue.replace(/[^\d]/g, "");
+          if (newValue !== oldValue) {
+            input.value = newValue;
+            // 瑙﹀彂input浜嬩欢锛岄�氱煡v-model鏇存柊
+            input.dispatchEvent(new Event("input", { bubbles: true })); // 娉ㄦ剰bubbles
+          }
+        };
+
+        const handlePaste = function (event) {
+          event.preventDefault();
+          const clipboardData = event.clipboardData || window.clipboardData;
+          const pastedData = clipboardData.getData("text");
+          const numericValue = pastedData.replace(/[^\d]/g, "");
+
+          // 妯℃嫙鍦ㄥ厜鏍囦綅缃彃鍏ョ函鏁板瓧鏂囨湰
+          const start = input.selectionStart;
+          const end = input.selectionEnd;
+          input.value =
+            input.value.substring(0, start) +
+            numericValue +
+            input.value.substring(end);
+          // 璋冩暣鍏夋爣浣嶇疆
+          const newCursorPos = start + numericValue.length;
+          input.setSelectionRange(newCursorPos, newCursorPos);
+
+          // 瑙﹀彂input浜嬩欢
+          input.dispatchEvent(new Event("input", { bubbles: true }));
+        };
+
+        input.addEventListener("input", handleInput);
+        input.addEventListener("paste", handlePaste);
+
+        // 瀛樺偍寮曠敤浠ヤ究瑙g粦
+        el._numericOnly = {
+          inputHandle: handleInput,
+          pasteHandle: handlePaste,
+          inputEl: input,
+        };
+      },
+      unbind(el) {
+        if (el._numericOnly) {
+          const { inputHandle, pasteHandle, inputEl } = el._numericOnly;
+          inputEl.removeEventListener("input", inputHandle);
+          inputEl.removeEventListener("paste", pasteHandle);
+          delete el._numericOnly;
+        }
+      },
+    },
+  },
+  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: "", // 鐢ㄤ簬鍖哄垎鏄摢涓數璇�
+      isSipRegistering: true, // SIP娉ㄥ唽鐘舵��
+      // 宸叉湁鏁版嵁...
+      customCallStatus: "", // 鐢ㄤ簬瀛樺偍鑷畾涔夌姸鎬佹枃鏈�
+      callStatus: "idle", // idle, calling, connected, ended, failed
+      isEndingCall: false,
+      CaldialogVisible: false,
+      currentCall: null, // 褰撳墠閫氳瘽瀵硅薄
+      // 鏂板鍔熻兘鏁版嵁
+      showPatientInfo: true,
+      showContinuationCareBtn: false, // 鎺у埗寤剁画鎶ょ悊鎸夐挳鏄剧ず
+      // 璺敱鐩戝惉鐩稿叧
+      routeWatcher: null,
+      lastRoutePath: this.$route.path,
+      input: "浠婂ぉ韬綋杩樹笉閿�",
+      radio: "2",
+      taskname: "",
+      activeName: "wj",
+      voice: "",
+      templateid: "",
+      again: "",
+      orgname: "",
+      zcform: {},
+      form: {},
+      cities: [
+        {
+          label: "姝e父璇煶",
+          value: "1",
+        },
+        {
+          label: "鎮h�呮嫆鎺ユ垨鎷掕",
+          value: "2",
+        },
+        {
+          label: "闈㈣鎴栬�呮帴璇�",
+          value: "3",
+        },
+        {
+          label: "寰俊闅忚",
+          value: "4",
+        },
+        {
+          label: "闅忚鐢佃瘽涓嶆纭�",
+          value: "5",
+        },
+        {
+          label: "涓嶅疁闅忚琚繃婊�",
+          value: "6",
+        },
+        {
+          label: "鍏朵粬",
+          value: "7",
+        },
+      ],
+      tableDatatop: [], //棰樼洰琛�
+      voiceDatatop: [], //棰樼洰琛�
+      dynamicTags: [],
+      isMergeMode: false,
+      mergeDialogVisible: false,
+      selectedServices: [], // 閫変腑鐨勬湇鍔″垪琛�
+      selectedTag: "",
+      tagOptions: [
+        {
+          value: "0",
+          label: "姝e父",
+          type: "normal",
+          color: "#7ff5e1",
+          description: "鎮h�呮儏鍐垫甯革紝鏃犻渶鐗瑰埆鍏虫敞",
+        },
+        {
+          value: "1",
+          label: "寮傚父",
+          type: "abnormal",
+          color: "#f75c5c",
+          description: "鎮h�呭瓨鍦ㄥ紓甯告儏鍐碉紝闇�瑕侀噸鐐瑰叧娉�",
+        },
+        {
+          value: "2",
+          label: "璀﹀憡",
+          type: "warning",
+          color: "#fbfb4a",
+          description: "鎮h�呮儏鍐甸渶瑕佽鍛婃敞鎰忥紝鍙兘瀛樺湪椋庨櫓",
+        },
+      ],
+      zcrules: {
+        resource: [
+          { required: true, message: "璇烽�夋嫨闅忚鏂瑰紡", trigger: "change" },
+        ],
+        date1: [
+          { required: true, message: "璇烽�夋嫨闅忚鏃堕棿", trigger: "blur" },
+          {
+            validator: (rule, value, callback) => {
+              if (!value) {
+                return callback(new Error("璇烽�夋嫨闅忚鏃堕棿"));
+              }
+              const selectedDate = new Date(value);
+              const now = new Date();
+              if (selectedDate < now) {
+                return callback(new Error("闅忚鏃堕棿涓嶈兘鏃╀簬褰撳墠鏃ユ湡"));
+              }
+              callback();
+            },
+            trigger: "change",
+          },
+        ],
+      },
+      userrules: {
+        telcode: [{ validator: validatePhone, trigger: "blur" }],
+        relativetelcode: [{ validator: validatePhone, trigger: "blur" }],
+      },
+      url: "http://9.208.2.190:8090/smartor/serviceExternal/query360PatInfo",
+      postData: {
+        XiaoXiTou: {
+          FaSongFCSJC: "ZJHES",
+          FaSongJGID: localStorage.getItem("orgid"),
+          FaSongJGMC: localStorage.getItem("orgname"),
+          FaSongSJ: "2025-01-09聽17:29:36",
+          FaSongXTJC: "SUIFANGXT",
+          FaSongXTMC: "闅忚绯荤粺",
+          XiaoXiID: "5FA92AFB-9833-4608-87C7-F56A654AC171",
+          XiaoXiLX: "SC_LC_360STCX",
+          XiaoXiMC: "360聽瑙嗗浘鏌ヨ",
+          ZuHuID: localStorage.getItem("ZuHuID"),
+          ZuHuMC: localStorage.getItem("orgname"),
+        },
+        YeWuXX: {
+          BingRenXX: {
+            ZhengJianHM: "",
+            ZhengJianLXDM: "01",
+            ZhengJianLXMC: "灞呮皯韬唤璇�",
+            ZuZhiJGID: localStorage.getItem("orgid"),
+            ZuZhiJGMC: localStorage.getItem("orgname"),
+          },
+          YongHuXX: {
+            XiTongID: "SUIFANGXT",
+            XiTongMC: "闅忚绯荤粺",
+            YongHuID: localStorage.getItem("YongHuID"),
+            YongHuXM: localStorage.getItem("YongHuXM"),
+            ZuZhiJGID: localStorage.getItem("orgid"),
+            ZuZhiJGMC: localStorage.getItem("orgname"),
+            idp: "lyra",
+          },
+        },
+      },
+      pickerOptions: {
+        disabledDate(time) {
+          // 绂佺敤浠婂ぉ鍙婁箣鍓嶇殑鏃ユ湡
+          return time.getTime() < Date.now() - 24 * 60 * 60 * 1000;
+        },
+        // shortcuts: [
+        //   {
+        //     text: "涓冨ぉ鍚�",
+        //     onClick(picker) {
+        //       const date = new Date();
+        //       date.setTime(date.getTime() + 3600 * 1000 * 24 * 7);
+        //       picker.$emit("pick", date);
+        //     },
+        //   },
+        //   {
+        //     text: "15澶╁悗",
+        //     onClick(picker) {
+        //       const date = new Date();
+        //       date.setTime(date.getTime() + 3600 * 1000 * 24 * 15);
+        //       picker.$emit("pick", date);
+        //     },
+        //   },
+        //   {
+        //     text: "涓�涓湀鍚�",
+        //     onClick(picker) {
+        //       const date = new Date();
+        //       date.setTime(date.getTime() + 3600 * 1000 * 24 * 30);
+        //       picker.$emit("pick", date);
+        //     },
+        //   },
+        //   {
+        //     text: "涓変釜鏈堝悗",
+        //     onClick(picker) {
+        //       const date = new Date();
+        //       date.setTime(date.getTime() + 3600 * 1000 * 24 * 90);
+        //       picker.$emit("pick", date);
+        //     },
+        //   },
+        //   {
+        //     text: "鍏釜鏈堝悗",
+        //     onClick(picker) {
+        //       const date = new Date();
+        //       date.setTime(date.getTime() + 3600 * 1000 * 24 * 180);
+        //       picker.$emit("pick", date);
+        //     },
+        //   },
+        //   {
+        //     text: "涓�骞村悗",
+        //     onClick(picker) {
+        //       const date = new Date();
+        //       date.setTime(date.getTime() + 3600 * 1000 * 24 * 365);
+        //       picker.$emit("pick", date);
+        //     },
+        //   },
+        // ],
+      },
+      options: [
+        {
+          value: "涓冨ぉ鍚�",
+          label: "涓冨ぉ鍚�",
+        },
+        {
+          value: "15澶╁悗",
+          label: "15澶╁悗",
+        },
+        {
+          value: "涓�涓湀鍚�",
+          label: "涓�涓湀鍚�",
+        },
+        {
+          value: "涓変釜鏈堝悗",
+          label: "涓変釜鏈堝悗",
+        },
+        {
+          value: "鍏釜鏈堝悗",
+          label: "鍏釜鏈堝悗",
+        },
+        {
+          value: "涓�骞村悗",
+          label: "涓�骞村悗",
+        },
+      ],
+      statusTimer: null,
+      userform: {},
+      smsDialogVisible: false, // 鎺у埗鐭俊瀵硅瘽妗嗘樉绀�
+      smsContent: "", // 瀛樺偍鐭俊鍐呭
+      Whetherall: true, //鏄惁鍏ㄩ儴璁板綍灞曠ず
+      dialogFormVisible: false,
+      Voicetype: 0, //鏄惁涓鸿闊虫湇鍔�
+      visitCount: null,
+      logsheetlist: [],
+      topicobj: {},
+      sendname: null,
+      serviceType: null,
+      id: null,
+      taskid: null,
+      patid: null,
+    };
+  },
+  // 鍦ㄧ粍浠朵腑娣诲姞閿�姣佸墠鐨勬竻鐞�
+  beforeUnmount() {
+    if (this.statusTimer) {
+      clearTimeout(this.statusTimer);
+      this.statusTimer = null;
+    }
+  },
+  computed: {
+    callStatusText() {
+      if (this.customCallStatus) {
+        return this.customCallStatus;
+      }
+      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;
+    this.sendname = this.$route.query.sendname;
+    this.patid = this.$route.query.patid;
+    this.again = this.$route.query.again;
+    this.Voicetype = this.$route.query.Voicetype;
+    this.visitCount = this.$route.query.visitCount;
+    this.serviceType = this.$route.query.serviceType;
+    this.orgname = localStorage.getItem("orgname");
+    if (this.orgname == "鐪佺珛鍚屽痉缈犺嫅闄㈠尯") {
+      this.showContinuationCareBtn = true;
+    }
+
+    if (this.orgname == "缂欎簯鍘夸腑鍖诲尰闄�") {
+      this.options = [
+        {
+          value: "鍗婁釜鏈堝悗",
+          label: "鍗婁釜鏈堝悗",
+        },
+        {
+          value: "涓�涓湀鍚�",
+          label: "涓�涓湀鍚�",
+        },
+        {
+          value: "涓や釜鏈堝悗",
+          label: "涓や釜鏈堝悗",
+        },
+        {
+          value: "涓変釜鏈堝悗",
+          label: "涓変釜鏈堝悗",
+        },
+        {
+          value: "鍏釜鏈堝悗",
+          label: "鍏釜鏈堝悗",
+        },
+        {
+          value: "12涓湀鍚�",
+          label: "12涓湀鍚�",
+        },
+      ];
+    }
+    this.getTaskservelist();
+  },
+  mounted() {
+    // 鐩戝惉瀛愮粍浠剁殑sipStatus灞炴�у彉鍖�
+    if (this.$refs.callButton) {
+      this.$watch(
+        () => this.$refs.callButton.sipStatus,
+        (newStatus) => {
+          if (this.statusTimer) {
+            clearTimeout(this.statusTimer);
+            this.statusTimer = null;
+          }
+          if (newStatus === "宸叉敞鍐�") {
+            this.statusTimer = setTimeout(() => {
+              this.isSipRegistering = false;
+              this.customCallStatus = ""; // 娉ㄥ唽鎴愬姛鍚庢竻绌鸿嚜瀹氫箟鎻愮ず
+              console.log("SIP娉ㄥ唽鎴愬姛锛岀姸鎬佸凡鏇存柊");
+            }, 2000);
+            this.isSipRegistering = false;
+          } else if (newStatus === "娉ㄥ唽澶辫触" || newStatus === "鏈繛鎺�") {
+            this.isSipRegistering = true;
+            this.customCallStatus = "鍛煎彨涓柇锛岃祫婧愰噸鏂板姞杞戒腑璇风◢绛�3s閲嶆柊銆�";
+          }
+        },
+        { immediate: true } // 绔嬪嵆鎵ц涓�娆′互鑾峰彇鍒濆鍊�
+      );
+    }
+  },
+  methods: {
+    // 鑾峰彇涓婚鏍峰紡绫�
+    getTopicClass(item) {
+      console.log(item.isabnormal, "getTopicClass");
+
+      // 鏍规嵁鐘舵�佸�艰繑鍥炲搴旂殑鏍峰紡绫�
+      if (item.isabnormal == 1) {
+        return "scriptTopic-isabnormal"; // 寮傚父 - 绾㈣壊
+      } else if (item.isabnormal == 2) {
+        return "scriptTopic-warning"; // 璀﹀憡 - 榛勮壊
+      } else {
+        return "scriptTopic-dev"; // 姝e父 - 榛樿鏍峰紡
+      }
+    },
+
+    // 鑾峰彇閫夐」鏍峰紡绫�
+    getOptionClass(items) {
+      if (items.isabnormal == 1) {
+        return "red-star"; // 寮傚父 - 绾㈣壊鏄熷彿
+      } else if (items.isabnormal == 2) {
+        return "yellow-star"; // 璀﹀憡 - 榛勮壊鏄熷彿
+      }
+      return ""; // 姝e父 - 鏃犵壒娈婃牱寮�
+    },
+    // 鑾峰彇闂嵎鏁版嵁
+    getsearchrResults(id) {
+      getsearchrResults({
+        taskid: this.taskid,
+        patid: this.patid,
+        subId: id ? id : this.id,
+        isFinish: false,
+      }).then((res) => {
+        if (res.code === 200) {
+          // 閽堝鍐嶆闅忚鏈嶅姟杩涜鍒犻櫎缁撴灉璧嬪��
+          // if (this.again && res.data.upScriptResult) {
+          //   res.data.upScriptResult.forEach((itemA) => {
+          //     const itemB = res.data.scriptResult.find(
+          //       (item) => item.scriptContent === itemA.scriptContent
+          //     );
+          //     if (itemB) {
+          //       itemB.scriptResult = itemA.scriptResult;
+          //     }
+          //   });
+          // }
+          this.tableDatatop = res.data.scriptResult;
+
+          this.tableDatatop.forEach((item) => {
+            if (item.scriptType == 2) item.scriptResult = [];
+            if (item.scriptResultId && item.scriptType != 2) {
+              item.isoption = 3;
+              item.scriptResult = item.scriptResult;
+            } else if (item.scriptResultId && item.scriptType == 2) {
+              item.scriptResult = item.scriptResult.split("&");
+              item.isoption = 3;
+            }
+          });
+          this.taskname = res.data.taskName;
+          this.overdata();
+        }
+      });
+    },
+    //鎮h��360璺宠浆
+    gettoken360(sfzh, drcode, drname) {
+      // this.$modal.msgWarning("360鍔熻兘鏆傛湭寮�閫�");
+
+      this.postData.YeWuXX.BingRenXX.ZhengJianHM = sfzh;
+
+      query360PatInfo(this.postData).then((res) => {
+        if (res.data.url) {
+          window.open(res.data.url, "_blank");
+          // this.linkUrl = res.data.url;
+        } else {
+          this.$modal.msgWarning("360鏌ヨ鏃犵粨鏋�");
+        }
+      });
+    },
+    // 鑾峰彇鍩虹淇℃伅
+    getuserinfo() {
+      const queryParams = {
+        pid: Number(this.patid),
+        allhosp: "0", //1浣忛櫌2闂ㄨ瘖3浣撴4鍑洪櫌
+      };
+      // 鎮h�呭熀纭�淇℃伅
+      messagelistpatient(queryParams).then((response) => {
+        if (response.rows[0]) {
+          this.userform = response.rows[0];
+          // this.dynamicTags = response.rows[0].tagList.map(this.processElement);
+        }
+      });
+      listcontactinformation({ patid: this.patid }).then((response) => {
+        this.tableData = response.rows;
+        if (this.tableData.length) {
+          this.userform.relativetelcode = this.tableData[0].contactway;
+          this.userform.relation = this.tableData[0].relation;
+        }
+      });
+    },
+    // 鍐嶆闅忚鏃堕棿閫夊彇
+    visitChange(value) {
+      if (!this.form.endtime) {
+        this.$message.warning("璇峰厛纭鍑洪櫌鏃堕棿");
+        this.form.visitType = "";
+        this.$refs.zcform.clearValidate(["visitType"]);
+        return;
+      }
+
+      const dischargeDate = new Date(this.form.endtime);
+      const now = new Date();
+      let followupDate = new Date(dischargeDate);
+
+      // 鏍规嵁閫夋嫨鐨勯殢璁挎柟寮忚绠楅殢璁挎棩鏈�
+      if (value.includes("涓冨ぉ鍚�")) {
+        followupDate.setDate(dischargeDate.getDate() + 7);
+      } else if (value.includes("15澶╁悗") || value.includes("鍗婁釜鏈堝悗")) {
+        followupDate.setDate(dischargeDate.getDate() + 15);
+      } else if (value.includes("涓�涓湀鍚�")) {
+        followupDate.setMonth(dischargeDate.getMonth() + 1);
+      } else if (value.includes("涓や釜鏈堝悗")) {
+        followupDate.setMonth(dischargeDate.getMonth() + 2);
+      } else if (value.includes("涓変釜鏈堝悗")) {
+        followupDate.setMonth(dischargeDate.getMonth() + 3);
+      } else if (value.includes("鍏釜鏈堝悗")) {
+        followupDate.setMonth(dischargeDate.getMonth() + 6);
+      } else if (value.includes("涓�骞村悗") || value.includes("12涓湀鍚�")) {
+        followupDate.setFullYear(dischargeDate.getFullYear() + 1);
+      }
+
+      if (followupDate < now) {
+        this.$message.warning(
+          `璁$畻鍑虹殑闅忚鏃堕棿 ${this.formatTime(followupDate)} 宸茶繃鏈焋
+        );
+        this.form.visitType = "";
+        this.$refs.zcform.clearValidate(["visitType", "date1"]);
+        return;
+      }
+
+      this.form.date1 = this.formatTime(followupDate);
+
+      this.$refs.zcform.clearValidate(["date1"]);
+    },
+    // 妫�鏌ラ殢璁挎棩鏈熸槸鍚︽湁鏁�
+    checkFollowupDate(date) {
+      if (!date) {
+        this.form.date1 = "";
+        this.$refs.zcform.clearValidate(["date1"]);
+        return;
+      }
+
+      const selectedDate = new Date(date);
+      const now = new Date();
+
+      if (selectedDate < now) {
+        this.$message.warning("闅忚鏃堕棿涓嶈兘鏃╀簬褰撳墠鏃ユ湡");
+        this.form.date1 = "";
+        this.$refs.zcform.validateField("date1"); // 瑙﹀彂楠岃瘉
+      }
+    },
+    // 鑾峰彇璇煶鏁版嵁
+    getPersonVoices(id) {
+      let obj = {
+        taskid: this.taskid,
+        patid: this.patid,
+        subId: id ? id : this.id,
+      };
+
+      getPersonVoices(obj).then((res) => {
+        if (res.code == 200) {
+          this.voiceDatatop = res.data.serviceSubtaskDetails;
+          this.voice = res.data.voice;
+          this.activeName = "yy";
+          this.taskname = res.data.taskName;
+          // 闂嵎灞曠ず鏁版嵁澶勭悊
+          this.tableDatatop = res.data.filteredDetails;
+          this.tableDatatop.forEach((item) => {
+            if (item.targetvalue) {
+              item.scriptResult = item.targetvalue.split("&");
+            } else {
+              item.scriptResult = [];
+            }
+          });
+
+          if (!this.tableDatatop.length) {
+            this.puttaskid(this.templateid);
+          }
+        }
+      });
+    },
+    // 鑾峰彇闂嵎瀹屾暣鏁版嵁姣斿
+    puttaskid(id) {
+      getTaskFollowup(id).then((res) => {
+        if (res.code == 200) {
+          this.tableDatatop = res.data.ivrTaskTemplateScriptVOList;
+          this.tableDatatop.forEach((item) => {
+            item.id = null;
+            // 绫诲瀷鍒ゆ柇璧嬪��
+            if (item.ivrTaskScriptTargetoptionList) {
+              item.targetvalue = 1;
+              item.questiontext = item.scriptContent;
+              item.targetvalue = item.ivrTaskScriptTargetoptionList
+                .map((obj) => obj.targetvalue)
+                .join("&");
+            }
+            if (item.targetvalue) {
+              item.scriptResult = item.targetvalue.split("&");
+            } else {
+              item.scriptResult = [];
+            }
+          });
+        }
+      });
+    },
+    // 鍖绘姢浜哄憳瀛樺偍鏁版嵁
+    getdetail() {
+      let excep = "";
+      const promises = [];
+      this.tableDatatop.forEach((item) => {
+        if (item.valueType == 3 && item.scriptResult) {
+          // 楠岃瘉鏄惁涓烘湁鏁堟暟瀛�
+          if (!/^\d+$/.test(item.scriptResult)) {
+            this.$message.error(`闂 "${item.scriptContent}" 蹇呴』杈撳叆鏁板瓧`);
+            return;
+          }
+        }
+        var objs = item.svyTaskTemplateTargetoptions.find(
+          (items) => items.optioncontent == item.scriptResult
+        );
+
+        if (objs) {
+          if (excep != 1 && objs.isabnormal) {
+            excep = objs.isabnormal;
+            this.selectedTag = objs.isabnormal;
+          }
+        }
+        console.log(excep, "excep");
+
+        let obj = {
+          asrtext: null,
+          patid: this.patid,
+          subId: this.id,
+          taskid: this.taskid,
+          scriptid: item.id,
+          excep: excep,
+          questiontext: item.scriptContent,
+          categoryid: item.categoryid,
+          answerps: item.answerps || null, // 娣诲姞闄勫姞淇℃伅
+        };
+        if (item.scriptType == 2 && item.scriptResult[0]) {
+          obj.asrtext = item.scriptResult.join("&");
+        } else if (item.scriptType != 2 && item.scriptResult) {
+          obj.asrtext = item.scriptResult;
+        }
+
+        if (item.isoption == 3) {
+          promises.push(serviceSubtaskDetailedit(obj));
+        } else {
+          promises.push(serviceSubtaskDetailadd(obj));
+        }
+      });
+
+      // 浣跨敤 Promise.all 绛夊緟鎵�鏈夊紓姝ユ搷浣滃畬鎴�
+      Promise.all(promises)
+        .then((results) => {
+          // 鎵�鏈夊紓姝ユ搷浣滄垚鍔熷畬鎴愬悗鐨勯�昏緫
+          results.forEach((res) => {
+            if (res.code !== 200) {
+              this.$modal.error("淇敼澶辫触");
+            }
+          });
+          this.Editsingletasksonyic(6);
+          const orgName = localStorage.getItem("orgname");
+          console.log(orgName, "orgName");
+
+          if (this.form.isVisitAgain != 1 || orgName == "涓芥按甯備腑鍖婚櫌") {
+            this.Torouter();
+            return;
+          }
+          this.$modal
+            .confirm(
+              '浠诲姟淇濆瓨鎴愬姛鏄惁閽堝鎮h�咃細"' +
+                this.userform.name +
+                '"鍐嶆闅忚锛�',
+              "纭",
+              {
+                confirmButtonText: "纭畾",
+                cancelButtonText: "鍙栨秷",
+                showCancelButton: true,
+                dangerouslyUseHTMLString: true,
+                confirmButtonClass: "custom-confirm-button", // 鑷畾涔夌‘璁ゆ寜閽殑绫诲悕
+                cancelButtonClass: "custom-cancel-button", // 鑷畾涔夊彇娑堟寜閽殑绫诲悕
+              }
+            )
+            .then(() => {
+              document.querySelector("#app").scrollTo(0, 0);
+              this.formtidy();
+              this.dialogFormVisible = true;
+            })
+            .catch(() => {
+              this.Torouter();
+            });
+        })
+        .catch((error) => {
+          // 濡傛灉鏈変换浣曚竴涓紓姝ユ搷浣滃け璐ワ紝浼氳繘鍏ヨ繖閲�
+          console.error("鍙戠敓閿欒锛�", error);
+        });
+    },
+    Torouter() {
+      if (this.form.serviceType == 13) {
+        if (this.visitCount != 1) {
+          this.$router.push({
+            path: "/logisticsservice/zbAgain",
+          });
+        } else {
+          this.$router.push({
+            path: "/logisticsservice/record",
+          });
+        }
+      } else if (this.form.serviceType == 2) {
+        if (this.visitCount != 1) {
+          this.$router.push({
+            path: "/logisticsservice/again",
+          });
+        } else {
+          this.$router.push({
+            path: "/followvisit/discharge",
+          });
+        }
+      }
+    },
+    // 鐢佃瘽============================
+    // 楠岃瘉鐢佃瘽鍙风爜鏍煎紡骞惰繑鍥為敊璇俊鎭�
+    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, dh) {
+      if (!this.isValidPhone(phone) && !dh) {
+        this.$message.error("璇疯緭鍏ユ纭殑鎵嬫満鍙风爜");
+        return;
+      }
+      // 妫�鏌IP鏄惁宸叉敞鍐�
+
+      this.currentPhoneNumber = phone;
+      // 鏄惁鏅畞鍛煎彨
+      if (this.orgname == "鏅畞鐣叉棌鑷不鍘夸汉姘戝尰闄�") {
+        this.CaldialogVisible = true;
+        return;
+      }
+      // 涓嬫柟鏄腑鍖婚櫌鍛煎彨
+      if (this.isSipRegistering) {
+        this.$message.warning("绯荤粺姝e湪鍒濆鍖栵紝璇风◢鍊�...");
+        return;
+      }
+      this.callType = type;
+      this.callStatus = "calling";
+
+      this.$nextTick(() => {
+        this.$refs.callButton.startCall();
+
+        this.$refs.callButton.$on("call-status-change", (status) => {
+          this.handleCallStatusChange(status);
+          // 鐩戝惉娉ㄥ唽鐘舵�佸彉鍖�
+          if (status.type === "registered") {
+            this.isSipRegistering = false;
+          }
+          if (status.type === "failed" || status.type === "disconnected") {
+            this.isSipRegistering = true;
+          }
+        });
+      });
+    },
+    // 澶勭悊閫氳瘽鐘舵�佸彉鍖�
+    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() {
+      const dataToSubmit = JSON.parse(JSON.stringify(this.tableDatatop));
+      console.log(dataToSubmit, "dataToSubmit");
+      // return;
+      dataToSubmit.forEach((item, index) => {
+        // 瀵规嫹璐濈殑鏁版嵁杩涜鎿嶄綔锛屼笉褰卞搷鍘熷鐨� scriptResult 鏁扮粍
+        item.scriptResult = item.scriptResult.join("&");
+        item.templatequestionnum = index + 1;
+        item.subId = this.id;
+        item.taskid = this.taskid;
+        item.asrtext = item.matchedtext;
+        if (!item.id) {
+          item.isoperation = 1;
+        }
+        item.patid = this.patid;
+        item.templateid = item.templateID;
+      });
+
+      let obj = {
+        serviceSubtaskDetailList: dataToSubmit, // 鎻愪氦澶勭悊鍚庣殑鍓湰
+        param1: this.taskid,
+        param2: this.patid,
+        subId: this.id,
+      };
+      const orgName = localStorage.getItem("orgname");
+      console.log(orgName, "orgName");
+
+      if (this.form.isVisitAgain != 1 || orgName == "涓芥按甯備腑鍖婚櫌") {
+        this.Torouter();
+        return;
+      }
+      addPersonVoices(obj).then((res) => {
+        if (res.code == 200) {
+          this.$modal.msgSuccess("鏈嶅姟淇濆瓨鎴愬姛");
+          this.$modal
+            .confirm(
+              '浠诲姟淇濆瓨鎴愬姛鏄惁閽堝鎮h�咃細"' +
+                this.userform.name +
+                '"鍐嶆闅忚锛�',
+              "纭",
+              {
+                confirmButtonText: "纭畾",
+                cancelButtonText: "鍙栨秷",
+                showCancelButton: true,
+                dangerouslyUseHTMLString: true,
+                confirmButtonClass: "custom-confirm-button", // 鑷畾涔夌‘璁ゆ寜閽殑绫诲悕
+                cancelButtonClass: "custom-cancel-button", // 鑷畾涔夊彇娑堟寜閽殑绫诲悕
+              }
+            )
+            .then(() => {
+              document.querySelector("#app").scrollTo(0, 0);
+              this.formtidy();
+              this.dialogFormVisible = true;
+            })
+            .catch(() => {
+              this.Torouter();
+            });
+        }
+      });
+    },
+    // 鍐嶆闅忚鏁版嵁鏇存浛
+    formtidy() {
+      this.form.visitType2 = this.form.visitType;
+      this.form.date2 = this.form.visitTime;
+      // this.form.date1 = this.setCurrentDate();
+      this.form.remark2 = this.form.remark;
+    },
+    setCurrentDate() {
+      // 鑾峰彇褰撳墠鏃ユ湡骞舵牸寮忓寲涓� yyyy-MM-dd
+      const today = new Date();
+      const year = today.getFullYear();
+      const month = String(today.getMonth() + 1).padStart(2, "0");
+      const day = String(today.getDate()).padStart(2, "0");
+      return `${year}-${month}-${day}`;
+    },
+    // 鑾峰彇鎮h�呰褰�
+    getTaskservelist(id) {
+      if (id) {
+        this.Whetherall = false;
+      } else {
+        this.Whetherall = true;
+      }
+
+      getTaskservelist({
+        patid: this.patid,
+        subId: id,
+        pageSize: 100,
+      }).then((res) => {
+        if (res.code == 200) {
+          this.form = res.rows[0].serviceSubtaskList.find(
+            (item) => item.id == this.id
+          );
+          console.log(this.form, "serviceType");
+
+          this.logsheetlist = res.rows[0].serviceSubtaskList;
+          this.templateid = this.form.templateid;
+          this.selectedTag = this.form.excep;
+          const targetDate = new Date(this.form.visitTime); // 鐩爣鏃ユ湡
+          const now = new Date(); // 褰撳墠鏃堕棿
+          if (now < targetDate && this.form.sendstate == 2) {
+            this.$confirm("褰撳墠鏈嶅姟鏈埌鍙戦�佹椂闂磋璋ㄦ厧淇敼", "鎻愮ず", {
+              confirmButtonText: "纭畾",
+              cancelButtonText: "鍙栨秷",
+              type: "warning",
+            })
+              .then(() => {})
+              .catch(() => {});
+          }
+          this.getuserinfo();
+        }
+        if (this.Voicetype) {
+          this.getPersonVoices();
+        } else {
+          this.getsearchrResults();
+        }
+      });
+    },
+    // 璋冭捣鐭俊鍙戦�佸璇濇
+    sendAgainmsg() {
+      this.smsDialogVisible = true;
+      // 鍙互鍦ㄨ繖閲屽垵濮嬪寲 smsContent锛屼緥濡� this.smsContent = '';
+    },
+
+    // 鍙戦�佺煭淇$殑鏂规硶
+    sendSms() {
+      // 杩欓噷璋冪敤浣犵殑鐭俊鍙戦�� API
+      // 鍋囪 API 涓� sendMsg锛屽弬鏁板彲鑳介渶瑕佹牴鎹疄闄呮儏鍐佃皟鏁�
+      sendMsg({
+        phone: this.userform.telcode, // 纭繚鐢佃瘽鍙风爜瀛楁姝g‘
+        content: this.smsContent,
+      })
+        .then((res) => {
+          if (res.code == 200) {
+            this.$modal.msgSuccess("鍙戦�佹垚鍔�");
+            this.smsDialogVisible = false; // 鍏抽棴瀵硅瘽妗�
+            this.smsContent = ""; // 娓呯┖鍐呭
+          } else {
+            this.$modal.msgError("鍙戦�佸け璐�");
+          }
+        })
+        .catch((error) => {
+          console.error("鍙戦�佺煭淇″け璐�:", error);
+          this.$modal.msgError("鍙戦�佸け璐�");
+        });
+    },
+    Editsingletaskson(son) {
+      let objson = {};
+      getTaskservelist({
+        patid: this.patid,
+        subId: this.id,
+      }).then((res) => {
+        if (res.code == 200) {
+          objson = res.rows[0].serviceSubtaskList[0];
+          objson.suggest = son;
+          Editsingletaskson(objson).then((res) => {
+            if (res.code) {
+              this.$modal.msgSuccess("鏈嶅姟璁板綍鎴愬姛");
+              this.getTaskservelist();
+            }
+          });
+        }
+      });
+    },
+    Editsingletasksonyic(sendstate) {
+      let objson = {};
+      getTaskservelist({
+        patid: this.patid,
+        subId: this.id,
+      }).then((res) => {
+        if (res.code == 200) {
+          objson = res.rows[0].serviceSubtaskList.find(
+            (item) => item.id == this.id
+          );
+          objson.remark = this.form.remark;
+          objson.taskSituation = this.form.taskSituation;
+          objson.excep = this.selectedTag;
+          if (sendstate) objson.sendstate = sendstate;
+          Editsingletaskson(objson).then((res) => {
+            if (res.code) {
+              this.$modal.msgSuccess("鏈嶅姟淇敼鎴愬姛");
+              alterpatient(this.userform).then((res) => {
+                if (res.code == 200) {
+                  this.$modal.msgSuccess("鍩虹淇℃伅淇濆瓨鎴愬姛");
+                } else {
+                  this.$modal.msgError("鍩虹淇℃伅淇敼澶辫触");
+                }
+              });
+              this.getTaskservelist();
+            }
+          });
+        }
+      });
+    },
+    // 寮傚父鍒楁覆鏌�
+    tableRowClassName({ row, rowIndex }) {
+      if (row.id == this.id) {
+        return "warning-row";
+      }
+      return "";
+    },
+    getSelectedTagType() {
+      if (!this.selectedTag) return "";
+      const tag = this.tagOptions.find(
+        (item) => item.value === this.selectedTag
+      );
+      return tag ? tag.type : "";
+    },
+
+    getSelectedTagColor() {
+      if (!this.selectedTag) return "";
+      const tag = this.tagOptions.find(
+        (item) => item.value === this.selectedTag
+      );
+      return tag ? tag.color : "";
+    },
+
+    getSelectedDescription() {
+      if (!this.selectedTag) return "";
+      const tag = this.tagOptions.find(
+        (item) => item.value === this.selectedTag
+      );
+      return tag ? tag.description : "";
+    },
+
+    // 璋冭捣鍐嶆鍙戦��
+    sendAgain() {
+      getTaskservelist({
+        patid: this.patid,
+        visitCount: 2,
+        leaveldeptcodes: [this.form.deptcode],
+      }).then((res) => {
+        if (res.rows[0].serviceSubtaskList.length) {
+          if (
+            res.rows[0].serviceSubtaskList[0].sendstate != 5 &&
+            res.rows[0].serviceSubtaskList[0].sendstate != 6
+          ) {
+            this.$modal
+              .confirm(
+                '鏈偅鑰呭湪"' +
+                  res.rows[0].serviceSubtaskList[0].deptname +
+                  '"绉戝涓嬪凡鏈夊啀娆¢殢璁挎湇鍔¤繘琛屼腑鏄惁缁х画鍒涘缓锛�'
+              )
+              .then(() => {
+                document.querySelector("#app").scrollTo(0, 0);
+                this.formtidy();
+                this.dialogFormVisible = true;
+              });
+          } else {
+            document.querySelector("#app").scrollTo(0, 0);
+            this.formtidy();
+            this.dialogFormVisible = true;
+          }
+        } else {
+          document.querySelector("#app").scrollTo(0, 0);
+          this.formtidy();
+          this.dialogFormVisible = true;
+        }
+      });
+    },
+    // 鏌ョ湅璇︽儏
+    Seedetails(row) {
+      this.$modal
+        .confirm('鏄惁鏌ョ湅浠诲姟涓�"' + row.taskName + '"鐨勬湇鍔¤鎯呮暟鎹紵')
+        .then(() => {
+          let type = "";
+          console.log(row, "rwo");
+          if (row.type == 1) {
+            type = 1;
+          }
+          this.taskid = row.taskid;
+          this.id = row.id;
+          this.patid = row.patid;
+          this.serviceType = row.serviceType;
+          this.getTaskservelist();
+        })
+        .catch(() => {});
+    },
+    aahandleOptionChange(a, b, c) {
+      const result = c.find((item) => item.optioncontent == a);
+      if (result.nextQuestion == 0) {
+        this.tableDatatop = this.tableDatatop.reduce((acc, item, i) => {
+          acc.push(i > b ? { ...item, astrict: 1 } : item);
+          return acc;
+        }, []);
+      } else {
+        this.tableDatatop = this.tableDatatop.reduce((acc, item, i) => {
+          acc.push(i > b ? { ...item, astrict: 0 } : item);
+          return acc;
+        }, []);
+      }
+      if (this.Voicetype) {
+        var obj = this.tableDatatop[b].ivrTaskScriptTargetoptionList.find(
+          (item) => item.optioncontent == a
+        );
+      } else {
+        var obj = this.tableDatatop[b].svyTaskTemplateTargetoptions.find(
+          (item) => item.optioncontent == a
+        );
+      }
+      if (obj.isabnormal) {
+        this.tableDatatop[b].isabnormal = true;
+      } else {
+        this.tableDatatop[b].isabnormal = false;
+      }
+      this.$forceUpdate();
+    },
+    handleRadioToggles(questionItem, optionValue) {
+      if (!questionItem.matchedtext) {
+        questionItem.matchedtext == "";
+      }
+      // 濡傛灉鐐瑰嚮鐨勬槸褰撳墠宸查�変腑鐨勯�夐」锛屽垯鍙栨秷閫変腑
+      if (questionItem.matchedtext == optionValue) {
+        this.$set(questionItem, "matchedtext", "");
+        // 鍚屾椂閲嶇疆涓庨�夐」鐩稿叧鐨勭姸鎬�
+        // questionItem.isabnormal = false;
+        questionItem.showAppendInput = false;
+        // 娉ㄦ剰锛氬彇娑堥�変腑鏃讹紝鎴戜滑閫氬父涓嶅笇鏈涜Е鍙戦鐩烦杞�昏緫锛屾墍浠ョ洿鎺ヨ繑鍥�
+        // 濡傛灉闇�瑕侊紝鍙互鍦ㄨ繖閲屾坊鍔犲彇娑堥�変腑鍚庣殑鐗瑰畾閫昏緫锛屼緥濡傞噸缃鐩簭鍒�
+      } else {
+        // 濡傛灉鐐瑰嚮鐨勬槸鏈�変腑鐨勯�夐」锛屽垯閫氳繃鏇存敼缁戝畾鍊兼潵瑙﹀彂鍘熷鐨� handleOptionChange 鏂规硶
+        // 杩欓噷鍙渶瑕佹敼鍙� v-model 缁戝畾鐨勫�硷紝change浜嬩欢浼氳嚜鍔ㄨЕ鍙�
+        this.$set(questionItem, "matchedtext", optionValue); // 鍚庣画鐨勮烦杞瓑澶嶆潅閫昏緫浼氬湪 handleOptionChange 涓甯告墽琛�
+      }
+    },
+    // 鏂板鐨勫垏鎹㈤�変腑/鍙栨秷閫変腑鏂规硶
+    handleRadioToggle(questionItem, index, options, optionValue) {
+      // 濡傛灉鐐瑰嚮鐨勬槸褰撳墠宸查�変腑鐨勯�夐」锛屽垯鍙栨秷閫変腑
+      if (questionItem.scriptResult === optionValue) {
+        questionItem.scriptResult = ""; // 娓呯┖閫変腑鍊�
+        // 鍚屾椂閲嶇疆涓庨�夐」鐩稿叧鐨勭姸鎬�
+        // questionItem.isabnormal = false;
+        questionItem.showAppendInput = false;
+        // 娉ㄦ剰锛氬彇娑堥�変腑鏃讹紝鎴戜滑閫氬父涓嶅笇鏈涜Е鍙戦鐩烦杞�昏緫锛屾墍浠ョ洿鎺ヨ繑鍥�
+        // 濡傛灉闇�瑕侊紝鍙互鍦ㄨ繖閲屾坊鍔犲彇娑堥�変腑鍚庣殑鐗瑰畾閫昏緫锛屼緥濡傞噸缃鐩簭鍒�
+      } else {
+        // 濡傛灉鐐瑰嚮鐨勬槸鏈�変腑鐨勯�夐」锛屽垯閫氳繃鏇存敼缁戝畾鍊兼潵瑙﹀彂鍘熷鐨� handleOptionChange 鏂规硶
+        // 杩欓噷鍙渶瑕佹敼鍙� v-model 缁戝畾鐨勫�硷紝change浜嬩欢浼氳嚜鍔ㄨЕ鍙�
+        questionItem.scriptResult = optionValue;
+        this.handleOptionChange(optionValue, index, options, questionItem);
+        // 鍚庣画鐨勮烦杞瓑澶嶆潅閫昏緫浼氬湪 handleOptionChange 涓甯告墽琛�
+      }
+    },
+
+    // 鍦╩ethods閮ㄥ垎锛屼慨鏀筯andleOptionChange鏂规硶:
+    handleOptionChange(selectedOption, questionIndex, options, a) {
+      console.log(selectedOption, questionIndex, options, a, "888");
+
+      if (document.activeElement) {
+        document.activeElement.blur();
+      }
+
+      // 鎵惧埌琚�変腑鐨勯�夐」瀵硅薄
+      const selectedOptionObj = options.find(
+        (item) => item.optioncontent == selectedOption
+      );
+
+      // 澶勭悊寮傚父鐘舵�侀珮浜�
+      this.tableDatatop[questionIndex].isabnormal =
+        selectedOptionObj.isabnormal;
+      // 澶勭悊闄勫姞杈撳叆妗嗘樉绀�
+
+      this.tableDatatop[questionIndex].showAppendInput =
+        selectedOptionObj.appendflag == 1;
+      console.log(this.tableDatatop);
+
+      // if (!this.tableDatatop[questionIndex].showAppendInput) {
+      //   this.tableDatatop[questionIndex].answerps = ""; // 娓呴櫎闄勫姞淇℃伅
+      // }
+      // 淇濆瓨褰撳墠棰樼洰涔嬪墠宸茬粡闅愯棌鐨勯鐩姸鎬�
+      const previouslyHiddenBeforeCurrent = this.tableDatatop
+        .slice(0, questionIndex)
+        .map((item, index) => (item.astrict ? index : -1))
+        .filter((index) => index !== -1);
+
+      // 淇濆瓨涔嬪墠鍥爊extQuestion=0鑰岄殣钘忕殑棰樼洰鑼冨洿
+      const previouslyHiddenByEnd = this.tableDatatop
+        .map((item, index) => (item.hiddenByEnd ? index : -1))
+        .filter((index) => index !== -1);
+
+      // 濡傛灉branchFlag涓�1锛屽鐞嗛鐩烦杞�
+      if (a.branchFlag == 1) {
+        if (selectedOptionObj.nextQuestion == 0) {
+          // 缁撴潫闂瓟 - 闅愯棌鍚庨潰鎵�鏈夐鐩苟鏍囪
+          this.tableDatatop = this.tableDatatop.map((item, index) => ({
+            ...item,
+            astrict: index > questionIndex,
+            hiddenByEnd: index > questionIndex, // 鏍囪杩欎簺棰樼洰鏄缁撴潫闂瓟闅愯棌鐨�
+          }));
+        } else {
+          // 姝e父璺宠浆閫昏緫
+          const nextQuestionIndex = selectedOptionObj.nextQuestion - 1;
+
+          this.tableDatatop = this.tableDatatop.map((item, index) => {
+            // 淇濈暀褰撳墠棰樼洰涔嬪墠鐨勯殣钘忕姸鎬�
+            if (index < questionIndex) {
+              return {
+                ...item,
+                astrict: previouslyHiddenBeforeCurrent.includes(index),
+                hiddenByEnd: false, // 娓呴櫎缁撴潫鏍囪
+              };
+            }
+
+            // 褰撳墠棰樼洰鎬绘槸鍙
+            if (index === questionIndex) {
+              return { ...item, astrict: 0, hiddenByEnd: false };
+            }
+
+            // 鏄剧ず鐩爣涓嬩竴棰�
+            if (index === nextQuestionIndex) {
+              return { ...item, astrict: 0, hiddenByEnd: false };
+            }
+
+            // 濡傛灉鏄箣鍓嶈缁撴潫闂瓟闅愯棌鐨勯鐩紝鐜板湪搴旇鎭㈠鏄剧ず
+            if (item.hiddenByEnd) {
+              return { ...item, astrict: 0, hiddenByEnd: false };
+            }
+
+            // 闅愯棌褰撳墠棰樺拰鐩爣棰樹箣闂寸殑棰樼洰
+            if (index > questionIndex && index < nextQuestionIndex) {
+              return { ...item, astrict: 1, hiddenByEnd: false };
+            }
+
+            // 鍏朵粬鎯呭喌淇濇寔鍘熺姸
+            return item;
+          });
+        }
+      } else {
+        // 濡傛灉娌℃湁璺宠浆锛屽彧闇�纭繚涓嬩竴棰樺彲瑙�
+        this.tableDatatop = this.tableDatatop.map((item, index) => ({
+          ...item,
+          astrict: index === questionIndex + 1 ? 0 : item.astrict,
+          hiddenByEnd: index === questionIndex + 1 ? false : item.hiddenByEnd,
+        }));
+      }
+      2;
+
+      this.$forceUpdate();
+    },
+    overdata() {
+      this.tableDatatop.forEach((item, index) => {
+        var obj = item.svyTaskTemplateTargetoptions.find(
+          (items) => items.optioncontent == item.scriptResult
+        );
+        if (obj) {
+          if (obj.isabnormal) {
+            this.tableDatatop[index].isabnormal = obj.isabnormal;
+          }
+          this.$forceUpdate();
+        }
+      });
+    },
+    // 鍒涘缓鍐嶆闅忚鏈嶅姟
+    setupsubtask() {
+      this.$refs["zcform"].validate((valid) => {
+        if (valid) {
+          if (this.form.date1 && new Date(this.form.date1) < new Date()) {
+            this.$message.error("闅忚鏃堕棿涓嶈兘灏忎簬褰撳墠鏃堕棿");
+            return false;
+          }
+          if (this.form.resource == "2" && !this.form.remark) {
+            this.$message.error("褰撳墠閫夋嫨涓洪殢璁夸腑蹇冮殢璁块渶杈撳叆闅忚璁板綍");
+            return false;
+          }
+          this.form.remark =
+            this.form.remark + "銆�" + this.getCurrentTime() + "銆�";
+          let form = structuredClone(this.form);
+          form.visitTime = this.parseTime(form.date1);
+          form.finishtime = "";
+          if (form.resource) {
+            if (form.resource == 2) {
+              form.visitDeptCode = localStorage.getItem("deptCode")
+                ? localStorage.getItem("deptCode")
+                : form.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("鍒涘缓鎴愬姛");
+              if (form.serviceType == 13) {
+                this.$router.push({
+                  path: "/logisticsservice/zbAgain",
+                });
+              } else if (form.serviceType == 2) {
+                this.$router.push({
+                  path: "/logisticsservice/again",
+                });
+              }
+            } else {
+              this.$modal.msgError("鍒涘缓澶辫触");
+            }
+            document.querySelector("#app").scrollTo(0, 0);
+            this.dialogFormVisible = false;
+          });
+        }
+      });
+    },
+    getCurrentTime() {
+      const now = new Date();
+      const year = now.getFullYear();
+      const month = String(now.getMonth() + 1).padStart(2, "0");
+      const day = String(now.getDate()).padStart(2, "0");
+      const hours = String(now.getHours()).padStart(2, "0");
+      const minutes = String(now.getMinutes()).padStart(2, "0");
+      const seconds = String(now.getSeconds()).padStart(2, "0");
+
+      return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
+    },
+    updateScore(a, b, c) {},
+    // 鍚堝苟淇敼鐩稿叧=============================
+    toggleMergeMode() {
+      this.isMergeMode = !this.isMergeMode;
+      if (!this.isMergeMode) {
+        this.selectedServices = [];
+      }
+    },
+
+    handleSelectionChange(selection) {
+      this.selectedServices = selection
+        .filter(
+          (item) => !item.preachformson || !item.preachformson.includes("3")
+        )
+        .map((item) => ({
+          id: item.id,
+          taskid: item.taskid,
+          taskName: item.taskName,
+          sendname: item.sendname,
+        }));
+    },
+    checkSelectable(row, index) {
+      // 褰� sendstate 涓� 6 鏃朵笉鍙��
+      return row.sendstate !== 6;
+    },
+    openMergeDialog() {
+      if (this.selectedServices.length < 2) {
+        this.$message.warning("璇疯嚦灏戦�夋嫨2涓棶鍗锋湇鍔¤繘琛屽悎骞�");
+        return;
+      }
+      this.mergeDialogVisible = true;
+    },
+
+    handleMergeSave(mergedData) {
+      // 澶勭悊鍚堝苟淇濆瓨閫昏緫
+      this.mergeDialogVisible = false;
+      this.isMergeMode = false;
+      this.selectedServices = [];
+
+      // 鏄剧ず淇濆瓨缁撴灉
+      if (mergedData.successCount == mergedData.totalCount) {
+        this.$message.success(`鎴愬姛淇濆瓨 ${mergedData.successCount} 涓棶鍗穈);
+      } else if (mergedData.successCount > 0) {
+        this.$message.warning(
+          `鎴愬姛淇濆瓨 ${mergedData.successCount} 涓棶鍗凤紝澶辫触 ${
+            mergedData.totalCount - mergedData.successCount
+          } 涓猔
+        );
+      } else {
+        this.$message.error("鎵�鏈夐棶鍗蜂繚瀛樺け璐�");
+      }
+
+      // 鍒锋柊鏁版嵁
+      this.getTaskservelist();
+    },
+    // 寤剁画鎶ょ悊
+    handleContinuationCare() {
+      if (this.form.continueFlag != 2) {
+        this.$modal.confirm("鏄惁涓烘湰娆℃湇鍔″垱寤哄欢缁姢鐞嗭紵").then(() => {
+          this.$router.push({
+            path: "/followvisit/ContinueFordetails/",
+            query: {
+              taskid: this.taskid,
+              patid: this.patid,
+              id: this.id,
+              Voicetype: this.Voicetype,
+              visitCount: this.visitCount,
+            },
+          });
+        });
+      } else {
+        this.$router.push({
+          path: "/followvisit/ContinueFordetails/",
+          query: {
+            taskid: this.taskid,
+            patid: this.patid,
+            id: this.id,
+            Voicetype: this.Voicetype,
+            visitCount: this.visitCount,
+          },
+        });
+      }
+    },
+  },
+  // deactivated() {
+  //   console.log(11);
+  // },
+  beforeRouteLeave(to, from, next) {
+    this.$refs.callButton.cleanupResources();
+    if (this.$refs.CallCenterLs) {
+      console.log(1);
+
+      this.$refs.CallCenterLs.handleSeatLogout();
+    }
+    next(); // 纭繚璋冪敤 nex
+  },
+  // beforeRouteUpdate() {
+  //   console.log(33);
+  // },
+};
+</script>
+
+<style lang="scss" scoped>
+.Followupdetailspage {
+  margin: 10px;
+  display: flex;
+  flex-direction: column;
+  gap: 20px;
+}
+
+.action-container {
+  display: flex;
+  gap: 20px;
+  margin: 0 10px 20px 10px;
+
+  .manual-action {
+    flex: 1;
+    min-width: 0;
+    height: 100%;
+    /* 纭繚楂樺害缁ф壙 */
+  }
+
+  .call-action {
+    width: 60%;
+    min-width: 0;
+    height: 100%;
+    /* 纭繚楂樺害缁ф壙 */
+  }
+}
+
+.numeric-input {
+  position: relative;
+}
+
+.numeric-input::after {
+  content: "鍙兘杈撳叆鏁板瓧";
+  position: absolute;
+  right: 8px;
+  top: 50%;
+  transform: translateY(-50%);
+  font-size: 12px;
+  color: #999;
+  background: #f5f5f5;
+  padding: 2px 6px;
+  border-radius: 4px;
+}
+
+.call-container {
+  padding: 20px;
+  background: #fff;
+  border: 1px solid #dcdfe6;
+  box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.12), 0 0 6px 0 rgba(0, 0, 0, 0.04);
+  border-radius: 4px;
+  height: 100%;
+
+  .call-header {
+    margin-bottom: 20px;
+
+    h2 {
+      font-size: 20px;
+      color: #333;
+      margin: 0;
+      padding-bottom: 10px;
+      border-bottom: 1px solid #eee;
+    }
+  }
+
+  .call-status {
+    margin-bottom: 20px;
+  }
+
+  .hangup-btn {
+    text-align: center;
+    margin-top: 20px;
+  }
+}
+
+.merge-controls {
+  background: #f5f7fa;
+  border-radius: 4px;
+  margin-left: 20px;
+}
+
+.Followuserinfo {
+  margin: 10px 10px 0 10px;
+  align-items: center;
+  padding: 30px;
+  background: #ffff;
+  border: 1px solid #dcdfe6;
+  box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.12), 0 0 6px 0 rgba(0, 0, 0, 0.04);
+
+  .userinfo-text {
+    font-size: 20px;
+    margin-right: 20px;
+    margin-bottom: 10px;
+  }
+
+  .userinfo-value {
+    color: rgb(15, 139, 211);
+
+    span {
+      margin-right: 20px;
+    }
+  }
+}
+
+::v-deep.el-table .warning-row {
+  background: #c4e2ee;
+}
+
+.Followuserinfos {
+  align-items: center;
+  padding: 30px;
+  background: #ffff;
+  border: 1px solid #dcdfe6;
+  box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.12), 0 0 6px 0 rgba(0, 0, 0, 0.04);
+  height: 100%;
+  /* 纭繚楂樺害缁ф壙 */
+  min-height: 880px;
+  /* 鏈�灏忛珮搴︿笌闅忚鍐呭涓�鑷� */
+  display: flex;
+  flex-direction: column;
+
+  .userinfo-text {
+    font-size: 20px;
+    margin-right: 20px;
+    margin-bottom: 10px;
+  }
+
+  .userinfo-value {
+    color: rgb(15, 139, 211);
+
+    span {
+      margin-right: 20px;
+    }
+  }
+
+  .el-form {
+    flex: 1;
+    overflow-y: auto;
+    /* 鍐呭瓒呰繃楂樺害鏃舵樉绀烘粴鍔ㄦ潯 */
+    max-height: calc(880px - 60px);
+    /* 鍑忓幓padding */
+    padding-right: 10px;
+    /* 闃叉婊氬姩鏉¢伄鎸″唴瀹� */
+  }
+}
+
+.append-input-container {
+  margin-top: 15px;
+  padding: 10px;
+  background-color: #f5f7fa;
+  border-radius: 4px;
+  border: 1px solid #dcdfe6;
+}
+
+.borderdiv {
+  min-height: 60vh;
+  font-size: 20px;
+  padding: 30px;
+
+  .title {
+    font-size: 22px;
+    font-weight: bold;
+    margin-bottom: 20px;
+    text-align: center;
+  }
+
+  .leftside {
+    margin: 30px 0;
+
+    span {
+      width: 400px;
+      margin-left: 20px;
+      padding: 10px;
+      color: #fff;
+      background: rgb(110, 196, 247);
+      border-radius: 10px;
+    }
+  }
+
+  .offside {
+    display: flex;
+    flex-direction: row-reverse;
+
+    .offside-value {
+      padding: 10px;
+      background: rgb(217, 173, 253);
+      border-radius: 10px;
+      color: #fff;
+      margin-right: 20px;
+    }
+  }
+}
+
+.topic-dev[inert] {
+  opacity: 0.5;
+  pointer-events: none;
+}
+/* 鎸傛柇瀹瑰櫒鏍峰紡 */
+.hangup-container {
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  gap: 10px;
+  margin: 15px 0;
+}
+
+.hangup-btn {
+  width: 120px;
+  height: 40px;
+  font-size: 14px;
+  border-radius: 20px;
+  box-shadow: 0 2px 8px rgba(244, 67, 54, 0.3);
+  transition: all 0.3s ease;
+}
+
+.hangup-btn:hover:not(:disabled) {
+  transform: translateY(-2px);
+  box-shadow: 0 4px 12px rgba(244, 67, 54, 0.4);
+}
+
+/* 閫氳瘽璁℃椂鍣� */
+.call-timer {
+  font-size: 12px;
+  color: #666;
+  background: #f5f5f5;
+  padding: 4px 12px;
+  border-radius: 12px;
+  font-family: "Courier New", monospace;
+}
+
+/* 鐘舵�佹彁绀哄鍣� */
+.call-status-container {
+  margin: 10px 0;
+}
+
+.status-alert {
+  border-radius: 8px;
+  transition: all 0.3s ease;
+}
+
+.status-alert.status-calling {
+  border-left: 4px solid #e6a23c;
+}
+
+.status-alert.status-connected {
+  border-left: 4px solid #67c23a;
+  animation: pulse 2s infinite;
+}
+
+.status-alert.status-ended {
+  border-left: 4px solid #909399;
+}
+
+/* SIP娉ㄥ唽鎻愮ず */
+.sip-registering {
+  margin: 10px 0;
+}
+
+.registering-alert {
+  border-radius: 8px;
+  background-color: #f4f4f5;
+  border-left: 4px solid #909399;
+}
+
+/* 鍔ㄧ敾鏁堟灉 */
+@keyframes pulse {
+  0% {
+    opacity: 1;
+  }
+  50% {
+    opacity: 0.7;
+  }
+  100% {
+    opacity: 1;
+  }
+}
+
+/* 鍝嶅簲寮忚璁� */
+@media (max-width: 768px) {
+  .hangup-container {
+    margin: 10px 0;
+  }
+
+  .hangup-btn {
+    width: 100%;
+    max-width: 200px;
+  }
+
+  .status-alert {
+    font-size: 12px;
+  }
+}
+.CONTENT {
+  padding: 10px;
+  height: 100%;
+  min-height: 738px;
+  /* 璁剧疆鏈�灏忛珮搴� */
+
+  .title {
+    font-size: 22px;
+    font-weight: bold;
+    margin-bottom: 20px;
+    text-align: center;
+  }
+}
+
+.preview-left {
+  margin: 20px;
+  padding: 30px;
+  border: 1px solid #dcdfe6;
+  box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.12), 0 0 6px 0 rgba(0, 0, 0, 0.04);
+  max-height: 716px;
+  /* 璁剧疆鏈�澶ч珮搴� */
+  overflow-y: auto;
+  /* 鍐呭瓒呰繃楂樺害鏃舵樉绀烘粴鍔ㄦ潯 */
+
+  .topic-dev {
+    margin-bottom: 25px;
+    font-size: 20px !important;
+
+    .dev-text {
+      margin-bottom: 10px;
+    }
+  }
+}
+
+.scriptTopic-isabnormal {
+  color: red;
+}
+
+.detailed {
+  width: 88%;
+  border-radius: 8px;
+  padding: 30px;
+  margin-bottom: 30px;
+  background-color: #ddf0f8;
+
+  .bg-purple {
+    margin-bottom: 20px;
+  }
+
+  .spanvalue {
+    display: inline-block;
+    min-width: 200px;
+    border-bottom: 1px solid rgb(172, 172, 172);
+  }
+}
+
+.headline {
+  font-size: 24px;
+  height: 40px;
+  border-left: 5px solid #41a1be;
+  padding-left: 5px;
+  margin-bottom: 10px;
+  display: flex;
+
+  .Add-details {
+    font-size: 18px;
+    color: #02a7f0;
+    cursor: pointer;
+  }
+}
+
+/* 寮傚父鐘舵�佹牱寮� - 绾㈣壊 (淇濇寔涓嶅彉) */
+.scriptTopic-isabnormal {
+  color: red;
+}
+
+/* 鏂板锛氳鍛婄姸鎬佹牱寮� - 榛勮壊 */
+.scriptTopic-warning {
+  color: #d4be00;
+  /* 鎮ㄦ寚瀹氱殑榛勮壊 */
+}
+
+/* 寮傚父閫夐」鏍峰紡 - 绾㈣壊鏄熷彿 (淇濇寔涓嶅彉) */
+.red-star {
+  ::v-deep.el-radio__label {
+    position: relative;
+    padding-right: 10px;
+  }
+
+  ::v-deep.el-radio__label::after {
+    content: "*";
+    color: red;
+    position: absolute;
+    right: -5px;
+    top: 0;
+  }
+}
+
+/* 鏂板锛氳鍛婇�夐」鏍峰紡 - 榛勮壊鏄熷彿 */
+.yellow-star {
+  ::v-deep.el-radio__label {
+    position: relative;
+    padding-right: 10px;
+  }
+
+  ::v-deep.el-radio__label::after {
+    content: "*";
+    color: #ffe202;
+    /* 榛勮壊鏄熷彿 */
+    position: absolute;
+    right: -5px;
+    top: 0;
+    font-weight: bold;
+  }
+}
+
+/* 鍏辩敤鏍峰紡淇濇寔涓嶅彉 */
+::v-deep.el-input-group__textarea {
+  white-space: pre-wrap;
+  word-break: break-all;
+}
+
+::v-deep.el-checkbox__label {
+  position: relative;
+  padding-right: 10px;
+}
+
+::v-deep.el-checkbox__label::after {
+  content: "*";
+  color: red;
+  position: absolute;
+  right: -5px;
+  top: 0;
+}
+
+.tag-selector-container {
+  display: flex;
+  align-items: center;
+  margin: 0 30px;
+}
+
+.color-indicator {
+  width: 16px;
+  height: 16px;
+  border-radius: 3px;
+  margin-right: 8px;
+  display: inline-block;
+}
+
+.selected-indicator {
+  margin-left: 10px;
+  width: 20px;
+  height: 20px;
+}
+
+.tag-info-icon {
+  margin-left: 10px;
+  color: #909399;
+  cursor: pointer;
+  font-size: 16px;
+}
+
+/* 纭繚閫夋嫨鍣ㄩ�夐」涓篃鏄剧ず棰滆壊鍧� */
+.el-select-dropdown__item {
+  display: flex;
+  align-items: center;
+}
+
+.tag-normal {
+  background-color: #7ff5e1;
+}
+
+.tag-abnormal {
+  background-color: #f75c5c;
+}
+
+.tag-warning {
+  background-color: #fbfb4a;
+}
+
+.tag-info {
+  margin-left: 10px;
+  color: #909399;
+  cursor: pointer;
+}
+
+::v-deep.offside-value .el-radio__label {
+  color: #fff;
+}
+
+::v-deep.el-link.el-link--default {
+  color: #02a7f0 !important;
+}
+
+.el-message-box__btns button:nth-child(2) {
+  margin-left: 10px;
+  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;
+}
+
+/* 鍘熸湁鐨勬牱寮忎繚鎸佷笉鍙橈紝娣诲姞浠ヤ笅鍝嶅簲寮忎唬鐮� */
+
+.Followupdetailspage {
+  margin: 10px;
+  display: flex;
+  flex-direction: column;
+  gap: 20px;
+}
+
+.action-container {
+  display: flex;
+  flex-direction: row;
+  /* 榛樿妯悜鎺掑垪 */
+  gap: 20px;
+  margin: 0 10px 20px 10px;
+
+  /* 褰撶缉鏀炬瘮渚嬪ぇ浜�100%鎴栧睆骞曞搴﹁緝灏忔椂鏀逛负涓婁笅鎺掑垪 */
+  @media screen and (min-resolution: 1.5dppx) {
+    flex-direction: column;
+
+    .call-action,
+    .manual-action {
+      width: 100% !important;
+    }
+  }
+}
+
+.call-action {
+  width: 65%;
+  min-width: 0;
+}
+
+.manual-action {
+  flex: 1;
+  min-width: 0;
+}
+
+/* 璋冩暣鍐呴儴鍏冪礌鐨勫搷搴斿紡甯冨眬 */
+.Followuserinfos {
+  .el-form {
+    /* 琛ㄥ崟鍝嶅簲寮忚皟鏁� */
+    .el-row {
+      margin: 0 -10px;
+    }
+
+    .el-col {
+      padding: 0 10px;
+    }
+
+    @media screen and (max-width: 768px) {
+      .el-col {
+        width: 100%;
+        margin-bottom: 15px;
+
+        &:last-child {
+          margin-bottom: 0;
+        }
+      }
+    }
+  }
+}
+
+/* 璋冩暣琛ㄦ牸鐨勫搷搴斿紡琛ㄧ幇 */
+.el-table {
+  ::v-deep .el-table__body-wrapper {
+    overflow-x: auto;
+  }
+
+  /* 鍦ㄥ皬灞忓箷涓婅皟鏁磋〃鏍煎垪瀹� */
+  @media screen and (max-width: 992px) {
+    .el-table-column {
+      min-width: 120px;
+    }
+  }
+}
+
+/* 璋冩暣鏍囩閫夋嫨鍣ㄧ殑鍝嶅簲寮忓竷灞� */
+.tag-selector-container {
+  display: flex;
+  align-items: center;
+  flex-wrap: wrap;
+  gap: 10px;
+
+  @media screen and (max-width: 576px) {
+    flex-direction: column;
+    align-items: flex-start;
+
+    .el-select {
+      width: 100%;
+      margin-right: 0 !important;
+    }
+  }
+}
+
+/* 璋冩暣鎸夐挳缁勭殑鍝嶅簲寮忓竷灞� */
+.el-form-item.label-processing-opinion {
+  .el-button-group {
+    display: flex;
+    flex-wrap: wrap;
+    gap: 10px;
+
+    .el-button {
+      flex: 1;
+      min-width: 120px;
+    }
+  }
+}
+
+/* 璋冩暣閫夐」鍗$殑鍝嶅簲寮忚〃鐜� */
+.el-tabs {
+  ::v-deep .el-tabs__nav-wrap {
+    overflow-x: auto;
+    white-space: nowrap;
+
+    &::after {
+      display: none;
+    }
+  }
+}
+
+/* 璋冩暣棰勮鍖哄煙鐨勫搷搴斿紡琛ㄧ幇 */
+.preview-left {
+  @media screen and (max-width: 768px) {
+    margin: 10px;
+    padding: 15px;
+
+    .topic-dev,
+    .scriptTopic-dev {
+      margin-bottom: 15px;
+    }
+  }
+}
+
+/* 璋冩暣瀵硅瘽妗嗙殑鍝嶅簲寮忚〃鐜� */
+.el-dialog {
+  @media screen and (max-width: 992px) {
+    width: 90% !important;
+    margin-top: 5vh !important;
+
+    .el-dialog__body {
+      padding: 15px;
+    }
+  }
+
+  @media screen and (max-width: 576px) {
+    width: 95% !important;
+
+    .el-form-item {
+      margin-bottom: 15px;
+    }
+  }
+}
+
+/* 纭繚鍐呭鍦ㄧ缉鏀炬椂淇濇寔鍙鎬� */
+.headline {
+  font-size: clamp(18px, 2vw, 24px);
+  /* 浣跨敤clamp鍑芥暟纭繚瀛椾綋澶у皬鍦ㄥ悎鐞嗚寖鍥村唴 */
+}
+
+/* 涓虹Щ鍔ㄨ澶囦紭鍖栨粴鍔ㄤ綋楠� */
+@media screen and (max-width: 768px) {
+  .Followuserinfo,
+  .Followuserinfos {
+    padding: 15px;
+    margin: 5px;
+  }
+
+  .CONTENT {
+    min-height: auto;
+    padding: 5px;
+  }
+}
+
+/* 缂╂斁妫�娴嬫牱寮� */
+@media screen and (min-resolution: 1.5dppx),
+  screen and (-webkit-min-device-pixel-ratio: 1.5) {
+  .action-container {
+    flex-direction: column;
+  }
+
+  .call-action,
+  .manual-action {
+    width: 100%;
+  }
+
+  /* 璋冩暣鍐呴儴鍏冪礌闂磋窛 */
+  .call-container,
+  .Followuserinfos {
+    margin-bottom: 20px;
+  }
+}
+/* 浜哄伐澶勭悊閮ㄥ垎鏍峰紡 */
+.manual-action {
+  flex: 1;
+  min-width: 0;
+  height: 100%;
+  overflow: hidden;
+
+  .Followuserinfos {
+    display: flex;
+    flex-direction: column;
+    gap: 20px;
+    padding: 20px;
+    background: #fff;
+    border-radius: 8px;
+    box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
+    height: 100%;
+    overflow-y: auto;
+  }
+}
+
+/* 澶撮儴鍖哄煙 */
+.section-header {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  padding-bottom: 15px;
+  border-bottom: 2px solid #f0f0f0;
+  margin-bottom: 20px;
+  flex-wrap: wrap;
+  gap: 15px;
+
+  h3 {
+    margin: 0;
+    color: #409eff;
+    font-size: 18px;
+    font-weight: 600;
+    display: flex;
+    align-items: center;
+    gap: 8px;
+
+    i {
+      font-size: 20px;
+    }
+  }
+
+  .header-actions {
+    display: flex;
+    align-items: center;
+    flex-wrap: wrap;
+    gap: 15px;
+
+    .action-group {
+      display: flex;
+      align-items: center;
+      gap: 10px;
+    }
+  }
+}
+
+/* 鍩虹鎿嶄綔鎸夐挳 */
+.basic-actions {
+  .el-button {
+    min-width: 100px;
+  }
+}
+
+/* 寮傚父鐘舵�侀�夋嫨鍣� */
+.tag-selector {
+  display: flex;
+  align-items: center;
+  gap: 10px;
+
+  .current-tag {
+    display: flex;
+    align-items: center;
+    gap: 8px;
+    padding: 6px 12px;
+    background: #f8f9fa;
+    border: 1px solid;
+    border-radius: 4px;
+    font-size: 12px;
+    transition: all 0.3s;
+
+    &:hover {
+      box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
+    }
+  }
+}
+
+.color-indicator {
+  width: 16px;
+  height: 16px;
+  border-radius: 3px;
+  margin-right: 8px;
+  display: inline-block;
+}
+
+.selected-indicator {
+  margin-left: 10px;
+  width: 20px;
+  height: 20px;
+}
+
+.tag-info-icon {
+  margin-left: 10px;
+  color: #909399;
+  cursor: pointer;
+  font-size: 16px;
+}
+
+/* 琛ㄥ崟鍖哄煙 */
+.form-content {
+  background: #f8f9fa;
+  border-radius: 8px;
+  padding: 20px;
+  margin-bottom: 20px;
+
+  .el-form {
+    .el-row {
+      margin: 0 -10px;
+    }
+
+    .el-col {
+      padding: 0 10px;
+    }
+  }
+}
+
+/* 閫氳瘽鎺у埗鍖哄煙 */
+.call-controls {
+  margin: 15px 0;
+
+  .hangup-container {
+    display: flex;
+    flex-direction: column;
+    align-items: center;
+    gap: 10px;
+    margin: 15px 0;
+  }
+
+  .hangup-btn {
+    width: 120px;
+    height: 40px;
+    font-size: 14px;
+    border-radius: 20px;
+    box-shadow: 0 2px 8px rgba(244, 67, 54, 0.3);
+    transition: all 0.3s ease;
+  }
+
+  .hangup-btn:hover:not(:disabled) {
+    transform: translateY(-2px);
+    box-shadow: 0 4px 12px rgba(244, 67, 54, 0.4);
+  }
+
+  .call-timer {
+    font-size: 12px;
+    color: #666;
+    background: #f5f5f5;
+    padding: 4px 12px;
+    border-radius: 12px;
+    font-family: "Courier New", monospace;
+  }
+
+  .call-status-container {
+    margin: 10px 0;
+  }
+
+  .status-alert {
+    border-radius: 8px;
+    transition: all 0.3s ease;
+  }
+
+  .status-alert.status-calling {
+    border-left: 4px solid #e6a23c;
+  }
+
+  .status-alert.status-connected {
+    border-left: 4px solid #67c23a;
+    animation: pulse 2s infinite;
+  }
+
+  .status-alert.status-ended {
+    border-left: 4px solid #909399;
+  }
+
+  .sip-registering {
+    margin: 10px 0;
+  }
+
+  .registering-alert {
+    border-radius: 8px;
+    background-color: #f4f4f5;
+    border-left: 4px solid #909399;
+  }
+}
+
+/* 澶勭悊鎰忚鎸夐挳缁� */
+.opinion-buttons {
+  display: flex;
+  flex-wrap: wrap;
+  gap: 10px;
+  align-items: center;
+
+  .el-button {
+    flex: 1;
+    min-width: 120px;
+  }
+}
+
+/* 鎮h�呮。妗堜俊鎭� */
+.detailed {
+  width: 100%;
+  border-radius: 8px;
+  padding: 20px;
+  margin-bottom: 20px;
+  background-color: #ddf0f8;
+  border: 1px solid #b3e0f2;
+
+  h3 {
+    margin: 0 0 20px 0;
+    color: #333;
+    font-size: 16px;
+    font-weight: 500;
+    display: flex;
+    align-items: center;
+    gap: 8px;
+
+    &:before {
+      content: "";
+      display: block;
+      width: 4px;
+      height: 16px;
+      background: #409eff;
+      border-radius: 2px;
+    }
+  }
+
+  .el-form {
+    .el-row {
+      margin: 0 -10px;
+    }
+
+    .el-col {
+      padding: 0 10px;
+      margin-bottom: 15px;
+    }
+  }
+}
+
+/* 鍔ㄧ敾鏁堟灉 */
+@keyframes pulse {
+  0% {
+    opacity: 1;
+  }
+  50% {
+    opacity: 0.7;
+  }
+  100% {
+    opacity: 1;
+  }
+}
+
+/* 鍝嶅簲寮忚璁� */
+@media screen and (max-width: 1200px) {
+  .section-header {
+    flex-direction: column;
+    align-items: flex-start;
+    gap: 15px;
+  }
+
+  .header-actions {
+    width: 100%;
+    justify-content: space-between;
+  }
+
+  .opinion-buttons {
+    .el-button {
+      min-width: calc(50% - 8px);
+    }
+  }
+}
+
+@media screen and (max-width: 768px) {
+  .Followuserinfos {
+    padding: 15px;
+  }
+
+  .form-content,
+  .detailed {
+    padding: 15px;
+  }
+
+  .header-actions {
+    flex-direction: column;
+    align-items: stretch;
+
+    .action-group {
+      flex-direction: column;
+      align-items: stretch;
+
+      .el-select {
+        width: 100%;
+        margin-right: 0;
+      }
+    }
+  }
+
+  .opinion-buttons {
+    flex-direction: column;
+
+    .el-button {
+      width: 100%;
+    }
+  }
+
+  .detailed {
+    .el-form {
+      .el-col {
+        width: 100%;
+      }
+    }
+  }
+}
+
+/* 婊氬姩鏉$編鍖� */
+.Followuserinfos {
+  &::-webkit-scrollbar {
+    width: 6px;
+  }
+
+  &::-webkit-scrollbar-track {
+    background: #f1f1f1;
+    border-radius: 3px;
+  }
+
+  &::-webkit-scrollbar-thumb {
+    background: #c1c1c1;
+    border-radius: 3px;
+
+    &:hover {
+      background: #a8a8a8;
+    }
+  }
+}
+
+/* 鎸夐挳鍥炬爣浼樺寲 */
+.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);
+}
+</style>
diff --git a/src/views/followvisit/record/detailpage/index.vue b/src/views/followvisit/record/detailpage/index.vue
index 10a6605..a58c449 100644
--- a/src/views/followvisit/record/detailpage/index.vue
+++ b/src/views/followvisit/record/detailpage/index.vue
@@ -128,6 +128,9 @@
                   >宸插畬鎴�</el-tag
                 >
               </div>
+              <div v-if="scope.row.sendstate == 7">
+                <el-tag type="danger" :disable-transitions="false">瓒呮椂</el-tag>
+              </div>
             </template>
           </el-table-column>
           <el-table-column
@@ -282,11 +285,7 @@
                     >
                       <!-- 鍗曢�� -->
                       <div
-                        :class="
-                          item.isabnormal
-                            ? 'scriptTopic-isabnormal'
-                            : 'scriptTopic-dev'
-                        "
+                        :class="getTopicClass(item)"
                         :key="index"
                         v-if="item.scriptType == 1 && !item.astrict"
                       >
@@ -301,7 +300,7 @@
                               v-for="(
                                 items, indexs
                               ) in item.svyTaskTemplateTargetoptions"
-                              :class="items.isabnormal ? 'red-star' : ''"
+                              :class="getOptionClass(items)"
                               :key="indexs"
                               :label="items.optioncontent"
                               @click.native.prevent="
@@ -553,76 +552,96 @@
       <!-- 浜哄伐澶勭悊 -->
       <div class="manual-action">
         <div class="Followuserinfos">
-          <div>
+          <!-- 椤堕儴鎿嶄綔鍖哄煙 -->
+          <div class="section-header">
+            <h3><i class="el-icon-s-operation"></i> 浜哄伐澶勭悊</h3>
+            <div class="header-actions">
+              <!-- 鍩虹鎿嶄綔鎸夐挳缁� -->
+              <div class="action-group basic-actions">
+                <el-button
+                  type="primary"
+                  plain
+                  @click="Editsingletasksonyic('')"
+                >
+                  淇濆瓨鍩虹淇℃伅
+                </el-button>
+
+                <!-- 鏂板锛氬欢缁姢鐞嗘寜閽� -->
+                <el-button
+                  type="success"
+                  plain
+                  @click="handleContinuationCare"
+                  v-if="showContinuationCareBtn"
+                >
+                  寤剁画鎶ょ悊
+                </el-button>
+
+                <el-button
+                  type="primary"
+                  round
+                  @click="sendAgain"
+                  v-if="form.isVisitAgain != 2"
+                >
+                  鍐嶆闅忚
+                </el-button>
+              </div>
+
+              <!-- 寮傚父鐘舵�侀�夋嫨鍣� -->
+              <div class="action-group tag-selector">
+                <el-select
+                  v-model="selectedTag"
+                  placeholder="璇烽�夋嫨寮傚父鐘舵��"
+                  clearable
+                  style="width: 150px; margin-right: 10px"
+                >
+                  <el-option
+                    v-for="item in tagOptions"
+                    :key="item.value"
+                    :label="item.label"
+                    :value="item.value"
+                  >
+                    <span style="display: flex; align-items: center">
+                      <span
+                        class="color-indicator"
+                        :style="{ backgroundColor: item.color }"
+                      ></span>
+                      <span>{{ item.label }}</span>
+                    </span>
+                  </el-option>
+                </el-select>
+
+                <!-- 褰撳墠閫夋嫨鐨勯鑹叉寚绀哄櫒 -->
+                <div
+                  v-if="selectedTag"
+                  class="color-indicator selected-indicator"
+                  :style="{ backgroundColor: getSelectedTagColor() }"
+                ></div>
+
+                <!-- 鏍囪璇存槑鎻愮ず -->
+                <el-tooltip
+                  v-if="selectedTag"
+                  effect="light"
+                  :content="getSelectedDescription()"
+                  placement="top"
+                >
+                  <i class="el-icon-info tag-info-icon"></i>
+                </el-tooltip>
+              </div>
+            </div>
+          </div>
+
+          <!-- 琛ㄥ崟鍖哄煙 -->
+          <div class="form-content">
             <el-form
               ref="userform"
               :model="form"
               :rules="userrules"
-              label-width="120px"
+              label-width="100px"
             >
-              <div class="headline">
-                <div>浜哄伐澶勭悊</div>
-                <div style="margin: 0 30px">
-                  <el-button
-                    type="primary"
-                    plain
-                    @click="Editsingletasksonyic('')"
-                    >淇濆瓨鍩虹淇℃伅</el-button
-                  >
-                </div>
-                <div>
-                  <el-button
-                    type="primary"
-                    round
-                    v-if="this.form.isVisitAgain != 2"
-                    @click="sendAgain()"
-                    >鍐嶆闅忚</el-button
-                  >
-                </div>
-                <div class="tag-selector-container">
-                  <el-select
-                    v-model="selectedTag"
-                    placeholder="璇烽�夋嫨寮傚父鐘舵��"
-                    clearable
-                    style="width: 150px; margin-right: 10px"
-                  >
-                    <el-option
-                      v-for="item in tagOptions"
-                      :key="item.value"
-                      :label="item.label"
-                      :value="item.value"
-                    >
-                      <span style="display: flex; align-items: center">
-                        <span
-                          class="color-indicator"
-                          :style="{ backgroundColor: item.color }"
-                        ></span>
-                        <span>{{ item.label }}</span>
-                      </span>
-                    </el-option>
-                  </el-select>
-
-                  <!-- 褰撳墠閫夋嫨鐨勯鑹叉寚绀哄櫒 -->
-                  <div
-                    v-if="selectedTag"
-                    class="color-indicator selected-indicator"
-                    :style="{ backgroundColor: getSelectedTagColor() }"
-                  ></div>
-
-                  <!-- 鏍囪璇存槑鎻愮ず -->
-                  <el-tooltip
-                    v-if="selectedTag"
-                    effect="light"
-                    :content="getSelectedDescription()"
-                    placement="top"
-                  >
-                    <i class="el-icon-info tag-info-icon"></i>
-                  </el-tooltip>
-                </div>
-              </div>
+              <!-- 鑱旂郴淇℃伅琛� -->
               <el-row>
-                <el-col :span="14"
-                  ><el-form-item label="鑱旂郴鐢佃瘽">
+                <el-col :span="14">
+                  <el-form-item label="鑱旂郴鐢佃瘽">
                     <el-input
                       placeholder="鑱旂郴鐢佃瘽缂哄け"
                       v-model="userform.telcode"
@@ -632,13 +651,33 @@
                         icon="el-icon-phone"
                         @click="handleCall(userform.telcode, 'tel')"
                         :disabled="!isValidPhone(userform.telcode)"
-                      ></el-button
-                    ></el-input> </el-form-item
-                ></el-col>
+                      ></el-button>
+                    </el-input>
+                  </el-form-item>
+                </el-col>
+                <el-col :span="10">
+                  <el-form-item
+                    label="鐭彿鐢佃瘽"
+                    v-if="orgname == '鏅畞鐣叉棌鑷不鍘夸汉姘戝尰闄�'"
+                  >
+                    <el-input
+                      placeholder="鑱旂郴鐢佃瘽缂哄け"
+                      v-model="userform.telshortcode"
+                    >
+                      <el-button
+                        slot="append"
+                        icon="el-icon-phone"
+                        @click="handleCall(userform.telshortcode, 'tel', true)"
+                      ></el-button>
+                    </el-input>
+                  </el-form-item>
+                </el-col>
               </el-row>
+
+              <!-- 鑱旂郴浜轰俊鎭 -->
               <el-row>
-                <el-col :span="14"
-                  ><el-form-item label="鑱旂郴浜虹數璇�">
+                <el-col :span="14">
+                  <el-form-item label="鑱旂郴浜虹數璇�">
                     <el-input
                       placeholder="鑱旂郴浜虹數璇濈己澶�"
                       v-model="userform.relativetelcode"
@@ -650,17 +689,21 @@
                           handleCall(userform.relativetelcode, 'relative')
                         "
                         :disabled="!isValidPhone(userform.relativetelcode)"
-                      ></el-button
-                    ></el-input> </el-form-item
-                ></el-col>
-                <el-col :span="10"
-                  ><el-form-item label="鑱旂郴浜哄叧绯�">
+                      ></el-button>
+                    </el-input>
+                  </el-form-item>
+                </el-col>
+                <el-col :span="9">
+                  <el-form-item label="鍏崇郴">
                     <el-input
                       placeholder="鑱旂郴浜哄叧绯荤己澶�"
                       v-model="userform.relation"
-                    ></el-input> </el-form-item
-                ></el-col>
+                    ></el-input>
+                  </el-form-item>
+                </el-col>
               </el-row>
+
+              <!-- 閫氳瘽鎺у埗鍖哄煙 -->
               <div class="call-controls">
                 <CallButton
                   ref="callButton"
@@ -668,32 +711,59 @@
                   style="display: none"
                 />
 
-                <div v-if="callStatus === 'connected'" class="hangup-btn">
+                <!-- 鎸傛柇鎸夐挳鏍峰紡浼樺寲 -->
+                <div v-if="callStatus === 'connected'" class="hangup-container">
                   <el-button
                     type="danger"
                     icon="el-icon-phone"
                     @click="endCurrentCall"
                     :loading="isEndingCall"
+                    class="hangup-btn"
+                    size="medium"
                   >
-                    鎸傛柇鐢佃瘽
+                    {{ isEndingCall ? "鎸傛柇涓�..." : "鎸傛柇鐢佃瘽" }}
                   </el-button>
+
+                  <!-- 閫氳瘽璁℃椂鏄剧ず -->
+                  <div class="call-timer" v-if="callStartTime">
+                    閫氳瘽鏃堕暱: {{ formatCallTime }}
+                  </div>
                 </div>
-                <div class="call-status" v-if="callStatus !== 'idle'">
+
+                <!-- 鐘舵�佹彁绀轰紭鍖� -->
+                <div class="call-status-container" v-if="callStatus !== 'idle'">
                   <el-alert
                     :title="callStatusText"
                     :type="callStatusType"
                     :closable="false"
                     show-icon
+                    :class="['status-alert', `status-${callStatus}`]"
+                  />
+                </div>
+
+                <!-- SIP娉ㄥ唽鐘舵�佹彁绀� -->
+                <div
+                  v-if="isSipRegistering && orgname == '涓芥按甯備腑鍖婚櫌'"
+                  class="sip-registering"
+                >
+                  <el-alert
+                    title="鍛煎彨搴ф満鍒濆鍖栦腑锛岃绋嶅��..."
+                    type="info"
+                    :closable="false"
+                    show-icon
+                    class="registering-alert"
                   />
                 </div>
               </div>
-              <el-form-item label="闅忚鍐呭" v-if="orgname == '涓芥按甯備腑鍖婚櫌'">
-                <el-input type="textarea" v-model="form.remark"></el-input>
-              </el-form-item>
-              <el-form-item label="闅忚璁板綍" v-else>
+
+              <!-- 闅忚鍐呭/璁板綍 -->
+              <el-form-item
+                :label="orgname == '涓芥按甯備腑鍖婚櫌' ? '闅忚鍐呭' : '闅忚璁板綍'"
+              >
                 <el-input type="textarea" v-model="form.remark"></el-input>
               </el-form-item>
 
+              <!-- 闅忚鎯呭喌 -->
               <el-form-item label="闅忚鎯呭喌" v-if="orgname == '涓芥按甯備腑鍖婚櫌'">
                 <el-radio-group v-model="form.taskSituation">
                   <el-radio
@@ -701,121 +771,136 @@
                     :label="city.value"
                     :value="city.value"
                     :key="city.value"
-                    >{{ city.label }}</el-radio
                   >
+                    {{ city.label }}
+                  </el-radio>
                 </el-radio-group>
               </el-form-item>
+
+              <!-- 澶勭悊鎰忚 -->
               <el-form-item label="澶勭悊鎰忚">
-                <div>
+                <div class="opinion-buttons">
                   <el-button
                     plain
                     type="warning"
                     @click="Editsingletaskson('1')"
-                    >鏆備笉澶勭悊</el-button
                   >
+                    鏆備笉澶勭悊
+                  </el-button>
                   <el-button
                     plain
                     type="success"
                     @click="Editsingletaskson('2')"
-                    >鐥呮儏绋冲畾</el-button
                   >
+                    鐥呮儏绋冲畾
+                  </el-button>
                   <el-button
                     plain
                     type="primary"
                     @click="Editsingletaskson('3')"
-                    >閫氱煡灏辫瘖</el-button
                   >
-                  <el-button plain type="info" @click="Editsingletaskson('5')"
-                    >涓績闅忚</el-button
-                  >
-                  <el-button type="primary" round @click="sendAgainmsg"
-                    >鐭俊鍙戦��</el-button
-                  >
+                    閫氱煡灏辫瘖
+                  </el-button>
+                  <el-button plain type="info" @click="Editsingletaskson('5')">
+                    浜哄伐闅忚
+                  </el-button>
+                  <el-button type="primary" round @click="sendAgainmsg">
+                    鐭俊鍙戦��
+                  </el-button>
                 </div>
               </el-form-item>
             </el-form>
+          </div>
 
-            <div class="detailed">
-              <h3>鎮h�呮。妗堜俊鎭�</h3>
-              <el-form ref="userform" :model="userform" label-width="100px">
-                <el-row :gutter="20">
-                  <el-col :span="12">
-                    <el-form-item label="鎮h�呭鍚�" prop="name">
-                      <el-input
-                        v-model="userform.name"
-                        placeholder="璇疯緭鍏ュ鍚�"
-                        maxlength="30"
-                      ></el-input> </el-form-item
-                  ></el-col>
-                </el-row>
-                <el-row :gutter="20">
-                  <el-col :span="12"
-                    ><el-form-item label="鎬у埆" prop="telcode">
-                      <el-select v-model="userform.sex" placeholder="璇烽�夋嫨">
-                        <el-option label="鐢�" :value="1"> </el-option>
-                        <el-option label="濂�" :value="2"> </el-option>
-                      </el-select> </el-form-item
-                  ></el-col>
-                  <el-col :span="12">
-                    <el-form-item label="骞撮緞" prop="name">
-                      <el-input
-                        v-model="userform.age"
-                        placeholder="璇疯緭鍏ュ鍚�"
-                        maxlength="20"
-                      ></el-input> </el-form-item
-                  ></el-col>
-                </el-row>
+          <!-- 鎮h�呮。妗堜俊鎭� -->
+          <div class="detailed">
+            <h3>鎮h�呮。妗堜俊鎭�</h3>
+            <el-form ref="userform" :model="userform" label-width="100px">
+              <el-row :gutter="20">
+                <el-col :span="12">
+                  <el-form-item label="鎮h�呭鍚�" prop="name">
+                    <el-input
+                      v-model="userform.name"
+                      placeholder="璇疯緭鍏ュ鍚�"
+                      maxlength="30"
+                    ></el-input>
+                  </el-form-item>
+                </el-col>
+              </el-row>
+              <el-row :gutter="20">
+                <el-col :span="12">
+                  <el-form-item label="鎬у埆" prop="sex">
+                    <el-select v-model="userform.sex" placeholder="璇烽�夋嫨">
+                      <el-option label="鐢�" :value="1"> </el-option>
+                      <el-option label="濂�" :value="2"> </el-option>
+                    </el-select>
+                  </el-form-item>
+                </el-col>
+                <el-col :span="12">
+                  <el-form-item label="骞撮緞" prop="age">
+                    <el-input
+                      v-model="userform.age"
+                      placeholder="璇疯緭鍏ュ勾榫�"
+                      maxlength="20"
+                    ></el-input>
+                  </el-form-item>
+                </el-col>
+              </el-row>
 
-                <el-row :gutter="20">
-                  <el-col :span="12"
-                    ><el-form-item label="鑱旂郴鏂瑰紡" prop="telcode">
-                      <el-input
-                        v-model="userform.telcode"
-                        placeholder="璇疯緭鍏ヨ仈绯绘柟寮�"
-                        maxlength="20"
-                      /> </el-form-item
-                  ></el-col>
-                  <el-col :span="12">
-                    <el-form-item label="浜插睘鑱旂郴鏂瑰紡" prop="name">
-                      <el-input
-                        v-model="userform.relativetelcode"
-                        placeholder="璇疯緭鍏ュ鍚�"
-                        maxlength="20"
-                      ></el-input> </el-form-item
-                  ></el-col>
-                </el-row>
-                <el-row :gutter="20">
-                  <el-col :span="24">
-                    <el-form-item label="璇婃柇鍚嶇О" prop="name">
-                      <el-input
-                        v-model="form.leavediagname"
-                        placeholder="璇疯緭鍏ヨ瘖鏂�"
-                        maxlength="50"
-                      ></el-input> </el-form-item
-                  ></el-col>
-                </el-row>
-                <el-row :gutter="20">
-                  <el-col :span="24">
-                    <el-form-item label="鍑虹敓鍦�" prop="birthplace">
-                      <el-input
-                        v-model="userform.birthplace"
-                        placeholder="鍥姐�佺渷銆佸湴甯傘�佸尯鍘裤�佽閬撶瓑璇︾粏淇℃伅"
-                        maxlength="50"
-                      /> </el-form-item
-                  ></el-col>
-                </el-row>
-                <el-row :gutter="20">
-                  <el-col :span="24"
-                    ><el-form-item label="灞呬綇鍦�" prop="placeOfResidence">
-                      <el-input
-                        v-model="userform.placeOfResidence"
-                        placeholder="鍥姐�佺渷銆佸湴甯傘�佸尯鍘裤�佽閬撶瓑璇︾粏淇℃伅"
-                        maxlength="50"
-                      /> </el-form-item
-                  ></el-col>
-                </el-row>
-              </el-form>
-            </div>
+              <el-row :gutter="20">
+                <el-col :span="12">
+                  <el-form-item label="鑱旂郴鏂瑰紡" prop="telcode">
+                    <el-input
+                      v-model="userform.telcode"
+                      placeholder="璇疯緭鍏ヨ仈绯绘柟寮�"
+                      maxlength="20"
+                    />
+                  </el-form-item>
+                </el-col>
+                <el-col :span="12">
+                  <el-form-item label="浜插睘鑱旂郴鏂瑰紡" prop="relativetelcode">
+                    <el-input
+                      v-model="userform.relativetelcode"
+                      placeholder="璇疯緭鍏ヤ翰灞炶仈绯绘柟寮�"
+                      maxlength="20"
+                    ></el-input>
+                  </el-form-item>
+                </el-col>
+              </el-row>
+              <el-row :gutter="20">
+                <el-col :span="24">
+                  <el-form-item label="璇婃柇鍚嶇О" prop="leavediagname">
+                    <el-input
+                      v-model="form.leavediagname"
+                      placeholder="璇疯緭鍏ヨ瘖鏂�"
+                      maxlength="50"
+                    ></el-input>
+                  </el-form-item>
+                </el-col>
+              </el-row>
+              <el-row :gutter="20">
+                <el-col :span="24">
+                  <el-form-item label="鍑虹敓鍦�" prop="birthplace">
+                    <el-input
+                      v-model="userform.birthplace"
+                      placeholder="鍥姐�佺渷銆佸湴甯傘�佸尯鍘裤�佽閬撶瓑璇︾粏淇℃伅"
+                      maxlength="50"
+                    />
+                  </el-form-item>
+                </el-col>
+              </el-row>
+              <el-row :gutter="20">
+                <el-col :span="24">
+                  <el-form-item label="灞呬綇鍦�" prop="placeOfResidence">
+                    <el-input
+                      v-model="userform.placeOfResidence"
+                      placeholder="鍥姐�佺渷銆佸湴甯傘�佸尯鍘裤�佽閬撶瓑璇︾粏淇℃伅"
+                      maxlength="50"
+                    />
+                  </el-form-item>
+                </el-col>
+              </el-row>
+            </el-form>
           </div>
         </div>
       </div>
@@ -990,20 +1075,20 @@
                 align="right"
                 v-model="form.date1"
                 class="custom-disabled"
-                value-format="yyyy-MM-dd"
+                value-format="yyyy-MM-dd hh:mm:ss"
                 @change="checkFollowupDate"
               ></el-date-picker>
             </el-form-item>
           </el-col>
         </el-row>
-        <el-form-item label="闅忚鏂瑰紡" prop="resource">
+        <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-form-item label="闅忚璁板綍" :required="form.resource == '2'">
           <el-input type="textarea" v-model="form.remark"></el-input>
         </el-form-item>
       </el-form>
@@ -1040,6 +1125,7 @@
   serviceSubtaskDetailedit,
   serviceSubtaskDetailadd,
   updatePersonVoices,
+  savequestiondetail,
   addPersonVoices,
   query360PatInfo,
   sendMsg,
@@ -1137,11 +1223,16 @@
       userid: "",
       currentPhoneNumber: "",
       callType: "", // 鐢ㄤ簬鍖哄垎鏄摢涓數璇�
+      isSipRegistering: true, // SIP娉ㄥ唽鐘舵��
       // 宸叉湁鏁版嵁...
+      customCallStatus: "", // 鐢ㄤ簬瀛樺偍鑷畾涔夌姸鎬佹枃鏈�
       callStatus: "idle", // idle, calling, connected, ended, failed
       isEndingCall: false,
       CaldialogVisible: false,
       currentCall: null, // 褰撳墠閫氳瘽瀵硅薄
+      // 鏂板鍔熻兘鏁版嵁
+      showPatientInfo: true,
+      showContinuationCareBtn: false, // 鎺у埗寤剁画鎶ょ悊鎸夐挳鏄剧ず
       // 璺敱鐩戝惉鐩稿叧
       routeWatcher: null,
       lastRoutePath: this.$route.path,
@@ -1177,8 +1268,12 @@
           value: "5",
         },
         {
-          label: "鍏朵粬鎯呭喌涓嶅疁闅忚",
+          label: "涓嶅疁闅忚琚繃婊�",
           value: "6",
+        },
+        {
+          label: "鍏朵粬",
+          value: "7",
         },
       ],
       tableDatatop: [], //棰樼洰琛�
@@ -1353,6 +1448,7 @@
           label: "涓�骞村悗",
         },
       ],
+      statusTimer: null,
       userform: {},
       smsDialogVisible: false, // 鎺у埗鐭俊瀵硅瘽妗嗘樉绀�
       smsContent: "", // 瀛樺偍鐭俊鍐呭
@@ -1369,9 +1465,18 @@
       patid: null,
     };
   },
-
+  // 鍦ㄧ粍浠朵腑娣诲姞閿�姣佸墠鐨勬竻鐞�
+  beforeUnmount() {
+    if (this.statusTimer) {
+      clearTimeout(this.statusTimer);
+      this.statusTimer = null;
+    }
+  },
   computed: {
     callStatusText() {
+      if (this.customCallStatus) {
+        return this.customCallStatus;
+      }
       const statusMap = {
         idle: "鍑嗗鍛煎彨",
         calling: `姝e湪鍛煎彨 ${this.currentPhoneNumber}...`,
@@ -1402,11 +1507,90 @@
     this.visitCount = this.$route.query.visitCount;
     this.serviceType = this.$route.query.serviceType;
     this.orgname = localStorage.getItem("orgname");
+    if (this.orgname == "鐪佺珛鍚屽痉缈犺嫅闄㈠尯") {
+      this.showContinuationCareBtn = true;
+    }
 
+    if (this.orgname == "缂欎簯鍘夸腑鍖诲尰闄�") {
+      this.options = [
+        {
+          value: "鍗婁釜鏈堝悗",
+          label: "鍗婁釜鏈堝悗",
+        },
+        {
+          value: "涓�涓湀鍚�",
+          label: "涓�涓湀鍚�",
+        },
+        {
+          value: "涓や釜鏈堝悗",
+          label: "涓や釜鏈堝悗",
+        },
+        {
+          value: "涓変釜鏈堝悗",
+          label: "涓変釜鏈堝悗",
+        },
+        {
+          value: "鍏釜鏈堝悗",
+          label: "鍏釜鏈堝悗",
+        },
+        {
+          value: "12涓湀鍚�",
+          label: "12涓湀鍚�",
+        },
+      ];
+    }
     this.getTaskservelist();
   },
-
+  mounted() {
+    // 鐩戝惉瀛愮粍浠剁殑sipStatus灞炴�у彉鍖�
+    if (this.$refs.callButton) {
+      this.$watch(
+        () => this.$refs.callButton.sipStatus,
+        (newStatus) => {
+          if (this.statusTimer) {
+            clearTimeout(this.statusTimer);
+            this.statusTimer = null;
+          }
+          if (newStatus === "宸叉敞鍐�") {
+            this.statusTimer = setTimeout(() => {
+              this.isSipRegistering = false;
+              this.customCallStatus = ""; // 娉ㄥ唽鎴愬姛鍚庢竻绌鸿嚜瀹氫箟鎻愮ず
+              console.log("SIP娉ㄥ唽鎴愬姛锛岀姸鎬佸凡鏇存柊");
+            }, 2000);
+            this.isSipRegistering = false;
+          } else if (newStatus === "娉ㄥ唽澶辫触" || newStatus === "鏈繛鎺�") {
+            this.isSipRegistering = true;
+            this.customCallStatus = "鍛煎彨涓柇锛岃祫婧愰噸鏂板姞杞戒腑璇风◢绛�3s閲嶆柊銆�";
+          }
+        },
+        { immediate: true } // 绔嬪嵆鎵ц涓�娆′互鑾峰彇鍒濆鍊�
+      );
+    }
+  },
   methods: {
+    // 鑾峰彇涓婚鏍峰紡绫�
+    getTopicClass(item) {
+      console.log(item.isabnormal, "getTopicClass");
+
+      // 鏍规嵁鐘舵�佸�艰繑鍥炲搴旂殑鏍峰紡绫�
+      if (item.isabnormal == 1) {
+        return "scriptTopic-isabnormal"; // 寮傚父 - 绾㈣壊
+      } else if (item.isabnormal == 2) {
+        return "scriptTopic-warning"; // 璀﹀憡 - 榛勮壊
+      } else {
+        return "scriptTopic-dev"; // 姝e父 - 榛樿鏍峰紡
+      }
+    },
+
+    // 鑾峰彇閫夐」鏍峰紡绫�
+    getOptionClass(items) {
+      if (items.isabnormal == 1) {
+        return "red-star"; // 寮傚父 - 绾㈣壊鏄熷彿
+      } else if (items.isabnormal == 2) {
+        return "yellow-star"; // 璀﹀憡 - 榛勮壊鏄熷彿
+      }
+      return ""; // 姝e父 - 鏃犵壒娈婃牱寮�
+    },
     // 鑾峰彇闂嵎鏁版嵁
     getsearchrResults(id) {
       getsearchrResults({
@@ -1417,16 +1601,16 @@
       }).then((res) => {
         if (res.code === 200) {
           // 閽堝鍐嶆闅忚鏈嶅姟杩涜鍒犻櫎缁撴灉璧嬪��
-          if (this.again && res.data.upScriptResult) {
-            res.data.upScriptResult.forEach((itemA) => {
-              const itemB = res.data.scriptResult.find(
-                (item) => item.scriptContent === itemA.scriptContent
-              );
-              if (itemB) {
-                itemB.scriptResult = itemA.scriptResult;
-              }
-            });
-          }
+          // if (this.again && res.data.upScriptResult) {
+          //   res.data.upScriptResult.forEach((itemA) => {
+          //     const itemB = res.data.scriptResult.find(
+          //       (item) => item.scriptContent === itemA.scriptContent
+          //     );
+          //     if (itemB) {
+          //       itemB.scriptResult = itemA.scriptResult;
+          //     }
+          //   });
+          // }
           this.tableDatatop = res.data.scriptResult;
 
           this.tableDatatop.forEach((item) => {
@@ -1496,15 +1680,17 @@
       // 鏍规嵁閫夋嫨鐨勯殢璁挎柟寮忚绠楅殢璁挎棩鏈�
       if (value.includes("涓冨ぉ鍚�")) {
         followupDate.setDate(dischargeDate.getDate() + 7);
-      } else if (value.includes("15澶╁悗")) {
+      } else if (value.includes("15澶╁悗") || value.includes("鍗婁釜鏈堝悗")) {
         followupDate.setDate(dischargeDate.getDate() + 15);
       } else if (value.includes("涓�涓湀鍚�")) {
         followupDate.setMonth(dischargeDate.getMonth() + 1);
+      } else if (value.includes("涓や釜鏈堝悗")) {
+        followupDate.setMonth(dischargeDate.getMonth() + 2);
       } else if (value.includes("涓変釜鏈堝悗")) {
         followupDate.setMonth(dischargeDate.getMonth() + 3);
       } else if (value.includes("鍏釜鏈堝悗")) {
         followupDate.setMonth(dischargeDate.getMonth() + 6);
-      } else if (value.includes("涓�骞村悗")) {
+      } else if (value.includes("涓�骞村悗") || value.includes("12涓湀鍚�")) {
         followupDate.setFullYear(dischargeDate.getFullYear() + 1);
       }
 
@@ -1523,8 +1709,6 @@
     },
     // 妫�鏌ラ殢璁挎棩鏈熸槸鍚︽湁鏁�
     checkFollowupDate(date) {
-      console.log(date);
-
       if (!date) {
         this.form.date1 = "";
         this.$refs.zcform.clearValidate(["date1"]);
@@ -1576,11 +1760,13 @@
         if (res.code == 200) {
           this.tableDatatop = res.data.ivrTaskTemplateScriptVOList;
           this.tableDatatop.forEach((item) => {
+            item.scriptID = item.id;
             item.id = null;
             // 绫诲瀷鍒ゆ柇璧嬪��
             if (item.ivrTaskScriptTargetoptionList) {
               item.targetvalue = 1;
               item.questiontext = item.scriptContent;
+
               item.targetvalue = item.ivrTaskScriptTargetoptionList
                 .map((obj) => obj.targetvalue)
                 .join("&");
@@ -1626,32 +1812,41 @@
           scriptid: item.id,
           excep: excep,
           questiontext: item.scriptContent,
+          categoryid: item.categoryid,
           answerps: item.answerps || null, // 娣诲姞闄勫姞淇℃伅
         };
         if (item.scriptType == 2 && item.scriptResult[0]) {
           obj.asrtext = item.scriptResult.join("&");
+          obj.ivrtext = item.scriptResult.join("&");
         } else if (item.scriptType != 2 && item.scriptResult) {
           obj.asrtext = item.scriptResult;
+          obj.ivrtext = item.scriptResult;
         }
 
-        if (item.isoption == 3) {
-          promises.push(serviceSubtaskDetailedit(obj));
-        } else {
-          promises.push(serviceSubtaskDetailadd(obj));
-        }
+        // if (item.isoption == 3) {
+        //   promises.push(serviceSubtaskDetailedit(obj));
+        // } else {
+        //   promises.push(serviceSubtaskDetailadd(obj));
+        // }
       });
-
-      // 浣跨敤 Promise.all 绛夊緟鎵�鏈夊紓姝ユ搷浣滃畬鎴�
-      Promise.all(promises)
-        .then((results) => {
-          // 鎵�鏈夊紓姝ユ搷浣滄垚鍔熷畬鎴愬悗鐨勯�昏緫
-          results.forEach((res) => {
-            if (res.code !== 200) {
-              this.$modal.error("淇敼澶辫触");
-            }
-          });
+      console.log(this.tableDatatop);
+      let obj = {
+        svyTaskTemplateScriptVOS: this.tableDatatop, // 鎻愪氦澶勭悊鍚庣殑鍓湰
+        param1: this.taskid,
+        param2: this.patid,
+        param6: this.id,
+        type: 2,
+      };
+      savequestiondetail(obj).then((res) => {
+        if (res.code == 200) {
+          this.$modal.msgSuccess("鏈嶅姟淇濆瓨鎴愬姛");
           this.Editsingletasksonyic(6);
+          const orgName = localStorage.getItem("orgname");
 
+          if (this.form.isVisitAgain != 1 || orgName == "涓芥按甯備腑鍖婚櫌") {
+            this.Torouter();
+            return;
+          }
           this.$modal
             .confirm(
               '浠诲姟淇濆瓨鎴愬姛鏄惁閽堝鎮h�咃細"' +
@@ -1673,33 +1868,78 @@
               this.dialogFormVisible = true;
             })
             .catch(() => {
-              if (this.form.serviceType == 13) {
-                if (this.visitCount != 1) {
-                  this.$router.push({
-                    path: "/logisticsservice/zbAgain",
-                  });
-                } else {
-                  this.$router.push({
-                    path: "/logisticsservice/record",
-                  });
-                }
-              } else if (this.form.serviceType == 2) {
-                if (this.visitCount != 1) {
-                  this.$router.push({
-                    path: "/logisticsservice/again",
-                  });
-                } else {
-                  this.$router.push({
-                    path: "/followvisit/discharge",
-                  });
-                }
-              }
+              this.Torouter();
             });
-        })
-        .catch((error) => {
-          // 濡傛灉鏈変换浣曚竴涓紓姝ユ搷浣滃け璐ワ紝浼氳繘鍏ヨ繖閲�
-          console.error("鍙戠敓閿欒锛�", error);
-        });
+        }
+      });
+      // 浣跨敤 Promise.all 绛夊緟鎵�鏈夊紓姝ユ搷浣滃畬鎴�
+      // Promise.all(promises)
+      //   .then((results) => {
+      //     // 鎵�鏈夊紓姝ユ搷浣滄垚鍔熷畬鎴愬悗鐨勯�昏緫
+      //     results.forEach((res) => {
+      //       if (res.code !== 200) {
+      //         this.$modal.error("淇敼澶辫触");
+      //       }
+      //     });
+      //     this.Editsingletasksonyic(6);
+      //     const orgName = localStorage.getItem("orgname");
+      //     console.log(orgName, "orgName");
+
+      //     if (this.form.isVisitAgain != 1 || orgName == "涓芥按甯備腑鍖婚櫌") {
+      //       this.Torouter();
+      //       return;
+      //     }
+      //     this.$modal
+      //       .confirm(
+      //         '浠诲姟淇濆瓨鎴愬姛鏄惁閽堝鎮h�咃細"' +
+      //           this.userform.name +
+      //           '"鍐嶆闅忚锛�',
+      //         "纭",
+      //         {
+      //           confirmButtonText: "纭畾",
+      //           cancelButtonText: "鍙栨秷",
+      //           showCancelButton: true,
+      //           dangerouslyUseHTMLString: true,
+      //           confirmButtonClass: "custom-confirm-button", // 鑷畾涔夌‘璁ゆ寜閽殑绫诲悕
+      //           cancelButtonClass: "custom-cancel-button", // 鑷畾涔夊彇娑堟寜閽殑绫诲悕
+      //         }
+      //       )
+      //       .then(() => {
+      //         document.querySelector("#app").scrollTo(0, 0);
+      //         this.formtidy();
+      //         this.dialogFormVisible = true;
+      //       })
+      //       .catch(() => {
+      //         this.Torouter();
+      //       });
+      //   })
+      //   .catch((error) => {
+      //     // 濡傛灉鏈変换浣曚竴涓紓姝ユ搷浣滃け璐ワ紝浼氳繘鍏ヨ繖閲�
+      //     console.error("鍙戠敓閿欒锛�", error);
+      //   });
+    },
+    Torouter() {
+      if (this.form.serviceType == 13) {
+        if (this.visitCount != 1) {
+          this.$router.push({
+            path: "/logisticsservice/zbAgain",
+          });
+        } else {
+          this.$router.push({
+            path: "/logisticsservice/record",
+          });
+        }
+      } else if (this.form.serviceType == 2) {
+        if (this.visitCount != 1) {
+          this.$router.push({
+            path: "/logisticsservice/again",
+          });
+        } else {
+          this.$router.push({
+            path: "/followvisit/discharge",
+          });
+        }
+      }
     },
     // 鐢佃瘽============================
     // 楠岃瘉鐢佃瘽鍙风爜鏍煎紡骞惰繑鍥為敊璇俊鎭�
@@ -1737,27 +1977,39 @@
     isValidPhone(phone) {
       return this.validatePhoneNumber(phone).isValid;
     },
-    handleCall(phone, type) {
-      if (!this.isValidPhone(phone)) {
+    handleCall(phone, type, dh) {
+      if (!this.isValidPhone(phone) && !dh) {
         this.$message.error("璇疯緭鍏ユ纭殑鎵嬫満鍙风爜");
         return;
       }
+      // 妫�鏌IP鏄惁宸叉敞鍐�
+
       this.currentPhoneNumber = phone;
-      // 鍛煎彨鍒ゆ柇
+      // 鏄惁鏅畞鍛煎彨
       if (this.orgname == "鏅畞鐣叉棌鑷不鍘夸汉姘戝尰闄�") {
         this.CaldialogVisible = true;
         return;
       }
-
+      // 涓嬫柟鏄腑鍖婚櫌鍛煎彨
+      if (this.isSipRegistering) {
+        this.$message.warning("绯荤粺姝e湪鍒濆鍖栵紝璇风◢鍊�...");
+        return;
+      }
       this.callType = type;
       this.callStatus = "calling";
 
       this.$nextTick(() => {
         this.$refs.callButton.startCall();
 
-        // 鐩戝惉閫氳瘽鐘舵�佸彉鍖�
         this.$refs.callButton.$on("call-status-change", (status) => {
           this.handleCallStatusChange(status);
+          // 鐩戝惉娉ㄥ唽鐘舵�佸彉鍖�
+          if (status.type === "registered") {
+            this.isSipRegistering = false;
+          }
+          if (status.type === "failed" || status.type === "disconnected") {
+            this.isSipRegistering = true;
+          }
         });
       });
     },
@@ -1796,7 +2048,6 @@
     },
     yuyingetdetail() {
       const dataToSubmit = JSON.parse(JSON.stringify(this.tableDatatop));
-      console.log(dataToSubmit, "dataToSubmit");
       dataToSubmit.forEach((item, index) => {
         // 瀵规嫹璐濈殑鏁版嵁杩涜鎿嶄綔锛屼笉褰卞搷鍘熷鐨� scriptResult 鏁扮粍
         item.scriptResult = item.scriptResult.join("&");
@@ -1804,6 +2055,7 @@
         item.subId = this.id;
         item.taskid = this.taskid;
         item.asrtext = item.matchedtext;
+        item.ivrtext = item.matchedtext;
         if (!item.id) {
           item.isoperation = 1;
         }
@@ -1812,13 +2064,20 @@
       });
 
       let obj = {
-        serviceSubtaskDetailList: dataToSubmit, // 鎻愪氦澶勭悊鍚庣殑鍓湰
+        ivrTaskTemplateScriptVOList: dataToSubmit, // 鎻愪氦澶勭悊鍚庣殑鍓湰
         param1: this.taskid,
         param2: this.patid,
-        subId: this.id,
+        param6: this.id,
+        type: 1,
       };
+      const orgName = localStorage.getItem("orgname");
+      console.log(orgName, "orgName");
 
-      addPersonVoices(obj).then((res) => {
+      if (this.form.isVisitAgain != 1 || orgName == "涓芥按甯備腑鍖婚櫌") {
+        this.Torouter();
+        return;
+      }
+      savequestiondetail(obj).then((res) => {
         if (res.code == 200) {
           this.$modal.msgSuccess("鏈嶅姟淇濆瓨鎴愬姛");
           this.$modal
@@ -1842,27 +2101,7 @@
               this.dialogFormVisible = true;
             })
             .catch(() => {
-              if (this.form.serviceType == 13) {
-                if (this.visitCount != 1) {
-                  this.$router.push({
-                    path: "/logisticsservice/zbAgain",
-                  });
-                } else {
-                  this.$router.push({
-                    path: "/logisticsservice/record",
-                  });
-                }
-              } else if (form.serviceType == 2) {
-                if (this.visitCount != 1) {
-                  this.$router.push({
-                    path: "/followvisit/again",
-                  });
-                } else {
-                  this.$router.push({
-                    path: "/followvisit/discharge",
-                  });
-                }
-              }
+              this.Torouter();
             });
         }
       });
@@ -1870,7 +2109,7 @@
     // 鍐嶆闅忚鏁版嵁鏇存浛
     formtidy() {
       this.form.visitType2 = this.form.visitType;
-      this.form.date2 = this.form.longSendTime;
+      this.form.date2 = this.form.visitTime;
       // this.form.date1 = this.setCurrentDate();
       this.form.remark2 = this.form.remark;
     },
@@ -1899,12 +2138,11 @@
           this.form = res.rows[0].serviceSubtaskList.find(
             (item) => item.id == this.id
           );
-          console.log(this.form, "serviceType");
 
           this.logsheetlist = res.rows[0].serviceSubtaskList;
           this.templateid = this.form.templateid;
           this.selectedTag = this.form.excep;
-          const targetDate = new Date(this.form.longSendTime); // 鐩爣鏃ユ湡
+          const targetDate = new Date(this.form.visitTime); // 鐩爣鏃ユ湡
           const now = new Date(); // 褰撳墠鏃堕棿
           if (now < targetDate && this.form.sendstate == 2) {
             this.$confirm("褰撳墠鏈嶅姟鏈埌鍙戦�佹椂闂磋璋ㄦ厧淇敼", "鎻愮ず", {
@@ -2033,10 +2271,38 @@
 
     // 璋冭捣鍐嶆鍙戦��
     sendAgain() {
-      document.querySelector("#app").scrollTo(0, 0);
-      // scrollTo(0, 0)
-      this.formtidy();
-      this.dialogFormVisible = true;
+      getTaskservelist({
+        patid: this.patid,
+        visitCount: 2,
+        leaveldeptcodes: [this.form.deptcode],
+      }).then((res) => {
+        if (res.rows[0].serviceSubtaskList.length) {
+          if (
+            res.rows[0].serviceSubtaskList[0].sendstate != 5 &&
+            res.rows[0].serviceSubtaskList[0].sendstate != 6
+          ) {
+            this.$modal
+              .confirm(
+                '鏈偅鑰呭湪"' +
+                  res.rows[0].serviceSubtaskList[0].deptname +
+                  '"绉戝涓嬪凡鏈夊啀娆¢殢璁挎湇鍔¤繘琛屼腑鏄惁缁х画鍒涘缓锛�'
+              )
+              .then(() => {
+                document.querySelector("#app").scrollTo(0, 0);
+                this.formtidy();
+                this.dialogFormVisible = true;
+              });
+          } else {
+            document.querySelector("#app").scrollTo(0, 0);
+            this.formtidy();
+            this.dialogFormVisible = true;
+          }
+        } else {
+          document.querySelector("#app").scrollTo(0, 0);
+          this.formtidy();
+          this.dialogFormVisible = true;
+        }
+      });
     },
     // 鏌ョ湅璇︽儏
     Seedetails(row) {
@@ -2093,7 +2359,7 @@
       if (questionItem.matchedtext == optionValue) {
         this.$set(questionItem, "matchedtext", "");
         // 鍚屾椂閲嶇疆涓庨�夐」鐩稿叧鐨勭姸鎬�
-        questionItem.isabnormal = false;
+        // questionItem.isabnormal = false;
         questionItem.showAppendInput = false;
         // 娉ㄦ剰锛氬彇娑堥�変腑鏃讹紝鎴戜滑閫氬父涓嶅笇鏈涜Е鍙戦鐩烦杞�昏緫锛屾墍浠ョ洿鎺ヨ繑鍥�
         // 濡傛灉闇�瑕侊紝鍙互鍦ㄨ繖閲屾坊鍔犲彇娑堥�変腑鍚庣殑鐗瑰畾閫昏緫锛屼緥濡傞噸缃鐩簭鍒�
@@ -2109,7 +2375,7 @@
       if (questionItem.scriptResult === optionValue) {
         questionItem.scriptResult = ""; // 娓呯┖閫変腑鍊�
         // 鍚屾椂閲嶇疆涓庨�夐」鐩稿叧鐨勭姸鎬�
-        questionItem.isabnormal = false;
+        // questionItem.isabnormal = false;
         questionItem.showAppendInput = false;
         // 娉ㄦ剰锛氬彇娑堥�変腑鏃讹紝鎴戜滑閫氬父涓嶅笇鏈涜Е鍙戦鐩烦杞�昏緫锛屾墍浠ョ洿鎺ヨ繑鍥�
         // 濡傛灉闇�瑕侊紝鍙互鍦ㄨ繖閲屾坊鍔犲彇娑堥�変腑鍚庣殑鐗瑰畾閫昏緫锛屼緥濡傞噸缃鐩簭鍒�
@@ -2137,7 +2403,7 @@
 
       // 澶勭悊寮傚父鐘舵�侀珮浜�
       this.tableDatatop[questionIndex].isabnormal =
-        !!selectedOptionObj.isabnormal;
+        selectedOptionObj.isabnormal;
       // 澶勭悊闄勫姞杈撳叆妗嗘樉绀�
 
       this.tableDatatop[questionIndex].showAppendInput =
@@ -2213,6 +2479,7 @@
           hiddenByEnd: index === questionIndex + 1 ? false : item.hiddenByEnd,
         }));
       }
+      2;
 
       this.$forceUpdate();
     },
@@ -2223,9 +2490,7 @@
         );
         if (obj) {
           if (obj.isabnormal) {
-            this.tableDatatop[index].isabnormal = true;
-          } else {
-            this.tableDatatop[index].isabnormal = false;
+            this.tableDatatop[index].isabnormal = obj.isabnormal;
           }
           this.$forceUpdate();
         }
@@ -2239,14 +2504,20 @@
             this.$message.error("闅忚鏃堕棿涓嶈兘灏忎簬褰撳墠鏃堕棿");
             return false;
           }
+          if (this.form.resource == "2" && !this.form.remark) {
+            this.$message.error("褰撳墠閫夋嫨涓洪殢璁夸腑蹇冮殢璁块渶杈撳叆闅忚璁板綍");
+            return false;
+          }
           this.form.remark =
             this.form.remark + "銆�" + this.getCurrentTime() + "銆�";
           let form = structuredClone(this.form);
-          form.longSendTime = this.formatTime(form.date1);
+          form.visitTime = this.parseTime(form.date1);
           form.finishtime = "";
           if (form.resource) {
             if (form.resource == 2) {
-              form.visitDeptCode = localStorage.getItem("deptCode");
+              form.visitDeptCode = localStorage.getItem("deptCode")
+                ? localStorage.getItem("deptCode")
+                : form.deptcode;
               form.visitDeptName = "闅忚涓績";
             } else {
               form.visitDeptCode = form.deptcode;
@@ -2347,6 +2618,34 @@
       // 鍒锋柊鏁版嵁
       this.getTaskservelist();
     },
+    // 寤剁画鎶ょ悊
+    handleContinuationCare() {
+      if (this.form.continueFlag != 2) {
+        this.$modal.confirm("鏄惁涓烘湰娆℃湇鍔″垱寤哄欢缁姢鐞嗭紵").then(() => {
+          this.$router.push({
+            path: "/followvisit/ContinueFordetails/",
+            query: {
+              taskid: this.taskid,
+              patid: this.patid,
+              id: this.id,
+              Voicetype: this.Voicetype,
+              visitCount: this.visitCount,
+            },
+          });
+        });
+      } else {
+        this.$router.push({
+          path: "/followvisit/ContinueFordetails/",
+          query: {
+            taskid: this.taskid,
+            patid: this.patid,
+            id: this.id,
+            Voicetype: this.Voicetype,
+            visitCount: this.visitCount,
+          },
+        });
+      }
+    },
   },
   // deactivated() {
   //   console.log(11);
@@ -2382,15 +2681,18 @@
   .manual-action {
     flex: 1;
     min-width: 0;
-    height: 100%; /* 纭繚楂樺害缁ф壙 */
+    height: 100%;
+    /* 纭繚楂樺害缁ф壙 */
   }
 
   .call-action {
     width: 60%;
     min-width: 0;
-    height: 100%; /* 纭繚楂樺害缁ф壙 */
+    height: 100%;
+    /* 纭繚楂樺害缁ф壙 */
   }
 }
+
 .numeric-input {
   position: relative;
 }
@@ -2407,6 +2709,7 @@
   padding: 2px 6px;
   border-radius: 4px;
 }
+
 .call-container {
   padding: 20px;
   background: #fff;
@@ -2436,11 +2739,13 @@
     margin-top: 20px;
   }
 }
+
 .merge-controls {
   background: #f5f7fa;
   border-radius: 4px;
   margin-left: 20px;
 }
+
 .Followuserinfo {
   margin: 10px 10px 0 10px;
   align-items: center;
@@ -2474,8 +2779,10 @@
   background: #ffff;
   border: 1px solid #dcdfe6;
   box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.12), 0 0 6px 0 rgba(0, 0, 0, 0.04);
-  height: 100%; /* 纭繚楂樺害缁ф壙 */
-  min-height: 880px; /* 鏈�灏忛珮搴︿笌闅忚鍐呭涓�鑷� */
+  height: 100%;
+  /* 纭繚楂樺害缁ф壙 */
+  min-height: 880px;
+  /* 鏈�灏忛珮搴︿笌闅忚鍐呭涓�鑷� */
   display: flex;
   flex-direction: column;
 
@@ -2495,11 +2802,15 @@
 
   .el-form {
     flex: 1;
-    overflow-y: auto; /* 鍐呭瓒呰繃楂樺害鏃舵樉绀烘粴鍔ㄦ潯 */
-    max-height: calc(880px - 60px); /* 鍑忓幓padding */
-    padding-right: 10px; /* 闃叉婊氬姩鏉¢伄鎸″唴瀹� */
+    overflow-y: auto;
+    /* 鍐呭瓒呰繃楂樺害鏃舵樉绀烘粴鍔ㄦ潯 */
+    max-height: calc(880px - 60px);
+    /* 鍑忓幓padding */
+    padding-right: 10px;
+    /* 闃叉婊氬姩鏉¢伄鎸″唴瀹� */
   }
 }
+
 .append-input-container {
   margin-top: 15px;
   padding: 10px;
@@ -2507,6 +2818,7 @@
   border-radius: 4px;
   border: 1px solid #dcdfe6;
 }
+
 .borderdiv {
   min-height: 60vh;
   font-size: 20px;
@@ -2545,14 +2857,111 @@
     }
   }
 }
+
 .topic-dev[inert] {
   opacity: 0.5;
   pointer-events: none;
 }
+/* 鎸傛柇瀹瑰櫒鏍峰紡 */
+.hangup-container {
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  gap: 10px;
+  margin: 15px 0;
+}
+
+.hangup-btn {
+  width: 120px;
+  height: 40px;
+  font-size: 14px;
+  border-radius: 20px;
+  box-shadow: 0 2px 8px rgba(244, 67, 54, 0.3);
+  transition: all 0.3s ease;
+}
+
+.hangup-btn:hover:not(:disabled) {
+  transform: translateY(-2px);
+  box-shadow: 0 4px 12px rgba(244, 67, 54, 0.4);
+}
+
+/* 閫氳瘽璁℃椂鍣� */
+.call-timer {
+  font-size: 12px;
+  color: #666;
+  background: #f5f5f5;
+  padding: 4px 12px;
+  border-radius: 12px;
+  font-family: "Courier New", monospace;
+}
+
+/* 鐘舵�佹彁绀哄鍣� */
+.call-status-container {
+  margin: 10px 0;
+}
+
+.status-alert {
+  border-radius: 8px;
+  transition: all 0.3s ease;
+}
+
+.status-alert.status-calling {
+  border-left: 4px solid #e6a23c;
+}
+
+.status-alert.status-connected {
+  border-left: 4px solid #67c23a;
+  animation: pulse 2s infinite;
+}
+
+.status-alert.status-ended {
+  border-left: 4px solid #909399;
+}
+
+/* SIP娉ㄥ唽鎻愮ず */
+.sip-registering {
+  margin: 10px 0;
+}
+
+.registering-alert {
+  border-radius: 8px;
+  background-color: #f4f4f5;
+  border-left: 4px solid #909399;
+}
+
+/* 鍔ㄧ敾鏁堟灉 */
+@keyframes pulse {
+  0% {
+    opacity: 1;
+  }
+  50% {
+    opacity: 0.7;
+  }
+  100% {
+    opacity: 1;
+  }
+}
+
+/* 鍝嶅簲寮忚璁� */
+@media (max-width: 768px) {
+  .hangup-container {
+    margin: 10px 0;
+  }
+
+  .hangup-btn {
+    width: 100%;
+    max-width: 200px;
+  }
+
+  .status-alert {
+    font-size: 12px;
+  }
+}
 .CONTENT {
   padding: 10px;
   height: 100%;
-  min-height: 738px; /* 璁剧疆鏈�灏忛珮搴� */
+  min-height: 738px;
+  /* 璁剧疆鏈�灏忛珮搴� */
 
   .title {
     font-size: 22px;
@@ -2567,8 +2976,10 @@
   padding: 30px;
   border: 1px solid #dcdfe6;
   box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.12), 0 0 6px 0 rgba(0, 0, 0, 0.04);
-  max-height: 618px; /* 璁剧疆鏈�澶ч珮搴� */
-  overflow-y: auto; /* 鍐呭瓒呰繃楂樺害鏃舵樉绀烘粴鍔ㄦ潯 */
+  max-height: 716px;
+  /* 璁剧疆鏈�澶ч珮搴� */
+  overflow-y: auto;
+  /* 鍐呭瓒呰繃楂樺害鏃舵樉绀烘粴鍔ㄦ潯 */
 
   .topic-dev {
     margin-bottom: 25px;
@@ -2617,6 +3028,18 @@
   }
 }
 
+/* 寮傚父鐘舵�佹牱寮� - 绾㈣壊 (淇濇寔涓嶅彉) */
+.scriptTopic-isabnormal {
+  color: red;
+}
+
+/* 鏂板锛氳鍛婄姸鎬佹牱寮� - 榛勮壊 */
+.scriptTopic-warning {
+  color: #d4be00;
+  /* 鎮ㄦ寚瀹氱殑榛勮壊 */
+}
+
+/* 寮傚父閫夐」鏍峰紡 - 绾㈣壊鏄熷彿 (淇濇寔涓嶅彉) */
 .red-star {
   ::v-deep.el-radio__label {
     position: relative;
@@ -2630,25 +3053,45 @@
     right: -5px;
     top: 0;
   }
+}
 
-  ::v-deep.el-input-group__textarea {
-    white-space: pre-wrap;
-    word-break: break-all;
-  }
-
-  ::v-deep.el-checkbox__label {
+/* 鏂板锛氳鍛婇�夐」鏍峰紡 - 榛勮壊鏄熷彿 */
+.yellow-star {
+  ::v-deep.el-radio__label {
     position: relative;
     padding-right: 10px;
   }
 
-  ::v-deep.el-checkbox__label::after {
+  ::v-deep.el-radio__label::after {
     content: "*";
-    color: red;
+    color: #ffe202;
+    /* 榛勮壊鏄熷彿 */
     position: absolute;
     right: -5px;
     top: 0;
+    font-weight: bold;
   }
 }
+
+/* 鍏辩敤鏍峰紡淇濇寔涓嶅彉 */
+::v-deep.el-input-group__textarea {
+  white-space: pre-wrap;
+  word-break: break-all;
+}
+
+::v-deep.el-checkbox__label {
+  position: relative;
+  padding-right: 10px;
+}
+
+::v-deep.el-checkbox__label::after {
+  content: "*";
+  color: red;
+  position: absolute;
+  right: -5px;
+  top: 0;
+}
+
 .tag-selector-container {
   display: flex;
   align-items: center;
@@ -2685,9 +3128,11 @@
 .tag-normal {
   background-color: #7ff5e1;
 }
+
 .tag-abnormal {
   background-color: #f75c5c;
 }
+
 .tag-warning {
   background-color: #fbfb4a;
 }
@@ -2697,6 +3142,7 @@
   color: #909399;
   cursor: pointer;
 }
+
 ::v-deep.offside-value .el-radio__label {
   color: #fff;
 }
@@ -2746,6 +3192,7 @@
   color: #080808 !important;
   cursor: not-allowed;
 }
+
 /* 鍘熸湁鐨勬牱寮忎繚鎸佷笉鍙橈紝娣诲姞浠ヤ笅鍝嶅簲寮忎唬鐮� */
 
 .Followupdetailspage {
@@ -2757,7 +3204,8 @@
 
 .action-container {
   display: flex;
-  flex-direction: row; /* 榛樿妯悜鎺掑垪 */
+  flex-direction: row;
+  /* 榛樿妯悜鎺掑垪 */
   gap: 20px;
   margin: 0 10px 20px 10px;
 
@@ -2900,7 +3348,8 @@
 
 /* 纭繚鍐呭鍦ㄧ缉鏀炬椂淇濇寔鍙鎬� */
 .headline {
-  font-size: clamp(18px, 2vw, 24px); /* 浣跨敤clamp鍑芥暟纭繚瀛椾綋澶у皬鍦ㄥ悎鐞嗚寖鍥村唴 */
+  font-size: clamp(18px, 2vw, 24px);
+  /* 浣跨敤clamp鍑芥暟纭繚瀛椾綋澶у皬鍦ㄥ悎鐞嗚寖鍥村唴 */
 }
 
 /* 涓虹Щ鍔ㄨ澶囦紭鍖栨粴鍔ㄤ綋楠� */
@@ -2935,4 +3384,366 @@
     margin-bottom: 20px;
   }
 }
+/* 浜哄伐澶勭悊閮ㄥ垎鏍峰紡 */
+.manual-action {
+  flex: 1;
+  min-width: 0;
+  height: 100%;
+  overflow: hidden;
+
+  .Followuserinfos {
+    display: flex;
+    flex-direction: column;
+    gap: 20px;
+    padding: 20px;
+    background: #fff;
+    border-radius: 8px;
+    box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
+    height: 100%;
+    overflow-y: auto;
+  }
+}
+
+/* 澶撮儴鍖哄煙 */
+.section-header {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  padding-bottom: 15px;
+  border-bottom: 2px solid #f0f0f0;
+  margin-bottom: 20px;
+  flex-wrap: wrap;
+  gap: 15px;
+
+  h3 {
+    margin: 0;
+    color: #409eff;
+    font-size: 18px;
+    font-weight: 600;
+    display: flex;
+    align-items: center;
+    gap: 8px;
+
+    i {
+      font-size: 20px;
+    }
+  }
+
+  .header-actions {
+    display: flex;
+    align-items: center;
+    flex-wrap: wrap;
+    gap: 15px;
+
+    .action-group {
+      display: flex;
+      align-items: center;
+      gap: 10px;
+    }
+  }
+}
+
+/* 鍩虹鎿嶄綔鎸夐挳 */
+.basic-actions {
+  .el-button {
+    min-width: 100px;
+  }
+}
+
+/* 寮傚父鐘舵�侀�夋嫨鍣� */
+.tag-selector {
+  display: flex;
+  align-items: center;
+  gap: 10px;
+
+  .current-tag {
+    display: flex;
+    align-items: center;
+    gap: 8px;
+    padding: 6px 12px;
+    background: #f8f9fa;
+    border: 1px solid;
+    border-radius: 4px;
+    font-size: 12px;
+    transition: all 0.3s;
+
+    &:hover {
+      box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
+    }
+  }
+}
+
+.color-indicator {
+  width: 16px;
+  height: 16px;
+  border-radius: 3px;
+  margin-right: 8px;
+  display: inline-block;
+}
+
+.selected-indicator {
+  margin-left: 10px;
+  width: 20px;
+  height: 20px;
+}
+
+.tag-info-icon {
+  margin-left: 10px;
+  color: #909399;
+  cursor: pointer;
+  font-size: 16px;
+}
+
+/* 琛ㄥ崟鍖哄煙 */
+.form-content {
+  background: #f8f9fa;
+  border-radius: 8px;
+  padding: 20px;
+  margin-bottom: 20px;
+
+  .el-form {
+    .el-row {
+      margin: 0 -10px;
+    }
+
+    .el-col {
+      padding: 0 10px;
+    }
+  }
+}
+
+/* 閫氳瘽鎺у埗鍖哄煙 */
+.call-controls {
+  margin: 15px 0;
+
+  .hangup-container {
+    display: flex;
+    flex-direction: column;
+    align-items: center;
+    gap: 10px;
+    margin: 15px 0;
+  }
+
+  .hangup-btn {
+    width: 120px;
+    height: 40px;
+    font-size: 14px;
+    border-radius: 20px;
+    box-shadow: 0 2px 8px rgba(244, 67, 54, 0.3);
+    transition: all 0.3s ease;
+  }
+
+  .hangup-btn:hover:not(:disabled) {
+    transform: translateY(-2px);
+    box-shadow: 0 4px 12px rgba(244, 67, 54, 0.4);
+  }
+
+  .call-timer {
+    font-size: 12px;
+    color: #666;
+    background: #f5f5f5;
+    padding: 4px 12px;
+    border-radius: 12px;
+    font-family: "Courier New", monospace;
+  }
+
+  .call-status-container {
+    margin: 10px 0;
+  }
+
+  .status-alert {
+    border-radius: 8px;
+    transition: all 0.3s ease;
+  }
+
+  .status-alert.status-calling {
+    border-left: 4px solid #e6a23c;
+  }
+
+  .status-alert.status-connected {
+    border-left: 4px solid #67c23a;
+    animation: pulse 2s infinite;
+  }
+
+  .status-alert.status-ended {
+    border-left: 4px solid #909399;
+  }
+
+  .sip-registering {
+    margin: 10px 0;
+  }
+
+  .registering-alert {
+    border-radius: 8px;
+    background-color: #f4f4f5;
+    border-left: 4px solid #909399;
+  }
+}
+
+/* 澶勭悊鎰忚鎸夐挳缁� */
+.opinion-buttons {
+  display: flex;
+  flex-wrap: wrap;
+  gap: 10px;
+  align-items: center;
+
+  .el-button {
+    flex: 1;
+    min-width: 120px;
+  }
+}
+
+/* 鎮h�呮。妗堜俊鎭� */
+.detailed {
+  width: 100%;
+  border-radius: 8px;
+  padding: 20px;
+  margin-bottom: 20px;
+  background-color: #ddf0f8;
+  border: 1px solid #b3e0f2;
+
+  h3 {
+    margin: 0 0 20px 0;
+    color: #333;
+    font-size: 16px;
+    font-weight: 500;
+    display: flex;
+    align-items: center;
+    gap: 8px;
+
+    &:before {
+      content: "";
+      display: block;
+      width: 4px;
+      height: 16px;
+      background: #409eff;
+      border-radius: 2px;
+    }
+  }
+
+  .el-form {
+    .el-row {
+      margin: 0 -10px;
+    }
+
+    .el-col {
+      padding: 0 10px;
+      margin-bottom: 15px;
+    }
+  }
+}
+
+/* 鍔ㄧ敾鏁堟灉 */
+@keyframes pulse {
+  0% {
+    opacity: 1;
+  }
+  50% {
+    opacity: 0.7;
+  }
+  100% {
+    opacity: 1;
+  }
+}
+
+/* 鍝嶅簲寮忚璁� */
+@media screen and (max-width: 1200px) {
+  .section-header {
+    flex-direction: column;
+    align-items: flex-start;
+    gap: 15px;
+  }
+
+  .header-actions {
+    width: 100%;
+    justify-content: space-between;
+  }
+
+  .opinion-buttons {
+    .el-button {
+      min-width: calc(50% - 8px);
+    }
+  }
+}
+
+@media screen and (max-width: 768px) {
+  .Followuserinfos {
+    padding: 15px;
+  }
+
+  .form-content,
+  .detailed {
+    padding: 15px;
+  }
+
+  .header-actions {
+    flex-direction: column;
+    align-items: stretch;
+
+    .action-group {
+      flex-direction: column;
+      align-items: stretch;
+
+      .el-select {
+        width: 100%;
+        margin-right: 0;
+      }
+    }
+  }
+
+  .opinion-buttons {
+    flex-direction: column;
+
+    .el-button {
+      width: 100%;
+    }
+  }
+
+  .detailed {
+    .el-form {
+      .el-col {
+        width: 100%;
+      }
+    }
+  }
+}
+
+/* 婊氬姩鏉$編鍖� */
+.Followuserinfos {
+  &::-webkit-scrollbar {
+    width: 6px;
+  }
+
+  &::-webkit-scrollbar-track {
+    background: #f1f1f1;
+    border-radius: 3px;
+  }
+
+  &::-webkit-scrollbar-thumb {
+    background: #c1c1c1;
+    border-radius: 3px;
+
+    &:hover {
+      background: #a8a8a8;
+    }
+  }
+}
+
+/* 鎸夐挳鍥炬爣浼樺寲 */
+.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);
+}
 </style>
diff --git a/src/views/followvisit/record/index.vue b/src/views/followvisit/record/index.vue
index 332a54a..17d4c6b 100644
--- a/src/views/followvisit/record/index.vue
+++ b/src/views/followvisit/record/index.vue
@@ -107,7 +107,23 @@
             @change="handleChange"
           ></el-cascader>
         </el-form-item>
-
+         <el-form-item label="鏃ユ湡闄愬埗" prop="status">
+          <el-select v-model="endOut" placeholder="璇烽�夋嫨">
+            <el-option
+              v-for="item in endOuts"
+              :key="item.value"
+              :label="item.label"
+              :value="item.value"
+            >
+            </el-option>
+          </el-select>
+        </el-form-item>
+        <el-form-item label="璇婃柇鍚嶇О" prop="leavediagname">
+          <el-input
+            v-model="topqueryParams.leavediagname"
+            placeholder="璇疯緭鍏ヨ瘖鏂悕绉�"
+          ></el-input>
+        </el-form-item>
         <el-form-item label="浠诲姟鐘舵��" prop="status">
           <el-select v-model="topqueryParams.sendstate" placeholder="璇烽�夋嫨">
             <el-option
@@ -149,7 +165,7 @@
         <el-col :span="1.5">
           <el-button
             type="primary"
-                        icon="el-icon-plus"
+            icon="el-icon-plus"
             size="medium"
             @click="handleAdd"
             >鏂板</el-button
@@ -356,11 +372,11 @@
           label="搴旈殢璁挎棩鏈�"
           width="200"
           align="center"
-          key="longSendTime"
-          prop="longSendTime"
+          key="visitTime"
+          prop="visitTime"
         >
           <template slot-scope="scope">
-            <span>{{ formatTime(scope.row.longSendTime) }}</span>
+            <span>{{ formatTime(scope.row.visitTime) }}</span>
           </template></el-table-column
         >
         <el-table-column
@@ -402,7 +418,15 @@
           key="drname"
           prop="drname"
         />
-
+        <el-table-column
+          label="璇婃柇鍚嶇О"
+          align="center"
+          key="leavediagname"
+          prop="leavediagname"
+          width="120"
+          :show-overflow-tooltip="true"
+        >
+        </el-table-column>
         <!-- <el-table-column
           label="鐥呭巻鍙�"
           align="center"
@@ -834,7 +858,17 @@
       },
       value: [],
       list: [],
-
+  endOut: localStorage.getItem("orgname") == "涓芥按甯備腑鍖婚櫌" ? 0 : 1, //0 鍑洪櫌鏃堕棿(姝e簭)    1 鍑洪櫌鏃堕棿(鍊掑簭)   2 鍙戦�佹椂闂�(姝e簭)    3 鍙戦�佹椂闂�(鍊掑簭)  7搴旈殢璁挎棩鏈�(鍊掑簭) 搴旈殢璁挎棩鏈�(姝e簭)
+      endOuts: [
+        {
+          value: 0,
+          label: "鎴鑷冲綋鏃ユ湇鍔�",
+        },
+        {
+          value: 1,
+          label: "鍏ㄩ儴鏈嶅姟",
+        },
+      ],
       sourcetype: [
         {
           value: 1,
@@ -934,13 +968,17 @@
           value: 4,
           label: "涓嶆墽琛�",
         },
-        {
+         {
           value: 5,
           label: "鍙戦�佸け璐�",
         },
         {
           value: 6,
           label: "宸插畬鎴�",
+        },
+         {
+          value: 7,
+          label: "瓒呮椂",
         },
       ],
       topicoptionsyj: [
@@ -1029,6 +1067,13 @@
         this.topqueryParams.leavehospitaldistrictcodes =
           store.getters.belongWards.map((obj) => obj.districtCode);
       }
+        if (this.endOut == 0) {
+        this.topqueryParams.endSendDateTime = this.formatDateToYYYYMMDDHHMMSS(
+          this.getEndOfDay()
+        );
+      } else {
+        this.topqueryParams.endSendDateTime = null;
+      }
       // 鎺ュ彈寮傚父璺宠浆
       if (this.errtype) {
         this.topqueryParams.leavehospitaldistrictcodes.push(
@@ -1085,6 +1130,7 @@
         this.total = response.total;
       });
     },
+
     //鎮h��360璺宠浆
     gettoken360(sfzh, drcode, drname) {
       // this.$modal.msgWarning('360鍔熻兘鏆傛湭寮�閫�');
@@ -1099,6 +1145,21 @@
           this.$modal.msgWarning("360鏌ヨ鏃犵粨鏋�");
         }
       });
+    },
+    getEndOfDay() {
+      const date = new Date(); // 鍒涘缓涓�涓〃绀哄綋鍓嶆椂闂寸殑Date瀵硅薄
+      date.setHours(23, 59, 59, 0); // 灏嗘椂闂磋缃负23:59:59.000
+      return date;
+    },
+     formatDateToYYYYMMDDHHMMSS(date) {
+      const year = date.getFullYear();
+      const month = String(date.getMonth() + 1).padStart(2, "0"); // 鏈堜唤琛ラ浂
+      const day = String(date.getDate()).padStart(2, "0"); // 鏃ユ湡琛ラ浂
+      const hours = String(date.getHours()).padStart(2, "0");
+      const minutes = String(date.getMinutes()).padStart(2, "0");
+      const seconds = String(date.getSeconds()).padStart(2, "0");
+
+      return `${year}-${month}-${day}`;
     },
     buidegetTasklist(type) {
       if (this.topqueryParams.searchscope == 3) {
@@ -1412,9 +1473,9 @@
     Seedetails(row) {
       let type = "";
       console.log(row, "rwo");
-        if (row.type == 1) {
-          type = 1;
-        }
+      if (row.type == 1) {
+        type = 1;
+      }
       this.$router.push({
         path: "/followvisit/record/detailpage/",
         query: {
@@ -1422,6 +1483,7 @@
           patid: row.patid,
           id: row.id,
           Voicetype: type,
+          visitCount: 1,
           again: 1,
         },
       });
@@ -1588,11 +1650,11 @@
   }
 }
 ::v-deep.leftvlue .el-card__body {
-  background: #F2F8FF;
-  color: #324A9B;
+  background: #f2f8ff;
+  color: #324a9b;
 }
 ::v-deep.leftvlue .el-card__body:hover {
-  background: #3664D9;
+  background: #3664d9;
   color: #fff;
   cursor: pointer; /* 榧犳爣鎮诞鏃跺彉涓烘墜褰� */
 }
diff --git a/src/views/followvisit/record/physical/index.vue b/src/views/followvisit/record/physical/index.vue
index 7e370f1..bace874 100644
--- a/src/views/followvisit/record/physical/index.vue
+++ b/src/views/followvisit/record/physical/index.vue
@@ -1000,7 +1000,7 @@
     // 鍐嶆闅忚鏁版嵁鏇存浛
     formtidy() {
       this.form.visitType2 = this.form.visitType;
-      this.form.date2 = this.form.longSendTime;
+      this.form.date2 = this.form.visitTime;
       this.form.remark2 = this.form.remark;
     },
     // 鑾峰彇鎮h�呰褰�
@@ -1024,7 +1024,7 @@
           }
           this.logsheetlist = res.rows[0].serviceSubtaskList;
           this.templateid = this.logsheetlist[0].templateid;
-          const targetDate = new Date(this.form.longSendTime); // 鐩爣鏃ユ湡
+          const targetDate = new Date(this.form.visitTime); // 鐩爣鏃ユ湡
           const now = new Date(); // 褰撳墠鏃堕棿
           this.form.endtime = this.formatTime(this.form.endtime);
           if (now < targetDate && this.form.sendstate == 2) {
@@ -1169,7 +1169,7 @@
           this.form.remark =
             this.form.remark + "銆�" + this.getCurrentTime() + "銆�";
           let form = structuredClone(this.form);
-          form.longSendTime = this.formatTime(form.date1);
+          form.visitTime = this.formatTime(form.date1);
           form.finishtime = "";
           if (form.resource) {
             if (form.resource == 2) {
diff --git a/src/views/followvisit/satisfaction/index.vue b/src/views/followvisit/satisfaction/index.vue
index 59915c3..06537e8 100644
--- a/src/views/followvisit/satisfaction/index.vue
+++ b/src/views/followvisit/satisfaction/index.vue
@@ -29,6 +29,17 @@
             v-model="topqueryParams.patName"
           ></el-input>
         </el-form-item>
+        <el-form-item label="鏃堕棿鑼冨洿">
+          <el-date-picker
+            v-model="dateRangefs"
+            style="width: 240px"
+            value-format="yyyy-MM-dd HH:MM:SS"
+            type="datetimerange"
+            range-separator="-"
+            start-placeholder="寮�濮嬫棩鏈�"
+            end-placeholder="缁撴潫鏃ユ湡"
+          ></el-date-picker>
+        </el-form-item>
         <el-form-item>
           <el-button
             type="primary"
@@ -279,8 +290,8 @@
           fixed="right"
           width="150"
           align="center"
-          key="createTime"
-          prop="createTime"
+          key="updateTime"
+          prop="updateTime"
           sortable
         >
         </el-table-column>
@@ -366,6 +377,8 @@
       total: 0,
       // 鐢ㄦ埛琛ㄦ牸鏁版嵁
       userList: null,
+      dateRangefs: [],
+
       // 寮瑰嚭灞傛爣棰�
       title: "鏂板褰卞儚闅忚",
       // 鏄惁鏄剧ず淇敼銆佹坊鍔犲脊鍑哄眰
@@ -594,14 +607,14 @@
     /** 鎼滅储鎸夐挳鎿嶄綔 */
     handleQuery() {
       this.topqueryParams.pageNum = 1;
+      this.topqueryParams.startTime = this.dateRangefs[0] || null;
+      this.topqueryParams.endTime = this.dateRangefs[1] || null;
       this.getList();
     },
     /** 閲嶇疆鎸夐挳鎿嶄綔 */
     resetQuery() {
       this.dateRange = [];
-      this.resetForm("queryForm");
-      this.topqueryParams.deptId = undefined;
-      this.$refs.tree.setCurrentKey(null);
+      this.topqueryParams = {};
       this.handleQuery();
     },
     // 澶氶�夋閫変腑鏁版嵁
@@ -710,6 +723,8 @@
     },
     /** 瀵煎嚭鎸夐挳鎿嶄綔 */
     handleExport() {
+      console.log(this.topqueryParams,'鎵撳嵃鍏ュ弬');
+
       this.download(
         "smartor/satisfaction/export",
         {
diff --git a/src/views/followvisit/technology/index.vue b/src/views/followvisit/technology/index.vue
index 5691b3e..feef9ea 100644
--- a/src/views/followvisit/technology/index.vue
+++ b/src/views/followvisit/technology/index.vue
@@ -337,11 +337,11 @@
           label="搴旈殢璁挎棩鏈�"
           width="200"
           align="center"
-          key="longSendTime"
-          prop="longSendTime"
+          key="visitTime"
+          prop="visitTime"
         >
           <template slot-scope="scope">
-            <span>{{ formatTime(scope.row.longSendTime) }}</span>
+            <span>{{ formatTime(scope.row.visitTime) }}</span>
           </template></el-table-column
         >
         <el-table-column
@@ -905,7 +905,7 @@
           value: 4,
           label: "涓嶆墽琛�",
         },
-        {
+         {
           value: 5,
           label: "鍙戦�佸け璐�",
         },
@@ -913,6 +913,10 @@
           value: 6,
           label: "宸插畬鎴�",
         },
+         {
+          value: 7,
+          label: "瓒呮椂",
+        },
       ],
       topicoptionsyj: [
         {
diff --git a/src/views/followvisit/zbAgain/index.vue b/src/views/followvisit/zbAgain/index.vue
index 75cd9fe..f9a5b49 100644
--- a/src/views/followvisit/zbAgain/index.vue
+++ b/src/views/followvisit/zbAgain/index.vue
@@ -325,9 +325,14 @@
                   >鍙戦�佸け璐�</el-tag
                 >
               </div>
-              <div v-if="scope.row.sendstate == 6">
+            <div v-if="scope.row.sendstate == 6">
                 <el-tag type="success" :disable-transitions="false"
                   >宸插畬鎴�</el-tag
+                >
+              </div>
+              <div v-if="scope.row.sendstate == 7">
+                <el-tag type="danger" :disable-transitions="false"
+                  >瓒呮椂</el-tag
                 >
               </div>
             </el-tooltip>
@@ -382,11 +387,11 @@
           label="搴旈殢璁挎棩鏈�"
           width="200"
           align="center"
-          key="longSendTime"
-          prop="longSendTime"
+          key="visitTime"
+          prop="visitTime"
         >
           <template slot-scope="scope">
-            <span>{{ formatTime(scope.row.longSendTime) }}</span>
+            <span>{{ formatTime(scope.row.visitTime) }}</span>
           </template></el-table-column
         >
         <el-table-column
@@ -1019,13 +1024,17 @@
           value: 4,
           label: "涓嶆墽琛�",
         },
-        {
+         {
           value: 5,
           label: "鍙戦�佸け璐�",
         },
         {
           value: 6,
           label: "宸插畬鎴�",
+        },
+         {
+          value: 7,
+          label: "瓒呮椂",
         },
       ],
       sextype: [
@@ -1634,7 +1643,7 @@
           this.zcform.remark =
             this.zcform.remark + "銆�" + this.getCurrentTime() + "銆�";
           let form = structuredClone(this.zcform);
-          form.longSendTime = this.formatTime(form.date1);
+          form.visitTime = this.formatTime(form.date1);
           form.finishtime = "";
           if (form.resource) {
             if (form.resource == 2) {
diff --git a/src/views/followvisit/zysatisfaction/index.vue b/src/views/followvisit/zysatisfaction/index.vue
index 6b8edd4..779cdb3 100644
--- a/src/views/followvisit/zysatisfaction/index.vue
+++ b/src/views/followvisit/zysatisfaction/index.vue
@@ -333,9 +333,14 @@
                   >鍙戦�佸け璐�</el-tag
                 >
               </div>
-              <div v-if="scope.row.sendstate == 6">
+            <div v-if="scope.row.sendstate == 6">
                 <el-tag type="success" :disable-transitions="false"
                   >宸插畬鎴�</el-tag
+                >
+              </div>
+              <div v-if="scope.row.sendstate == 7">
+                <el-tag type="danger" :disable-transitions="false"
+                  >瓒呮椂</el-tag
                 >
               </div>
             </el-tooltip>
@@ -1126,7 +1131,7 @@
           value: 4,
           label: "涓嶆墽琛�",
         },
-        {
+         {
           value: 5,
           label: "鍙戦�佸け璐�",
         },
@@ -1134,6 +1139,10 @@
           value: 6,
           label: "宸插畬鎴�",
         },
+         {
+          value: 7,
+          label: "瓒呮椂",
+        },
       ],
       sextype: [
         {
diff --git a/src/views/index.vue b/src/views/index.vue
index ac2876e..5697f38 100644
--- a/src/views/index.vue
+++ b/src/views/index.vue
@@ -3,7 +3,7 @@
     <div class="home" style="margin-top: 40px; margin-left: 20px">
       <!-- 澶撮儴涓や釜 -->
       <el-row :gutter="20">
-        <el-col :span="11">
+        <el-col :span="8">
           <!-- 灏辫瘖缁熻鐩掑瓙 -->
           <div class="grid-content bg-purple headerBox bgc1">
             <div class="title">
@@ -45,7 +45,7 @@
             </el-row>
           </div>
         </el-col>
-        <el-col :span="9">
+        <el-col :span="12">
           <div class="grid-content bg-purple headerBox bgc2">
             <div class="title">
               鍑洪櫌鏈嶅姟
@@ -60,7 +60,8 @@
               <span>{{ endatd }} ~ {{ statd }}</span>
             </div>
             <el-row :gutter="20">
-              <el-col :span="10">
+              <!-- 鍑洪櫌灏辫瘖閲� -->
+              <el-col :span="6">
                 <div class="home-user-task-stats">
                   <p style="color: red">{{ DischargeData.rc }}</p>
                 </div>
@@ -68,12 +69,31 @@
                   <p>鍑洪櫌灏辫瘖閲忥紙浜烘锛�</p>
                 </div>
               </el-col>
-              <el-col :span="10">
+              <!-- 棣栨鏈嶅姟 -->
+              <el-col :span="6">
                 <div class="home-user-task-stats">
-                  <p style="color: red">{{ DischargeData.rs }}</p>
-                  <div class="text-color2">
-                    <p>鍑洪櫌鏈嶅姟閲忥紙浜烘锛�</p>
-                  </div>
+                  <p style="color: #67c23a">{{ DischargeData.scsf }}</p>
+                </div>
+                <div class="text-color2" style="color: #67c23a">
+                  <p>棣栨鏈嶅姟锛堜汉娆★級</p>
+                </div>
+              </el-col>
+              <!-- 鍐嶆鏈嶅姟 -->
+              <el-col :span="6">
+                <div class="home-user-task-stats">
+                  <p style="color: #e6a23c">{{ DischargeData.zcsf }}</p>
+                </div>
+                <div class="text-color2" style="color: #e6a23c">
+                  <p>鍐嶆鏈嶅姟锛堜汉娆★級</p>
+                </div>
+              </el-col>
+              <!-- 涓撶梾鏈嶅姟 -->
+              <el-col :span="6">
+                <div class="home-user-task-stats">
+                  <p style="color: #409eff">{{ DischargeData.zbsf }}</p>
+                </div>
+                <div class="text-color2" style="color: #409eff">
+                  <p>涓撶梾鏈嶅姟锛堜汉娆★級</p>
                 </div>
               </el-col>
             </el-row>
@@ -336,8 +356,11 @@
         骞�: "year",
       },
       DischargeData: {
-        rs: "",
-        rc: "",
+        rc: "", // 鍑洪櫌灏辫瘖閲忥紙鎬讳汉娆★級
+        rs: "", // 鍑洪櫌鏈嶅姟閲忥紙鎬讳汉娆★級
+        scsf: 0, // 鏂板锛氶娆℃湇鍔′汉娆�
+        zcsf: 0, // 鏂板锛氬啀娆℃湇鍔′汉娆�
+        zbsf: 0, // 鏂板锛氫笓鐥呮湇鍔′汉娆�
       },
       OutpatientData: {
         rs: "",
@@ -873,7 +896,6 @@
     },
     // 椤甸潰鍙樺寲璋冩暣澶у皬
     handleResize() {
-      console.log(111);
       // 璋冩暣 ECharts 鍥捐〃澶у皬
       if (this.myChart2) {
         this.myChart2.resize();
diff --git a/src/views/knowledge/questionbank/particulars/index.vue b/src/views/knowledge/questionbank/particulars/index.vue
index 6e58ca1..3186864 100644
--- a/src/views/knowledge/questionbank/particulars/index.vue
+++ b/src/views/knowledge/questionbank/particulars/index.vue
@@ -23,7 +23,13 @@
       </div>
       <div v-if="Editprogress == 1">
         <el-card class="box-card">
-          <el-form :inline="true" ref="topicobj" :model="topicobj" :rules="rules" class="demo-form-inline">
+          <el-form
+            :inline="true"
+            ref="topicobj"
+            :model="topicobj"
+            :rules="rules"
+            class="demo-form-inline"
+          >
             <div class="headline">
               鍩虹淇℃伅閰嶇疆
               <span style="margin-left: 30px"
@@ -65,6 +71,7 @@
                       v-model="topicobj.categoryid"
                       size="medium"
                       filterable
+                      @change="categoryidChange"
                       placeholder="璇烽�夋嫨鍒嗙被"
                     >
                       <el-option-group
@@ -87,7 +94,7 @@
                   <el-form-item label="璇勪环绫诲瀷" prop="scoretype">
                     <el-select
                       v-model="topicobj.scoretype"
-                      placeholder="璇烽�夋嫨鍒嗙被"
+                      placeholder="璇烽�夋嫨绫诲瀷"
                     >
                       <el-option
                         v-for="group in appraiselist"
@@ -121,7 +128,7 @@
                   ><el-form-item label="鏄惁鍙敤" prop="isavailable">
                     <el-radio-group v-model="topicobj.isavailable">
                       <el-radio
-                      @change="$forceUpdate()"
+                        @change="$forceUpdate()"
                         v-for="(item, index) in usable"
                         :label="item.value"
                         >{{ item.label }}</el-radio
@@ -143,7 +150,6 @@
                 </el-col> -->
               </el-row>
               <el-row :gutter="10">
-
                 <el-col :span="8"
                   ><el-form-item label="闂绫诲瀷" prop="scriptType">
                     <el-select
@@ -151,7 +157,7 @@
                       @change="changefn"
                       size="medium"
                       filterable
-                      placeholder="璇烽�夋嫨鍒嗙被"
+                      placeholder="璇烽�夋嫨绫诲瀷"
                     >
                       <el-option
                         class="topicobjaa"
@@ -185,7 +191,7 @@
                       v-model="topicobj.language"
                       size="medium"
                       filterable
-                      placeholder="璇烽�夋嫨鍒嗙被"
+                      placeholder="璇烽�夋嫨"
                     >
                       <el-option
                         class="topicobjaa"
@@ -245,7 +251,6 @@
                 </el-form-item>
               </el-col>
             </el-row> -->
-
 
               <!-- <el-form-item label="閫変腑鎸囨爣锛�">
                 <span style="margin-left: 30px"
@@ -329,8 +334,8 @@
                       style="width: 100px; height: 100px"
                       :src="topicobj.picturePath"
                       :preview-src-list="
-                                topicobj.picturePath ? [topicobj.picturePath] : []
-                              "
+                        topicobj.picturePath ? [topicobj.picturePath] : []
+                      "
                     >
                     </el-image>
                   </div>
@@ -342,7 +347,12 @@
       </div>
       <div v-if="Editprogress == 2">
         <el-card class="box-card">
-          <el-form :inline="true" ref="topicobj" :model="topicobj" class="demo-form-inline">
+          <el-form
+            :inline="true"
+            ref="topicobj"
+            :model="topicobj"
+            class="demo-form-inline"
+          >
             <div class="headline">
               鎸囨爣璁剧疆璇︽儏
               <span v-if="topicobj.targetname" style="margin-left: 30px"
@@ -731,8 +741,8 @@
         svyLibScriptOptions: [],
         svyLibScriptTagList: [],
         suitway: "1",
-        scoretype:'4',
-        language:'鏅�氳瘽',
+        scoretype: "4",
+        language: "鏅�氳瘽",
       },
       headers: {
         Authorization: "Bearer " + getToken(),
@@ -873,13 +883,12 @@
     getissueinfo() {
       this.id = this.$route.query.id;
 
-
       // 鍒嗙被
       getissueclassify({}).then((res) => {
         this.classifylist = res.rows;
         if (this.$route.query.categoryid) {
-        this.topicobj.categoryid = Number(this.$route.query.categoryid);
-      }
+          this.topicobj.categoryid = Number(this.$route.query.categoryid);
+        }
       });
       if (!this.id) {
         return;
@@ -919,75 +928,94 @@
         this.drawer = true;
       });
     },
+    //     categoryidChange(id) {
+    //   // 閬嶅巻鎵�鏈夊垎缁勶紝鍦ㄦ瘡涓垎缁勭殑 svyLibScriptCategoryList 涓煡鎵�
+    //   let targetOption = null;
+    //   for (const group of this.classifylist) {
+    //     targetOption = group.svyLibScriptCategoryList.find(item => item.id == id);
+    //     if (targetOption) break;
+    //   }
+
+    //   if (targetOption) {
+    //     console.log('閫変腑鐨勯�夐」:', targetOption);
+    //     // 娉ㄦ剰锛氳繖閲� targetOption.name 鏄�夐」鍚嶏紝濡傗�滀綇闄㈡弧鎰忓害璋冩煡鈥�
+    //     if (targetOption.name.includes('浣忛櫌')) {
+    //       this.topicobj.type = "zymyd";
+    //     } else if (targetOption.name.includes('闂ㄨ瘖')) {
+    //       this.topicobj.type = "mzmyd";
+    //     } else if (targetOption.name.includes('鍑洪櫌')) {
+    //       this.topicobj.type = "cymyd";
+    //     } else if (targetOption.name.includes('甯哥敤')) {
+    //       this.topicobj.type = "cymyd"; // 娉ㄦ剰锛氳繖閲屽拰鈥滃嚭闄⑩�濋噸澶嶄簡锛岀‘璁ゆ槸鍚﹂渶鍖哄垎
+    //     }
+    //   }
+    // },
     // 鏂板鎴栦慨鏀硅鎯�
     compileissue() {
       this.$refs["topicobj"].validate((valid) => {
         if (valid) {
-          this.topicobj.svyLibScriptOptions = this.topicobj.svyLibScriptOptions.map(
-        (item) => {
-          if (item.isoperation != 1 && item.isoperation != 3) {
-            item.isoperation = 2;
-          }
-          return item;
-        }
-      );
-      this.topicobj.targetoptions = this.topicobj.svyLibScriptOptions
-        .filter((item) => item.isoperation != 3)
-        .map((item) => item.optioncontent)
-        .join(", ");
-      this.topicobj.otherdata = JSON.stringify(this.variablelist);
-      if (this.id) {
-        this.topicobj.isoperation = 2;
-        compileissue(this.topicobj).then((res) => {
-          if (res.code == 200) {
-            this.$message({
-              message: "淇敼鎴愬姛",
-              type: "success",
+          this.topicobj.svyLibScriptOptions =
+            this.topicobj.svyLibScriptOptions.map((item) => {
+              if (item.isoperation != 1 && item.isoperation != 3) {
+                item.isoperation = 2;
+              }
+              return item;
             });
-            this.$router.go(-1);
+          this.topicobj.targetoptions = this.topicobj.svyLibScriptOptions
+            .filter((item) => item.isoperation != 3)
+            .map((item) => item.optioncontent)
+            .join(", ");
+          this.topicobj.otherdata = JSON.stringify(this.variablelist);
+          if (this.id) {
+            this.topicobj.isoperation = 2;
+            compileissue(this.topicobj).then((res) => {
+              if (res.code == 200) {
+                this.$message({
+                  message: "淇敼鎴愬姛",
+                  type: "success",
+                });
+                this.$router.go(-1);
+              } else {
+                this.$message({
+                  message: "淇敼澶辫触",
+                  type: "error",
+                });
+              }
+            });
           } else {
-            this.$message({
-              message: "淇敼澶辫触",
-              type: "error",
+            this.topicobj.isoperation = 1;
+            compileissue(this.topicobj).then((res) => {
+              if (res.code == 200) {
+                this.$message({
+                  message: "鏂板鎴愬姛",
+                  type: "success",
+                });
+                this.$router.go(-1);
+              } else {
+                this.$message({
+                  message: "鏂板澶辫触",
+                  type: "error",
+                });
+              }
             });
           }
-        });
-      } else {
-        this.topicobj.isoperation = 1;
-        compileissue(this.topicobj).then((res) => {
-          if (res.code == 200) {
-            this.$message({
-              message: "鏂板鎴愬姛",
-              type: "success",
-            });
-            this.$router.go(-1);
-          } else {
-            this.$message({
-              message: "鏂板澶辫触",
-              type: "error",
-            });
+          this.illnesslist.forEach((item, index) => {
+            if (!item.id) {
+              addtargetillness(item).then((res) => {});
+            }
+          });
+          if (this.illnesslistapi.length) {
+            deltargetillness(this.illnesslistapi.join(",")).then((res) => {});
           }
-        });
-      }
-      this.illnesslist.forEach((item, index) => {
-        if (!item.id) {
-          addtargetillness(item).then((res) => {});
         }
       });
-      if (this.illnesslistapi.length) {
-        deltargetillness(this.illnesslistapi.join(",")).then((res) => {});
-      }
-        }
-      })
-
-
     },
     // 鍒ゆ柇鍒嗗��
     Scorejudgment() {
       let scorearr = this.topicobj.svyLibScriptOptions;
       let isValid = scorearr.every((score, index) => {
         if (this.topicobj.scriptType == 1) {
-          if (score.score||score.score==0) {
+          if (score.score || score.score == 0) {
             if (
               Number(score.score) < 0 ||
               Number(score.score) > Number(this.topicobj.score)
diff --git a/src/views/login-sy.vue b/src/views/login-sy.vue
new file mode 100644
index 0000000..0408a34
--- /dev/null
+++ b/src/views/login-sy.vue
@@ -0,0 +1,322 @@
+<template>
+  <div class="login">
+    <el-form
+      ref="loginForm"
+      :model="loginForm"
+      :rules="loginRules"
+      class="login-form"
+    >
+      <h3 class="title">鏅烘収闅忚绯荤粺</h3>
+      <el-form-item prop="username">
+        <el-input
+          v-model="loginForm.username"
+          type="text"
+          auto-complete="off"
+          placeholder="璐﹀彿"
+        >
+          <svg-icon
+            slot="prefix"
+            icon-class="user"
+            class="el-input__icon input-icon"
+          />
+        </el-input>
+      </el-form-item>
+      <el-form-item prop="password">
+        <el-input
+          v-model="loginForm.password"
+          type="password"
+          auto-complete="off"
+          placeholder="瀵嗙爜"
+          @keyup.enter.native="handleLogin"
+        >
+          <svg-icon
+            slot="prefix"
+            icon-class="password"
+            class="el-input__icon input-icon"
+          />
+        </el-input>
+      </el-form-item>
+      <!-- 甯備竴===================涓� -->
+      <el-form-item prop="medicalCode">
+        <el-select
+          style="width: 100%"
+          v-model="loginForm.medicalCode"
+          placeholder="璇烽�夋嫨闄㈠尯"
+        >
+          <el-option
+            v-for="item in options"
+            :label="item.label"
+            :value="item.value"
+          >
+          </el-option>
+          <i slot="prefix" class="el-icon-mobile"></i>
+        </el-select>
+      </el-form-item>
+      <!-- <el-form-item prop="code" v-if="captchaEnabled">
+        <el-input
+          v-model="loginForm.code"
+          auto-complete="off"
+          placeholder="楠岃瘉鐮�"
+          style="width: 63%"
+          @keyup.enter.native="handleLogin"
+        >
+          <svg-icon
+            slot="prefix"
+            icon-class="validCode"
+            class="el-input__icon input-icon"
+          />
+        </el-input>
+        <div class="login-code">
+          <img :src="codeUrl" @click="getCode" class="login-code-img" />
+        </div>
+      </el-form-item> -->
+      <el-checkbox
+        v-model="loginForm.rememberMe"
+        style="margin: 0px 0px 25px 0px"
+        >璁颁綇瀵嗙爜</el-checkbox
+      >
+      <el-form-item style="width: 100%">
+        <el-button
+          :loading="loading"
+          size="medium"
+          type="primary"
+          style="width: 100%"
+          @click.native.prevent="handleLogin"
+        >
+          <span v-if="!loading">鐧� 褰�</span>
+          <span v-else>鐧� 褰� 涓�...</span>
+        </el-button>
+        <div style="float: right" v-if="register">
+          <router-link class="link-type" :to="'/register'"
+            >绔嬪嵆娉ㄥ唽1</router-link
+          >
+        </div>
+      </el-form-item>
+    </el-form>
+    <!--  搴曢儴  -->
+    <!-- <div class="el-login-footer">
+      <span style="color: #568FBD; font-size: 25px;">Copyright 漏 2018-2022 ruoyi.vip All Rights Reserved.</span>
+    </div> -->
+  </div>
+</template>
+
+<script>
+import { getCodeImg } from "@/api/login";
+import Cookies from "js-cookie";
+import { encrypt, decrypt } from "@/utils/jsencrypt";
+import { getorganization } from "@/api/AiCentre/index";
+
+export default {
+  name: "Login",
+  data() {
+    return {
+      codeUrl: "",
+      loginForm: {
+        username: "",
+        password: "",
+        rememberMe: false,
+        code: "",
+        orgid: "H41010500003",
+      },
+      options: [
+      ],
+      loginRules: {
+        username: [
+          { required: true, trigger: "blur", message: "璇疯緭鍏ユ偍鐨勮处鍙�" },
+        ],
+        password: [
+          { required: true, trigger: "blur", message: "璇疯緭鍏ユ偍鐨勫瘑鐮�" },
+        ],
+        orgid: [{ required: true, trigger: "blur", message: "璇烽�夋嫨闄㈠尯" }],
+      },
+      loading: false,
+      // 楠岃瘉鐮佸紑鍏�
+      captchaEnabled: true,
+      // 娉ㄥ唽寮�鍏�
+      register: false,
+      redirect: undefined,
+    };
+  },
+  watch: {
+    $route: {
+      handler: function (route) {
+        this.redirect = route.query && route.query.redirect;
+      },
+      immediate: true,
+    },
+  },
+  created() {
+    this.getorganization();
+    this.getCode();
+    this.getCookie();
+    // if (localStorage.getItem('orgid')) {
+    //   this.loginForm.orgid = localStorage.getItem('orgid');
+    // }
+  },
+  methods: {
+    getCode() {
+      getCodeImg().then((res) => {
+        this.captchaEnabled =
+          res.captchaEnabled === undefined ? true : res.captchaEnabled;
+        if (this.captchaEnabled) {
+          this.codeUrl = "data:image/gif;base64," + res.img;
+          this.loginForm.uuid = res.uuid;
+        }
+      });
+    },
+    getorganization() {
+      getorganization({ pageSize: 30 }).then((res) => {
+        if (res.code == 200) {
+          this.options = res.rows.map((item) => ({
+            value: item.medicalCode,
+            // value: item.medicalCode,
+            label: item.organizationName,
+          }));
+        }
+      });
+    },
+    getCookie() {
+      const username = Cookies.get("username");
+      const password = Cookies.get("password");
+      const rememberMe = Cookies.get("rememberMe");
+      this.loginForm = {
+        username: username === undefined ? this.loginForm.username : username,
+        password:
+          password === undefined ? this.loginForm.password : decrypt(password),
+        rememberMe: rememberMe === undefined ? false : Boolean(rememberMe),
+      };
+    },
+    handleLogin() {
+  this.$refs.loginForm.validate((valid) => {
+    if (valid) {
+      this.loading = true;
+
+      if (this.loginForm.rememberMe) {
+        Cookies.set("username", this.loginForm.username, { expires: 30 });
+        Cookies.set("password", encrypt(this.loginForm.password), {
+          expires: 30,
+        });
+        Cookies.set("rememberMe", this.loginForm.rememberMe, {
+          expires: 30,
+        });
+      } else {
+        Cookies.remove("username");
+        Cookies.remove("password");
+        Cookies.remove("rememberMe");
+      }
+
+      // 鍔ㄦ�佽缃� campusid 鍙傛暟
+      const selectedOrg = this.options.find(item => item.value === this.loginForm.medicalCode);
+      console.log(selectedOrg);
+
+      if (selectedOrg) {
+        if (selectedOrg.label.includes('婀栨花')) {
+          this.loginForm.campusid = 1;
+          this.loginForm.orgid = 1;
+        } else if (selectedOrg.label.includes('鍚村北')) {
+          this.loginForm.campusid = 2;
+          this.loginForm.orgid = 1;
+        } else {
+          this.loginForm.campusid = 1; // 榛樿鍊兼垨鍏朵粬澶勭悊
+          this.loginForm.orgid = 1;
+        }
+      }
+
+      this.$store
+        .dispatch("Login", this.loginForm)
+        .then((res) => {
+          if (this.loginForm.username == "admin") {
+            this.$router.push({ path: "/index" }).catch(() => {});
+          } else {
+            this.$router
+              .push({ path: "/followvisit/discharge" })
+              .catch(() => {});
+          }
+        })
+        .catch(() => {
+          this.loading = false;
+          if (this.captchaEnabled) {
+            this.getCode();
+          }
+        });
+    }
+  });
+}
+  },
+};
+</script>
+
+<style rel="stylesheet/scss" lang="scss">
+.login {
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  height: 100%;
+  overflow: hidden !important;
+  background-position: center center;
+
+  /* 鑳屾櫙鍥句笉骞抽摵 */
+  background-repeat: no-repeat;
+  /* 褰撳唴瀹归珮搴﹀ぇ浜庡浘鐗囬珮搴︽椂锛岃儗鏅浘鍍忕殑浣嶇疆鐩稿浜巚iewport鍥哄畾 */
+  background-attachment: fixed;
+  /* 璁╄儗鏅浘鍩轰簬瀹瑰櫒澶у皬浼哥缉 */
+  background-size: cover;
+  /* 璁剧疆鑳屾櫙棰滆壊锛岃儗鏅浘鍔犺浇杩囩▼涓細鏄剧ず鑳屾櫙鑹� */
+  background-color: #464646;
+  background-image: url("../assets/images/login-background.jpg");
+  background-size: cover;
+}
+.title {
+  margin: 0px auto 30px auto;
+  text-align: center;
+  color: #707070;
+}
+
+.login-form {
+  border-radius: 6px;
+  background: #ffffff;
+  width: 400px;
+  padding: 25px 25px 5px 25px;
+  .el-input {
+    height: 38px;
+    input {
+      height: 38px;
+    }
+  }
+  .input-icon {
+    height: 39px;
+    width: 14px;
+    margin-left: 2px;
+  }
+}
+.login-tip {
+  font-size: 13px;
+  text-align: center;
+  color: #bfbfbf;
+}
+.login-code {
+  width: 33%;
+  height: 38px;
+  float: right;
+  img {
+    cursor: pointer;
+    vertical-align: middle;
+  }
+}
+.el-login-footer {
+  height: 40px;
+  line-height: 40px;
+  position: fixed;
+  bottom: 0;
+  width: 100%;
+  text-align: center;
+  color: #fff;
+  font-family: Arial;
+  font-size: 12px;
+  letter-spacing: 1px;
+}
+
+.login-code-img {
+  height: 38px;
+}
+</style>
diff --git a/src/views/login.vue b/src/views/login.vue
index 0f19503..d087469 100644
--- a/src/views/login.vue
+++ b/src/views/login.vue
@@ -114,8 +114,7 @@
         code: "",
         orgid:'1',
       },
-      options: [
-      ],
+      options: [],
       loginRules: {
         username: [
           { required: true, trigger: "blur", message: "璇疯緭鍏ユ偍鐨勮处鍙�" },
@@ -161,7 +160,7 @@
       });
     },
     getorganization() {
-      getorganization().then((res) => {
+      getorganization({ pageSize: 30 }).then((res) => {
         if (res.code == 200) {
           this.options = res.rows.map((item) => ({
             value: item.orgid,
@@ -185,6 +184,7 @@
       this.$refs.loginForm.validate((valid) => {
         if (valid) {
           this.loading = true;
+
           if (this.loginForm.rememberMe) {
             Cookies.set("username", this.loginForm.username, { expires: 30 });
             Cookies.set("password", encrypt(this.loginForm.password), {
diff --git a/src/views/outsideChainwtnew.vue b/src/views/outsideChainwtnew.vue
index 3b5a39e..205e6d2 100644
--- a/src/views/outsideChainwtnew.vue
+++ b/src/views/outsideChainwtnew.vue
@@ -208,6 +208,9 @@
   computed: {
     // 璁$畻灞炴�э細鑾峰彇鎵�鏈夊彲瑙佺殑棰樼洰
     visibleQuestions() {
+      if (!Array.isArray(this.questionList)) {
+        return [];
+      }
       return this.questionList.filter((question) => !question.ishide);
     },
   },
@@ -259,7 +262,7 @@
       getCachequestionnaire({ param1: this.taskid, param2: this.patid }).then(
         (res) => {
           if (res.code == 200) {
-            this.questionList = res.data;
+            this.questionList = res.data.result;
             this.accomplish = res.data.submit;
             if (this.questionList[0]) {
               this.questionList.forEach((item) => {
@@ -471,6 +474,8 @@
         } else {
           // 姝e父璺宠浆閫昏緫
           const nextQuestionIndex = selectedOptionObj.nextQuestion - 1;
+          console.log(nextQuestionIndex, 4);
+          console.log(selectedOptionObj);
 
           this.questionList = this.questionList.map((item, index) => {
             // 淇濈暀褰撳墠棰樼洰涔嬪墠鐨勯殣钘忕姸鎬�
diff --git a/src/views/patient/patient/AwaitingAdmission.vue b/src/views/patient/patient/AwaitingAdmission.vue
index f692a80..6a72312 100644
--- a/src/views/patient/patient/AwaitingAdmission.vue
+++ b/src/views/patient/patient/AwaitingAdmission.vue
@@ -11,42 +11,6 @@
           v-show="showSearch"
           label-width="98px"
         >
-          <el-form-item label="濮撳悕" width="100" prop="name">
-            <el-input
-              v-model="queryParams.patname"
-              placeholder="璇疯緭鍏ュ鍚�"
-              clearable
-              style="width: 200px"
-              @keyup.enter.native="handleQuery"
-            />
-          </el-form-item>
-          <el-form-item label="璇婃柇" width="100" prop="name">
-            <el-input
-              v-model="queryParams.diagname"
-              placeholder="璇疯緭鍏ヨ瘖鏂�"
-              clearable
-              style="width: 200px"
-              @keyup.enter.native="handleQuery"
-            />
-          </el-form-item>
-          <el-form-item label="绉戝" width="100" prop="name">
-            <el-input
-              v-model="queryParams.deptname"
-              placeholder="璇疯緭鍏ョ瀹ゅ悕绉�"
-              clearable
-              style="width: 200px"
-              @keyup.enter.native="handleQuery"
-            />
-          </el-form-item>
-          <el-form-item label="鍖荤敓" width="100" prop="name">
-            <el-input
-              v-model="queryParams.drname"
-              placeholder="璇疯緭鍏ュ尰鐢熷鍚�"
-              clearable
-              style="width: 200px"
-              @keyup.enter.native="handleQuery"
-            />
-          </el-form-item>
           <el-form-item label="鐥呮鍙�" prop="outhospno">
             <el-input
               v-model="queryParams.outhospno"
@@ -56,17 +20,7 @@
               @keyup.enter.native="handleQuery"
             />
           </el-form-item>
-
-          <el-form-item label="鎮h�呰寖鍥�" prop="status">
-            <el-cascader
-              v-model="queryParams.scopetype"
-              placeholder="榛樿鍏ㄩ儴"
-              :options="sourcetype"
-              :props="{ expandTrigger: 'hover' }"
-              @change="handleChange"
-            ></el-cascader>
-          </el-form-item>
-          <el-form-item label="灏辫瘖鏃ユ湡">
+          <el-form-item label="棰勭害浣忛櫌鏃ユ湡">
             <el-date-picker
               v-model="dateRange"
               style="width: 240px"
@@ -76,28 +30,31 @@
               start-placeholder="寮�濮嬫棩鏈�"
               end-placeholder="缁撴潫鏃ユ湡"
             ></el-date-picker>
-            <!-- <el-date-picker
-                v-model="dateRange"
-                type="datetimerange"
-                value-format="yyyy-MM-dd HH:mm:ss"
-                start-placeholder="寮�濮嬫棩鏈�"
-                end-placeholder="缁撴潫鏃ユ湡"
-                :default-time="['12:00:00']"
+          </el-form-item>
+          <el-form-item label="鏈夋棤闄㈠墠妫�鏌�" prop="status">
+            <el-select v-model="queryParams.examine" placeholder="璇烽�夋嫨">
+              <el-option label="鏈�" :value="1"> </el-option>
+              <el-option label="鏃�" :value="2"> </el-option>
+            </el-select>
+          </el-form-item>
+          <el-form-item label="鏀舵不绫诲瀷" prop="status">
+            <el-select v-model="queryParams.cureType" placeholder="璇烽�夋嫨">
+              <el-option
+                v-for="item in dict.type.receive_and_cure"
+                :key="item.value"
+                :label="item.label"
+                :value="item.value"
               >
-              </el-date-picker> -->
+              </el-option>
+            </el-select>
+          </el-form-item>
+          <el-form-item label="瀹夋帓鐘舵��" prop="status">
+            <el-select v-model="queryParams.arrange" placeholder="璇烽�夋嫨">
+              <el-option label="宸插畨鎺�" :value="1"> </el-option>
+              <el-option label="鏈畨鎺�" :value="2"> </el-option>
+            </el-select>
           </el-form-item>
           <el-row>
-            <!-- <el-form-item label=" 灏辫瘖鏃ユ湡 " prop="admitdate">
-              <el-date-picker
-                clearable
-                v-model="queryParams.admitdate"
-                type="date"
-                value-format="yyyy-MM-dd"
-                placeholder="璇烽�夋嫨 灏辫瘖鏃ユ湡 "
-              >
-              </el-date-picker>
-            </el-form-item> -->
-
             <el-form-item>
               <el-button
                 type="primary"
@@ -207,6 +164,12 @@
             prop="id"
           /> -->
           <el-table-column
+            label="鐥呮鍙�"
+            align="center"
+            key="outhospno"
+            prop="outhospno"
+          />
+          <el-table-column
             label="灏辫瘖鏃堕棿"
             align="center"
             key="admitdate"
@@ -217,18 +180,29 @@
               <span>{{ formatTime(scope.row.admitdate) }}</span>
             </template>
           </el-table-column>
-          <!-- <el-table-column
-            label="鐥呮鍙�"
-            align="center"
-            key="patno"
-            prop="patno"
-          /> -->
           <el-table-column
-            label="鐥呮鍙�"
+            label="棰勭害浣忛櫌鏃ユ湡"
             align="center"
-            key="outhospno"
-            prop="outhospno"
-          />
+            key="admitdate"
+            prop="admitdate"
+            width="160"
+          >
+            <template slot-scope="scope">
+              <span>{{ formatTime(scope.row.admitdate) }}</span>
+            </template>
+          </el-table-column>
+          <el-table-column
+            label="棰勭害璇婃柇鏃ユ湡"
+            align="center"
+            key="admitdate"
+            prop="admitdate"
+            width="160"
+          >
+            <template slot-scope="scope">
+              <span>{{ formatTime(scope.row.admitdate) }}</span>
+            </template>
+          </el-table-column>
+
           <el-table-column
             label="濮撳悕"
             width="100"
@@ -272,48 +246,49 @@
             width="120"
           />
           <el-table-column
+            label="韬唤璇佸彿"
+            align="center"
+            key="idcardno"
+            prop="idcardno"
+            width="220"
+          />
+          <el-table-column
             label="鑱旂郴鐢佃瘽"
             align="center"
             key="telcode"
             prop="telcode"
             width="120"
           />
-          <!-- <el-table-column
-            label="鎮h�呮爣绛撅紙缂猴級"
-            align="center"
-            key="tagList"
-            prop="tagList"
-            width="160"
-            :show-overflow-tooltip="true"
-          >
-            <template slot-scope="scope">
-              <span v-for="item in scope.row.tagList">{{ item }} </span>
-            </template>
-          </el-table-column> -->
 
           <el-table-column
-            label="璇婃柇"
-            align="center"
-            key="diagname"
-            prop="diagname"
-            width="190"
-          />
-          <!-- <el-table-column
-            label="涓昏堪"
-            align="center"
-            key="mainsuit"
-            prop="mainsuit"
-            width="120"
-          /> -->
-          <el-table-column
-            label="灏辫瘖绉戝"
+            label="绉戝"
             align="center"
             key="deptname"
             prop="deptname"
             width="120"
           />
           <el-table-column
-            label="鎺ヨ瘖鍖荤敓"
+            label="鏈夋棤闄㈠墠妫�鏌�"
+            align="center"
+            key="deptname"
+            prop="deptname"
+            width="120"
+          />
+          <el-table-column
+            label="鏀舵不绫诲瀷"
+            align="center"
+            key="deptname"
+            prop="deptname"
+            width="120"
+          >
+            <template slot-scope="scope">
+              <dict-tag
+                :options="dict.type.receive_and_cure"
+                :value="scope.row.sendState"
+              /> </template
+          ></el-table-column>
+          <el-table-column
+            label="瀹夋帓鐘舵��"
             align="center"
             key="drname"
             prop="drname"
@@ -559,7 +534,7 @@
 import { delUser } from "@/api/system/user";
 
 import {
-  listPatouthosp,
+  listPatMedInhosp,
   getPatouthosp,
   addPatouthosp,
   updatePatouthosp,
@@ -577,7 +552,7 @@
 
 export default {
   name: "Userhuanze",
-  dicts: ["sys_normal_disable", "sys_user_sex"],
+  dicts: ["sys_normal_disable", "sys_user_sex", "receive_and_cure"],
   components: { Treeselect },
   data() {
     return {
@@ -722,9 +697,7 @@
       queryParams: {
         pageNum: 1,
         pageSize: 10,
-        searchscope: 3,
-        scopetype: [],
-        deptcodes: [],
+
       },
       // 琛ㄥ崟鏍¢獙
       rules: {
@@ -800,13 +773,6 @@
     /** 鏌ヨ鎮h�呭垪琛� */
     getList() {
       this.loading = true;
-      if (this.queryParams.searchscope == 3) {
-        this.queryParams.deptcodes = store.getters.belongDepts.map(
-          (obj) => obj.deptCode
-        );
-        // this.queryParams.leavehospitaldistrictcodes =
-        //   store.getters.belongWards.map((obj) => obj.districtCode);
-      }
       if (this.dateRange) {
         this.queryParams.beginTime = this.dateRange[0];
         this.queryParams.endTime = this.dateRange[1];
@@ -814,7 +780,9 @@
         this.queryParams.beginTime = "";
         this.queryParams.endTime = "";
       }
-      listPatouthosp(this.queryParams).then((response) => {
+        this.loading = false;
+
+      listPatMedInhosp(this.queryParams).then((response) => {
         this.userList = response.rows;
         this.total = response.total;
         this.loading = false;
@@ -834,25 +802,7 @@
         this.optionstag = response.rows;
       });
     },
-    // 鎮h�呰寖鍥村鐞�
-    handleChange(value) {
-      let type = value[0];
-      let code = value.slice(-1)[0];
-      // this.queryParams.leavehospitaldistrictcodes = [];
-      this.queryParams.deptcodes = [];
 
-      if (type == 1) {
-        this.queryParams.deptcodes.push(code);
-        // this.queryParams.leavehospitaldistrictcodes = [];
-        this.queryParams.searchscope = 1;
-      } else if (type == 2) {
-        // this.queryParams.leavehospitaldistrictcodes.push(code);
-        this.queryParams.deptcodes = [];
-        this.queryParams.searchscope = 2;
-      } else {
-        this.queryParams.searchscope = 3;
-      }
-    },
     // 鏌ヨ瀵煎叆灞曠ず鍒楄〃
     geterryList() {
       this.loading = true;
@@ -919,9 +869,7 @@
       this.queryParams = {
         pageNum: 1,
         pageSize: 10,
-        searchscope: 3,
-        scopetype: [],
-        deptcodes: [],
+
         // leavehospitaldistrictcodes: [],
       };
       this.handleQuery();
diff --git a/src/views/patient/patient/behospitalized.vue b/src/views/patient/patient/behospitalized.vue
index a368496..56c7b2f 100644
--- a/src/views/patient/patient/behospitalized.vue
+++ b/src/views/patient/patient/behospitalized.vue
@@ -96,18 +96,19 @@
               >鏂板</el-button
             >
           </el-col> -->
-          <!-- <el-col :span="1.5">
+          <!-- 寤剁画鎶ょ悊鎸夐挳 -->
+          <el-col :span="1.5">
             <el-button
-              type="success"
+              type="warning"
               plain
-              icon="el-icon-edit"
+              icon="el-icon-plus"
               size="medium"
-              :disabled="single"
-              @click="handleUpdate"
-              v-hasPermi="['system:user:edit']"
-              >淇敼</el-button
+              :disabled="multiple"
+              @click="handleBatchAddTask"
             >
-          </el-col> -->
+              娣诲姞寤剁画鎶ょ悊浠诲姟
+            </el-button>
+          </el-col>
           <el-col :span="1.5">
             <el-button
               type="danger"
@@ -284,7 +285,172 @@
         />
       </el-col>
     </el-row>
+    <!-- 鎵归噺娣诲姞寤剁画鎶ょ悊浠诲姟寮圭獥 -->
+    <!-- 鎵归噺娣诲姞寤剁画鎶ょ悊浠诲姟寮圭獥 -->
+    <el-dialog
+      title="鎵归噺娣诲姞寤剁画鎶ょ悊"
+      :visible.sync="batchTaskVisible"
+      width="90%"
+      append-to-body
+      class="batch-dialog"
+      :close-on-click-modal="false"
+    >
+      <el-row :gutter="20">
+        <!-- 宸︿晶锛氶�変腑鎮h�呭垪琛� -->
+        <el-col :span="12">
+          <div class="batch-patient-section">
+            <div class="section-header">
+              <h4>閫変腑鎮h��</h4>
+              <span class="patient-count">{{ selectedPatients.length }}浜�</span>
+            </div>
+            <el-table
+              :data="selectedPatients"
+              border
+              style="width: 100%"
+              size="small"
+              :row-class-name="tableRowClassName"
+              :header-cell-style="{ background: '#F5F7FA', color: '#606266' }"
+            >
+              <el-table-column
+                prop="patname"
+                label="濮撳悕"
+                width="100"
+                align="center"
+              />
+              <el-table-column
+                prop="sex"
+                label="鎬у埆"
+                width="80"
+                align="center"
+              >
+                <template slot-scope="scope">
+                  <el-tag
+                    size="small"
+                    :type="scope.row.sex === 1 ? 'primary' : 'danger'"
+                  >
+                    {{ scope.row.sex === 1 ? "鐢�" : "濂�" }}
+                  </el-tag>
+                </template>
+              </el-table-column>
+              <el-table-column
+                label="鍏ラ櫌鏃堕棿"
+                align="center"
+                key="starttime"
+                prop="starttime"
+                width="120"
+              >
+                <template slot-scope="scope">
+                  <span class="time-text">{{
+                    formatTime(scope.row.starttime)
+                  }}</span>
+                </template>
+              </el-table-column>
+              <el-table-column
+                prop="inhospno"
+                label="浣忛櫌鍙�"
+                width="120"
+                align="center"
+              />
+              <el-table-column prop="deptname" label="绉戝" align="center" />
+              <el-table-column
+                prop="leavehospitaldistrictname"
+                label="鐥呭尯"
+                align="center"
+              />
+            </el-table>
+          </div>
+        </el-col>
 
+        <!-- 鍙充晶锛氫换鍔″垪琛� -->
+        <el-col :span="12">
+          <div class="batch-task-section">
+            <div class="section-header">
+              <h4>寤剁画鎶ょ悊浠诲姟</h4>
+              <div v-if="selectedTask" class="task-selected-hint selected">
+                <i class="el-icon-success"></i>
+                <span>宸查�夋嫨锛歿{ selectedTask.taskName }}</span>
+              </div>
+              <div v-else class="task-selected-hint">
+                <i class="el-icon-info"></i>
+                <span>璇风偣鍑婚�夋嫨涓�涓换鍔�</span>
+              </div>
+            </div>
+            <el-table
+              :data="taskList"
+              border
+              style="width: 100%"
+              height="680"
+              size="small"
+              @current-change="handleTaskSelectionChange"
+              highlight-current-row
+              :row-class-name="taskRowClassName"
+              :header-cell-style="{ background: '#F5F7FA', color: '#606266' }"
+              :current-row-key="selectedTask ? selectedTask.taskid : ''"
+            >
+              <el-table-column
+                label="浠诲姟鍚嶇О"
+                fixed
+                align="center"
+                key="taskName"
+                prop="taskName"
+                :show-overflow-tooltip="true"
+                width="180"
+              />
+
+              <el-table-column
+                label="鏈嶅姟椤圭洰"
+                align="center"
+                key="templatename"
+                prop="templatename"
+                :show-overflow-tooltip="true"
+              />
+
+              <el-table-column
+                label="鍒涘缓浜�"
+                align="center"
+                key="createBy"
+                prop="createBy"
+                :show-overflow-tooltip="true"
+              />
+              <el-table-column
+                label="鍒涘缓鏃堕棿"
+                sortable
+                align="center"
+                prop="createTime"
+              >
+                <template slot-scope="scope">
+                  <span class="time-text">{{
+                    formatTime(scope.row.createTime)
+                  }}</span>
+                </template>
+              </el-table-column>
+              <template #empty>
+                <div class="empty-message">
+                  <i class="el-icon-document"></i>
+                  <span>鏆傛棤鍙敤寤剁画鎶ょ悊浠诲姟</span>
+                  <span class="empty-tips">璇疯仈绯荤鐞嗗憳鍒涘缓浠诲姟</span>
+                </div>
+              </template>
+            </el-table>
+          </div>
+        </el-col>
+      </el-row>
+
+      <!-- 搴曢儴鎸夐挳 -->
+      <div slot="footer" class="dialog-footer">
+        <el-button @click="batchTaskVisible = false" :disabled="batchLoading"
+          >鍙� 娑�</el-button
+        >
+        <el-button
+          type="primary"
+          :loading="batchLoading"
+          @click="submitBatchTask"
+          :disabled="!selectedTask || batchLoading"
+        >
+          {{ batchLoading ? "鍒涘缓涓�..." : "鍒涘缓寤剁画鎶ょ悊浠诲姟" }}
+        </el-button>
+      </div>
+    </el-dialog>
     <!-- 鐢ㄦ埛瀵煎叆瀵硅瘽妗� -->
     <el-dialog
       :title="upload.title"
@@ -398,7 +564,7 @@
 import Treeselect from "@riophae/vue-treeselect";
 import { listDept } from "@/api/system/dept";
 import "@riophae/vue-treeselect/dist/vue-treeselect.css";
-import { query360PatInfo } from "@/api/AiCentre/index";
+import { query360PatInfo, getTasklist, addSubtask } from "@/api/AiCentre/index";
 
 import store from "@/store";
 
@@ -433,6 +599,12 @@
       // 榛樿瀵嗙爜
       initPassword: undefined,
       amendtag: false, //鏄惁淇敼
+      // 鎵归噺浠诲姟鐩稿叧鏁版嵁
+      batchTaskVisible: false, // 寮圭獥鍙鎬�
+      selectedPatients: [], // 閫変腑鐨勬偅鑰呭垪琛�
+      taskList: [], // 浠诲姟鍒楄〃
+      selectedTask: null, // 閫変腑鐨勪换鍔�
+      batchLoading: false, // 鎵归噺鎻愪氦鍔犺浇鐘舵��
       // 鏃ユ湡鑼冨洿
       dateRange: [],
       paperstypes: [
@@ -567,52 +739,6 @@
         leaveldeptcodes: [],
         leavehospitaldistrictcodes: [],
       },
-      // 琛ㄥ崟鏍¢獙
-      rules: {
-        // userName: [
-        //   { required: true, message: "鐢ㄦ埛鍚嶇О涓嶈兘涓虹┖", trigger: "blur" },
-        //   {
-        //     min: 2,
-        //     max: 20,
-        //     message: "鐢ㄦ埛鍚嶇О闀垮害蹇呴』浠嬩簬 2 鍜� 20 涔嬮棿",
-        //     trigger: "blur",
-        //   },
-        // ],
-        // nickName: [
-        //   { required: true, message: "鐢ㄦ埛鏄电О涓嶈兘涓虹┖", trigger: "blur" },
-        // ],
-        // password: [
-        //   { required: true, message: "鐢ㄦ埛瀵嗙爜涓嶈兘涓虹┖", trigger: "blur" },
-        //   {
-        //     min: 5,
-        //     max: 20,
-        //     message: "鐢ㄦ埛瀵嗙爜闀垮害蹇呴』浠嬩簬 5 鍜� 20 涔嬮棿",
-        //     trigger: "blur",
-        //   },
-        // ],
-        // email: [
-        //   {
-        //     type: "email",
-        //     message: "璇疯緭鍏ユ纭殑閭鍦板潃",
-        //     trigger: ["blur", "change"],
-        //   },
-        // ],
-        // phonenumber: [
-        //   {
-        //     pattern: /^1[3|4|5|6|7|8|9][0-9]\d{8}$/,
-        //     message: "璇疯緭鍏ユ纭殑鎵嬫満鍙风爜",
-        //     trigger: "blur",
-        //   },
-        // ],
-        // IDnumber: [
-        //   {
-        //     pattern:
-        //       /^\d{6}((((((19|20)\d{2})(0[13-9]|1[012])(0[1-9]|[12]\d|30))|(((19|20)\d{2})(0[13578]|1[02])31)|((19|20)\d{2})02(0[1-9]|1\d|2[0-8])|((((19|20)([13579][26]|[2468][048]|0[48]))|(2000))0229))\d{3})|((((\d{2})(0[13-9]|1[012])(0[1-9]|[12]\d|30))|((\d{2})(0[13578]|1[02])31)|((\d{2})02(0[1-9]|1\d|2[0-8]))|(([13579][26]|[2468][048]|0[048])0229))\d{2}))(\d|X|x)$/,
-        //     message: "璇疯緭鍏ユ纭殑韬唤璇佸彿鐮�",
-        //     trigger: "blur",
-        //   },
-        // ],
-      },
     };
   },
   watch: {
@@ -637,6 +763,9 @@
     this.queryParams.leaveldeptcodes = store.getters.belongDepts.map(
       (obj) => obj.deptCode
     );
+    this.queryParams.leavehospitaldistrictcodes = store.getters.belongWards.map(
+      (obj) => obj.districtCode
+    );
     this.getList();
     // this.listDept();
     this.gettabList();
@@ -651,6 +780,23 @@
         this.total = response.total;
         this.loading = false;
       });
+    },
+    /** 琛ㄦ牸琛屾牱寮� */
+    tableRowClassName({ row, rowIndex }) {
+      if (rowIndex % 2 === 0) {
+        return "even-row";
+      } else {
+        return "odd-row";
+      }
+    },
+
+    /** 浠诲姟琛ㄦ牸琛屾牱寮� */
+    taskRowClassName({ row, rowIndex }) {
+      if (rowIndex % 2 === 0) {
+        return "task-even-row";
+      } else {
+        return "task-odd-row";
+      }
     },
     listDept() {
       listDept(this.queryParams).then((res) => {
@@ -705,7 +851,151 @@
         this.loading = false;
       });
     },
+    /** 鎵归噺娣诲姞寤剁画鎶ょ悊浠诲姟鎸夐挳鐐瑰嚮 */
+    handleBatchAddTask() {
+      // 鏍¢獙鏄惁閫変腑鎮h��
+      if (this.ids.length === 0) {
+        this.$modal.msgWarning("璇疯嚦灏戦�変腑1鍚嶆偅鑰�");
+        return;
+      }
 
+      // 鑾峰彇閫変腑鎮h�呯殑绉戝淇℃伅
+      const patientDepts = new Set();
+      let deptcode = "";
+      this.ids.forEach((patId) => {
+        const patient = this.userList.find((item) => item.patid === patId);
+        if (patient) {
+          patientDepts.add(patient.deptname);
+          deptcode = patient.deptcode;
+        }
+      });
+
+      // 鑾峰彇閫変腑鎮h�呭垪琛�
+      this.selectedPatients = this.userList.filter((item) =>
+        this.ids.includes(item.patid)
+      );
+
+      // 鏄剧ず寮圭獥
+      this.batchTaskVisible = true;
+
+      // 鑾峰彇浠诲姟鍒楄〃
+      this.loadTaskList(deptcode);
+    },
+
+    /** 鍔犺浇浠诲姟鍒楄〃 */
+    loadTaskList(deptcode) {
+      this.batchLoading = true;
+      let topqueryParams = {
+        pageNum: 1,
+        pageSize: 100, // 璁剧疆杈冨ぇ鐨勫垎椤佃幏鍙栨洿澶氫换鍔�
+        type: 2, // 寤剁画鎶ょ悊浠诲姟绫诲瀷
+      };
+
+      getTasklist(topqueryParams)
+        .then((response) => {
+          this.taskList = response.rows;
+          this.batchLoading = false;
+
+          if (this.taskList.length === 0) {
+            this.$modal.msgWarning("褰撳墠绉戝鏃犲彲鐢ㄥ欢缁姢鐞嗕换鍔�");
+          }
+        })
+        .catch((error) => {
+          this.$modal.msgError("鑾峰彇浠诲姟鍒楄〃澶辫触锛�" + error.message);
+          this.batchLoading = false;
+        });
+    },
+
+    /** 澶勭悊浠诲姟閫夋嫨鍙樺寲 */
+    handleTaskSelectionChange(currentRow) {
+      this.selectedTask = currentRow;
+    },
+
+    /** 鎵归噺鎻愪氦寤剁画鎶ょ悊浠诲姟 */
+    async submitBatchTask() {
+      // 鏍¢獙鏄惁閫変腑浠诲姟
+      if (!this.selectedTask) {
+        this.$modal.msgWarning("璇烽�夋嫨1涓换鍔�");
+        return;
+      }
+
+      this.batchLoading = true;
+      const successPatients = [];
+      const failedPatients = [];
+      const errorMessages = [];
+
+      try {
+        // 閬嶅巻閫変腑鐨勬偅鑰咃紝閫愪釜璋冪敤鎺ュ彛
+        for (const patient of this.selectedPatients) {
+          const params = {
+            taskid: this.selectedTask.taskid,
+            type: this.selectedTask.type,
+            taskName: this.selectedTask.taskName,
+            serviceType: 99, // 寤剁画鎶ょ悊鏈嶅姟绫诲瀷
+            preachform: this.selectedTask.preachform,
+            templateid: this.selectedTask.templateid,
+            libtemplateid: this.selectedTask.libtemplateid,
+            sendstate: 2, // 鍙戦�佺姸鎬�
+            continueFlag: 1, // 寤剁画鎶ょ悊鏍囧織锛堝湪闄㈡偅鑰咃級
+            ...patient,
+            sendname: patient.patname,
+            // 鍦ㄩ櫌鎮h�呬娇鐢ㄥ綋鍓嶆椂闂翠綔涓轰换鍔″紑濮嬫椂闂�
+            starttime: new Date().toISOString().split("T")[0] + " 00:00:00",
+            // 鍦ㄩ櫌鎮h�呭彲鑳介渶瑕佽缃换鍔$殑缁撴潫鏃堕棿锛堝鍑洪櫌鍚�7澶╋級
+            endtime: this.getFollowUpEndTime(patient.starttime),
+            leavediagname: patient.diagname || "", // 浣跨敤鍏ラ櫌璇婃柇
+            age: patient.age || "",
+          };
+
+          try {
+            const response = await addSubtask(params);
+            if (response.code === 200) {
+              successPatients.push(patient.patname);
+            } else {
+              failedPatients.push(patient.patname);
+              errorMessages.push(
+                `${patient.patname}: ${response.msg || "娣诲姞澶辫触"}`
+              );
+            }
+          } catch (error) {
+            failedPatients.push(patient.patname);
+            errorMessages.push(
+              `${patient.patname}: ${error.message || "缃戠粶閿欒"}`
+            );
+          }
+        }
+
+        // 鏄剧ず澶勭悊缁撴灉
+        if (failedPatients.length === 0) {
+          this.$modal.msgSuccess(
+            `鎴愬姛涓� ${successPatients.length} 鍚嶆偅鑰呮坊鍔犲欢缁姢鐞嗕换鍔
+          );
+        } else {
+          this.$modal.msgWarning(
+            `鎴愬姛娣诲姞 ${successPatients.length} 浜猴紝澶辫触 ${failedPatients.length} 浜恒�俙 +
+              (errorMessages.length > 0
+                ? `澶辫触鍘熷洜锛�${errorMessages.join("; ")}`
+                : "")
+          );
+        }
+
+        this.batchTaskVisible = false;
+        this.getList(); // 鍒锋柊鎮h�呭垪琛�
+      } catch (error) {
+        this.$modal.msgError("鎵归噺娣诲姞浠诲姟杩囩▼涓嚭閿欙細" + error.message);
+      } finally {
+        this.batchLoading = false;
+      }
+    },
+
+    /** 璁$畻闅忚缁撴潫鏃堕棿锛堝湪闄㈡偅鑰咃細鍑洪櫌鍚�7澶╋級 */
+    getFollowUpEndTime(admitDate) {
+      if (!admitDate) return "";
+      // 鍋囪鍦ㄩ櫌鎮h�呯殑寤剁画鎶ょ悊鍦ㄥ嚭闄㈠悗7澶╃粨鏉�
+      const endDate = new Date(admitDate);
+      endDate.setDate(endDate.getDate() + 7); // 鍑洪櫌鍚�7澶�
+      return endDate.toISOString().split("T")[0] + " 00:00:00";
+    },
     // 绛涢�夎妭鐐�
     filterNode(value, data) {
       if (!value) return true;
@@ -776,8 +1066,8 @@
         leavehospitaldistrictcodes: [],
       };
       this.queryParams.leaveldeptcodes = store.getters.belongDepts.map(
-      (obj) => obj.deptCode
-    );
+        (obj) => obj.deptCode
+      );
       this.handleQuery();
     },
     // 澶氶�夋閫変腑鏁版嵁
@@ -948,6 +1238,325 @@
   }
 }
 .button-textsc {
-  color: #3664D9;
+  color: #3664d9;
+}
+// 鎵归噺浠诲姟寮圭獥浼樺寲鏍峰紡
+.batch-dialog {
+  .el-dialog__body {
+    padding: 20px 20px 10px;
+  }
+
+  .el-dialog__header {
+    background: linear-gradient(135deg, #5788fe, #7aa1ff);
+    padding: 15px 20px;
+
+    .el-dialog__title {
+      color: white;
+      font-weight: 600;
+      font-size: 16px;
+    }
+
+    .el-dialog__headerbtn {
+      .el-dialog__close {
+        color: white;
+        font-size: 18px;
+
+        &:hover {
+          color: #f0f0f0;
+        }
+      }
+    }
+  }
+}
+
+// 寮圭獥鍐呭鍖哄煙
+.batch-patient-section,
+.batch-task-section {
+  h4 {
+    margin: 0 0 12px 0;
+    color: #333;
+    font-size: 16px;
+    font-weight: 600;
+    padding-left: 8px;
+    border-left: 4px solid #5788fe;
+    display: flex;
+    align-items: center;
+
+    &::before {
+      content: "";
+      display: inline-block;
+      width: 6px;
+      height: 6px;
+      background-color: #5788fe;
+      border-radius: 50%;
+      margin-right: 8px;
+    }
+  }
+
+  .section-header {
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+    margin-bottom: 12px;
+
+    .patient-count {
+      color: #5788fe;
+      font-weight: 500;
+      background: #f0f5ff;
+      padding: 4px 12px;
+      border-radius: 12px;
+      font-size: 13px;
+    }
+  }
+}
+
+// 鎮h�呰〃鏍间紭鍖�
+.batch-patient-section {
+  .el-table {
+    border: 1px solid #e8eaec;
+    border-radius: 6px;
+    overflow: hidden;
+
+    .el-table__header-wrapper {
+      th {
+        background-color: #f5f7fa;
+        color: #606266;
+        font-weight: 600;
+        height: 40px;
+      }
+    }
+
+    .el-table__body-wrapper {
+      tr:hover > td {
+        background-color: #f5f9ff;
+      }
+    }
+  }
+}
+
+// 浠诲姟琛ㄦ牸浼樺寲
+.batch-task-section {
+  .el-table {
+    border: 1px solid #e8eaec;
+    border-radius: 6px;
+    overflow: hidden;
+
+    .el-table__header-wrapper {
+      th {
+        background-color: #f5f7fa;
+        color: #606266;
+        font-weight: 600;
+        height: 40px;
+      }
+    }
+
+    .el-table__body-wrapper {
+      tr {
+        cursor: pointer;
+        transition: all 0.3s;
+
+        &:hover > td {
+          background-color: #f5f9ff;
+        }
+
+        // 閫変腑琛屾牱寮�
+        &.current-row {
+          td {
+            background-color: #e8f1ff !important;
+            border-left: 3px solid #5788fe;
+
+            &:first-child {
+              border-left: none;
+            }
+          }
+        }
+      }
+
+      .selected-row {
+        position: relative;
+
+        &::after {
+          content: "鉁�";
+          position: absolute;
+          right: 10px;
+          top: 50%;
+          transform: translateY(-50%);
+          color: #5788fe;
+          font-weight: bold;
+          font-size: 16px;
+        }
+      }
+    }
+
+    .el-table__empty-block {
+      min-height: 200px;
+      display: flex;
+      align-items: center;
+      justify-content: center;
+    }
+  }
+}
+
+// 绌虹姸鎬佷紭鍖�
+.empty-message {
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  padding: 40px 20px;
+  color: #909399;
+
+  i {
+    font-size: 48px;
+    margin-bottom: 12px;
+    color: #c0c4cc;
+  }
+
+  span {
+    font-size: 14px;
+    color: #c0c4cc;
+  }
+
+  .empty-tips {
+    margin-top: 8px;
+    font-size: 12px;
+    color: #dcdfe6;
+  }
+}
+
+// 搴曢儴鎸夐挳鍖哄煙
+.dialog-footer {
+  display: flex;
+  justify-content: flex-end;
+  padding: 20px 0 0;
+  border-top: 1px solid #f0f0f0;
+  margin-top: 20px;
+
+  .el-button {
+    min-width: 80px;
+    height: 36px;
+    border-radius: 4px;
+    font-size: 14px;
+
+    &.el-button--default {
+      color: #666;
+      border-color: #dcdfe6;
+
+      &:hover {
+        color: #5788fe;
+        border-color: #5788fe;
+        background-color: #f0f5ff;
+      }
+    }
+
+    &.el-button--primary {
+      background: linear-gradient(135deg, #5788fe, #7aa1ff);
+      border-color: #5788fe;
+
+      &:hover {
+        background: linear-gradient(135deg, #4a7cfe, #6b94ff);
+        border-color: #4a7cfe;
+      }
+
+      &:active {
+        background: linear-gradient(135deg, #3d70fe, #5e87ff);
+        border-color: #3d70fe;
+      }
+
+      &.is-loading {
+        position: relative;
+        pointer-events: none;
+
+        &::after {
+          content: "";
+          position: absolute;
+          right: 10px;
+          top: 50%;
+          transform: translateY(-50%);
+          width: 16px;
+          height: 16px;
+          border: 2px solid transparent;
+          border-top-color: white;
+          border-radius: 50%;
+          animation: loading-rotate 1s linear infinite;
+        }
+      }
+    }
+  }
+}
+
+// 鍔犺浇鍔ㄧ敾
+@keyframes loading-rotate {
+  0% {
+    transform: translateY(-50%) rotate(0deg);
+  }
+  100% {
+    transform: translateY(-50%) rotate(360deg);
+  }
+}
+
+// 鍝嶅簲寮忚皟鏁�
+@media screen and (max-width: 1200px) {
+  .batch-patient-section,
+  .batch-task-section {
+    margin-bottom: 20px;
+  }
+
+  .el-row {
+    flex-wrap: wrap;
+  }
+
+  .el-col-12 {
+    width: 100%;
+  }
+}
+
+// 浠诲姟鍒楄〃閫変腑鎻愮ず
+.task-selected-hint {
+  margin-top: 8px;
+  font-size: 12px;
+  color: #5788fe;
+  display: flex;
+  align-items: center;
+
+  i {
+    margin-right: 4px;
+    font-size: 14px;
+  }
+
+  &.selected {
+    color: #67c23a;
+  }
+}
+
+// 寮圭獥婊氬姩浼樺寲
+.el-dialog__wrapper {
+  .el-dialog {
+    border-radius: 8px;
+    overflow: hidden;
+    box-shadow: 0 4px 20px rgba(87, 136, 254, 0.1);
+
+    .el-dialog__body {
+      max-height: 70vh;
+      overflow-y: auto;
+
+      &::-webkit-scrollbar {
+        width: 6px;
+      }
+
+      &::-webkit-scrollbar-track {
+        background: #f5f5f5;
+        border-radius: 3px;
+      }
+
+      &::-webkit-scrollbar-thumb {
+        background: #c0c4cc;
+        border-radius: 3px;
+
+        &:hover {
+          background: #a0a4ab;
+        }
+      }
+    }
+  }
 }
 </style>
diff --git a/src/views/patient/patient/hospital.vue b/src/views/patient/patient/hospital.vue
index 6961289..bde9c2b 100644
--- a/src/views/patient/patient/hospital.vue
+++ b/src/views/patient/patient/hospital.vue
@@ -121,6 +121,18 @@
           </el-col> -->
           <el-col :span="1.5">
             <el-button
+              type="warning"
+              plain
+              icon="el-icon-plus"
+              size="medium"
+              :disabled="multiple"
+              @click="handleBatchAddTask"
+            >
+              娣诲姞寤剁画鎶ょ悊浠诲姟
+            </el-button>
+          </el-col>
+          <el-col :span="1.5">
+            <el-button
               type="danger"
               plain
               icon="el-icon-delete"
@@ -323,7 +335,172 @@
         />
       </el-col>
     </el-row>
+    <!-- 鎵归噺娣诲姞浠诲姟寮圭獥 -->
+    <!-- 鎵归噺娣诲姞寤剁画鎶ょ悊浠诲姟寮圭獥 -->
+    <el-dialog
+      title="鎵归噺娣诲姞寤剁画鎶ょ悊"
+      :visible.sync="batchTaskVisible"
+      width="90%"
+      append-to-body
+      class="batch-dialog"
+      :close-on-click-modal="false"
+    >
+      <el-row :gutter="20">
+        <!-- 宸︿晶锛氶�変腑鎮h�呭垪琛� -->
+        <el-col :span="12">
+          <div class="batch-patient-section">
+            <div class="section-header">
+              <h4>閫変腑鎮h��</h4>
+              <span class="patient-count">{{ selectedPatients.length }}浜�</span>
+            </div>
+            <el-table
+              :data="selectedPatients"
+              border
+              style="width: 100%"
+              size="small"
+              :row-class-name="tableRowClassName"
+              :header-cell-style="{ background: '#F5F7FA', color: '#606266' }"
+            >
+              <el-table-column
+                prop="patname"
+                label="濮撳悕"
+                width="100"
+                align="center"
+              />
+              <el-table-column
+                prop="sex"
+                label="鎬у埆"
+                width="80"
+                align="center"
+              >
+                <template slot-scope="scope">
+                  <el-tag
+                    size="small"
+                    :type="scope.row.sex === 1 ? 'primary' : 'danger'"
+                  >
+                    {{ scope.row.sex === 1 ? "鐢�" : "濂�" }}
+                  </el-tag>
+                </template>
+              </el-table-column>
+              <el-table-column
+                label="鍏ラ櫌鏃堕棿"
+                align="center"
+                key="starttime"
+                prop="starttime"
+                width="120"
+              >
+                <template slot-scope="scope">
+                  <span class="time-text">{{
+                    formatTime(scope.row.starttime)
+                  }}</span>
+                </template>
+              </el-table-column>
+              <el-table-column
+                prop="inhospno"
+                label="浣忛櫌鍙�"
+                width="120"
+                align="center"
+              />
+              <el-table-column prop="deptname" label="绉戝" align="center" />
+              <el-table-column
+                prop="leavehospitaldistrictname"
+                label="鐥呭尯"
+                align="center"
+              />
+            </el-table>
+          </div>
+        </el-col>
 
+        <!-- 鍙充晶锛氫换鍔″垪琛� -->
+        <el-col :span="12">
+          <div class="batch-task-section">
+            <div class="section-header">
+              <h4>寤剁画鎶ょ悊浠诲姟</h4>
+              <div v-if="selectedTask" class="task-selected-hint selected">
+                <i class="el-icon-success"></i>
+                <span>宸查�夋嫨锛歿{ selectedTask.taskName }}</span>
+              </div>
+              <div v-else class="task-selected-hint">
+                <i class="el-icon-info"></i>
+                <span>璇风偣鍑婚�夋嫨涓�涓换鍔�</span>
+              </div>
+            </div>
+            <el-table
+              :data="taskList"
+              border
+               height="680"
+              style="width: 100%"
+              size="small"
+              @current-change="handleTaskSelectionChange"
+              highlight-current-row
+              :row-class-name="taskRowClassName"
+              :header-cell-style="{ background: '#F5F7FA', color: '#606266' }"
+              :current-row-key="selectedTask ? selectedTask.taskid : ''"
+            >
+              <el-table-column
+                label="浠诲姟鍚嶇О"
+                fixed
+                align="center"
+                key="taskName"
+                prop="taskName"
+                :show-overflow-tooltip="true"
+                width="180"
+              />
+
+              <el-table-column
+                label="鏈嶅姟椤圭洰"
+                align="center"
+                key="templatename"
+                prop="templatename"
+                :show-overflow-tooltip="true"
+              />
+
+              <el-table-column
+                label="鍒涘缓浜�"
+                align="center"
+                key="createBy"
+                prop="createBy"
+                :show-overflow-tooltip="true"
+              />
+              <el-table-column
+                label="鍒涘缓鏃堕棿"
+                sortable
+                align="center"
+                prop="createTime"
+              >
+                <template slot-scope="scope">
+                  <span class="time-text">{{
+                    formatTime(scope.row.createTime)
+                  }}</span>
+                </template>
+              </el-table-column>
+              <template #empty>
+                <div class="empty-message">
+                  <i class="el-icon-document"></i>
+                  <span>鏆傛棤鍙敤寤剁画鎶ょ悊浠诲姟</span>
+                  <span class="empty-tips">璇疯仈绯荤鐞嗗憳鍒涘缓浠诲姟</span>
+                </div>
+              </template>
+            </el-table>
+          </div>
+        </el-col>
+      </el-row>
+
+      <!-- 搴曢儴鎸夐挳 -->
+      <div slot="footer" class="dialog-footer">
+        <el-button @click="batchTaskVisible = false" :disabled="batchLoading"
+          >鍙� 娑�</el-button
+        >
+        <el-button
+          type="primary"
+          :loading="batchLoading"
+          @click="submitBatchTask"
+          :disabled="!selectedTask || batchLoading"
+        >
+          {{ batchLoading ? "鍒涘缓涓�..." : "鍒涘缓寤剁画鎶ょ悊浠诲姟" }}
+        </el-button>
+      </div>
+    </el-dialog>
     <!-- 鐢ㄦ埛瀵煎叆瀵硅瘽妗� -->
     <el-dialog
       :title="upload.title"
@@ -435,7 +612,7 @@
 import Treeselect from "@riophae/vue-treeselect";
 import { listDept } from "@/api/system/dept";
 import "@riophae/vue-treeselect/dist/vue-treeselect.css";
-import { query360PatInfo } from "@/api/AiCentre/index";
+import { query360PatInfo, getTasklist, addSubtask } from "@/api/AiCentre/index";
 
 import store from "@/store";
 
@@ -470,6 +647,12 @@
       // 榛樿瀵嗙爜
       initPassword: undefined,
       amendtag: false, //鏄惁淇敼
+      // 鎵归噺浠诲姟鐩稿叧鏁版嵁
+      batchTaskVisible: false, // 寮圭獥鍙鎬�
+      selectedPatients: [], // 閫変腑鐨勬偅鑰呭垪琛�
+      taskList: [], // 浠诲姟鍒楄〃
+      selectedTask: null, // 閫変腑鐨勪换鍔�
+      batchLoading: false, // 鎵归噺鎻愪氦鍔犺浇鐘舵��
       // 鏃ユ湡鑼冨洿
       dateRange: [],
       source: [
@@ -630,6 +813,9 @@
     this.queryParams.leaveldeptcodes = store.getters.belongDepts.map(
       (obj) => obj.deptCode
     );
+    this.queryParams.leavehospitaldistrictcodes = store.getters.belongWards.map(
+      (obj) => obj.districtCode
+    );
     this.getList();
     // this.listDept();
     this.gettabList();
@@ -665,6 +851,162 @@
           this.$modal.msgWarning("360鏌ヨ鏃犵粨鏋�");
         }
       });
+    },
+    /** 鎵归噺娣诲姞浠诲姟鎸夐挳鐐瑰嚮 */
+    handleBatchAddTask() {
+      // 鏍¢獙鏄惁閫変腑鎮h��
+      if (this.ids.length === 0) {
+        this.$modal.msgWarning("璇疯嚦灏戦�変腑1鍚嶆偅鑰�");
+        return;
+      }
+
+      // 鑾峰彇閫変腑鎮h�呯殑绉戝淇℃伅
+      const patientDepts = new Set();
+      let deptcode = "";
+      this.ids.forEach((patId) => {
+        const patient = this.userList.find((item) => item.patid === patId);
+        if (patient) {
+          patientDepts.add(patient.deptname);
+          deptcode = patient.deptcode;
+        }
+      });
+
+      // 鑾峰彇閫変腑鎮h�呭垪琛�
+      this.selectedPatients = this.userList.filter((item) =>
+        this.ids.includes(item.patid)
+      );
+
+      // 鏄剧ず寮圭獥
+      this.batchTaskVisible = true;
+
+      // 鑾峰彇浠诲姟鍒楄〃
+      this.loadTaskList(deptcode);
+    },
+    /** 琛ㄦ牸琛屾牱寮� */
+    tableRowClassName({ row, rowIndex }) {
+      if (rowIndex % 2 === 0) {
+        return "even-row";
+      } else {
+        return "odd-row";
+      }
+    },
+
+    /** 浠诲姟琛ㄦ牸琛屾牱寮� */
+    taskRowClassName({ row, rowIndex }) {
+      if (rowIndex % 2 === 0) {
+        return "task-even-row";
+      } else {
+        return "task-odd-row";
+      }
+    },
+    /** 鍔犺浇浠诲姟鍒楄〃 */
+    loadTaskList(deptcode) {
+      this.batchLoading = true;
+      let topqueryParams = {
+        pageNum: 1,
+        pageSize: 100, // 璁剧疆杈冨ぇ鐨勫垎椤佃幏鍙栨洿澶氫换鍔�
+        type: 2, // 鏍规嵁瀹為檯鎯呭喌璋冩暣
+      };
+
+      getTasklist(topqueryParams)
+        .then((response) => {
+          this.taskList = response.rows;
+          this.batchLoading = false;
+
+          if (this.taskList.length === 0) {
+            this.$modal.msgWarning("褰撳墠绉戝鏃犲彲鐢ㄤ换鍔�");
+          }
+        })
+        .catch((error) => {
+          this.$modal.msgError("鑾峰彇浠诲姟鍒楄〃澶辫触锛�" + error.message);
+          this.batchLoading = false;
+        });
+    },
+
+    /** 澶勭悊浠诲姟閫夋嫨鍙樺寲 */
+    handleTaskSelectionChange(currentRow) {
+      this.selectedTask = currentRow;
+    },
+
+    /** 鎵归噺鎻愪氦浠诲姟 */
+    async submitBatchTask() {
+      // 鏍¢獙鏄惁閫変腑浠诲姟
+      if (!this.selectedTask) {
+        this.$modal.msgWarning("璇烽�夋嫨1涓换鍔�");
+        return;
+      }
+
+      this.batchLoading = true;
+      const successPatients = [];
+      const failedPatients = [];
+      const errorMessages = [];
+
+      try {
+        // 閬嶅巻閫変腑鐨勬偅鑰咃紝閫愪釜璋冪敤鎺ュ彛
+        for (const patient of this.selectedPatients) {
+          const params = {
+            taskid: this.selectedTask.taskid,
+            type: this.selectedTask.type,
+            taskName: this.selectedTask.taskName,
+            serviceType: 99,
+            preachform: this.selectedTask.preachform,
+            templateid: this.selectedTask.templateid,
+            libtemplateid: this.selectedTask.libtemplateid,
+            sendstate: 2,
+            continueFlag: 2,
+            ...patient,
+            sendname: patient.patname,
+            starttime: patient.starttime ? patient.starttime + " 00:00:00" : "",
+            endtime: patient.endtime ? patient.endtime + " 00:00:00" : "",
+            leavediagname: patient.leavediagname || patient.diagname || "",
+            age: patient.age || "",
+          };
+
+          try {
+            const response = await addSubtask(params);
+            if (response.code === 200) {
+              successPatients.push(patient.patname);
+            } else {
+              failedPatients.push(patient.patname);
+              errorMessages.push(
+                `${patient.patname}: ${response.msg || "娣诲姞澶辫触"}`
+              );
+            }
+          } catch (error) {
+            failedPatients.push(patient.patname);
+            errorMessages.push(
+              `${patient.patname}: ${error.message || "缃戠粶閿欒"}`
+            );
+          }
+        }
+
+        // 鏄剧ず澶勭悊缁撴灉
+        if (failedPatients.length === 0) {
+          this.$modal.msgSuccess(
+            `鎴愬姛涓� ${successPatients.length} 鍚嶆偅鑰呮坊鍔犱换鍔
+          );
+        } else {
+          this.$modal.msgWarning(
+            `鎴愬姛娣诲姞 ${successPatients.length} 浜猴紝澶辫触 ${failedPatients.length} 浜恒�俙 +
+              (errorMessages.length > 0
+                ? `澶辫触鍘熷洜锛�${errorMessages.join("; ")}`
+                : "")
+          );
+        }
+
+        this.batchTaskVisible = false;
+        this.getList(); // 鍒锋柊鎮h�呭垪琛�
+      } catch (error) {
+        this.$modal.msgError("鎵归噺娣诲姞浠诲姟杩囩▼涓嚭閿欙細" + error.message);
+      } finally {
+        this.batchLoading = false;
+      }
+    },
+
+    /** 鏍煎紡鍖栨椂闂� */
+    formatTime(time) {
+      if (!time) return "";
+      return time;
     },
     /** 鏌ヨ鏍囩鍒楄〃 */
     gettabList() {
@@ -774,8 +1116,8 @@
         leavehospitaldistrictcodes: [],
       };
       this.queryParams.leaveldeptcodes = store.getters.belongDepts.map(
-      (obj) => obj.deptCode
-    );
+        (obj) => obj.deptCode
+      );
       this.handleQuery();
     },
     // 澶氶�夋閫変腑鏁版嵁
@@ -946,6 +1288,325 @@
   }
 }
 .button-textsc {
-  color: #3664D9;
+  color: #3664d9;
+}
+// 鎵归噺浠诲姟寮圭獥浼樺寲鏍峰紡
+.batch-dialog {
+  .el-dialog__body {
+    padding: 20px 20px 10px;
+  }
+
+  .el-dialog__header {
+    background: linear-gradient(135deg, #5788fe, #7aa1ff);
+    padding: 15px 20px;
+
+    .el-dialog__title {
+      color: white;
+      font-weight: 600;
+      font-size: 16px;
+    }
+
+    .el-dialog__headerbtn {
+      .el-dialog__close {
+        color: white;
+        font-size: 18px;
+
+        &:hover {
+          color: #f0f0f0;
+        }
+      }
+    }
+  }
+}
+
+// 寮圭獥鍐呭鍖哄煙
+.batch-patient-section,
+.batch-task-section {
+  h4 {
+    margin: 0 0 12px 0;
+    color: #333;
+    font-size: 16px;
+    font-weight: 600;
+    padding-left: 8px;
+    border-left: 4px solid #5788fe;
+    display: flex;
+    align-items: center;
+
+    &::before {
+      content: "";
+      display: inline-block;
+      width: 6px;
+      height: 6px;
+      background-color: #5788fe;
+      border-radius: 50%;
+      margin-right: 8px;
+    }
+  }
+
+  .section-header {
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+    margin-bottom: 12px;
+
+    .patient-count {
+      color: #5788fe;
+      font-weight: 500;
+      background: #f0f5ff;
+      padding: 4px 12px;
+      border-radius: 12px;
+      font-size: 13px;
+    }
+  }
+}
+
+// 鎮h�呰〃鏍间紭鍖�
+.batch-patient-section {
+  .el-table {
+    border: 1px solid #e8eaec;
+    border-radius: 6px;
+    overflow: hidden;
+
+    .el-table__header-wrapper {
+      th {
+        background-color: #f5f7fa;
+        color: #606266;
+        font-weight: 600;
+        height: 40px;
+      }
+    }
+
+    .el-table__body-wrapper {
+      tr:hover > td {
+        background-color: #f5f9ff;
+      }
+    }
+  }
+}
+
+// 浠诲姟琛ㄦ牸浼樺寲
+.batch-task-section {
+  .el-table {
+    border: 1px solid #e8eaec;
+    border-radius: 6px;
+    overflow: hidden;
+
+    .el-table__header-wrapper {
+      th {
+        background-color: #f5f7fa;
+        color: #606266;
+        font-weight: 600;
+        height: 40px;
+      }
+    }
+
+    .el-table__body-wrapper {
+      tr {
+        cursor: pointer;
+        transition: all 0.3s;
+
+        &:hover > td {
+          background-color: #f5f9ff;
+        }
+
+        // 閫変腑琛屾牱寮�
+        &.current-row {
+          td {
+            background-color: #e8f1ff !important;
+            border-left: 3px solid #5788fe;
+
+            &:first-child {
+              border-left: none;
+            }
+          }
+        }
+      }
+
+      .selected-row {
+        position: relative;
+
+        &::after {
+          content: "鉁�";
+          position: absolute;
+          right: 10px;
+          top: 50%;
+          transform: translateY(-50%);
+          color: #5788fe;
+          font-weight: bold;
+          font-size: 16px;
+        }
+      }
+    }
+
+    .el-table__empty-block {
+      min-height: 200px;
+      display: flex;
+      align-items: center;
+      justify-content: center;
+    }
+  }
+}
+
+// 绌虹姸鎬佷紭鍖�
+.empty-message {
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  padding: 40px 20px;
+  color: #909399;
+
+  i {
+    font-size: 48px;
+    margin-bottom: 12px;
+    color: #c0c4cc;
+  }
+
+  span {
+    font-size: 14px;
+    color: #c0c4cc;
+  }
+
+  .empty-tips {
+    margin-top: 8px;
+    font-size: 12px;
+    color: #dcdfe6;
+  }
+}
+
+// 搴曢儴鎸夐挳鍖哄煙
+.dialog-footer {
+  display: flex;
+  justify-content: flex-end;
+  padding: 20px 0 0;
+  border-top: 1px solid #f0f0f0;
+  margin-top: 20px;
+
+  .el-button {
+    min-width: 80px;
+    height: 36px;
+    border-radius: 4px;
+    font-size: 14px;
+
+    &.el-button--default {
+      color: #666;
+      border-color: #dcdfe6;
+
+      &:hover {
+        color: #5788fe;
+        border-color: #5788fe;
+        background-color: #f0f5ff;
+      }
+    }
+
+    &.el-button--primary {
+      background: linear-gradient(135deg, #5788fe, #7aa1ff);
+      border-color: #5788fe;
+
+      &:hover {
+        background: linear-gradient(135deg, #4a7cfe, #6b94ff);
+        border-color: #4a7cfe;
+      }
+
+      &:active {
+        background: linear-gradient(135deg, #3d70fe, #5e87ff);
+        border-color: #3d70fe;
+      }
+
+      &.is-loading {
+        position: relative;
+        pointer-events: none;
+
+        &::after {
+          content: "";
+          position: absolute;
+          right: 10px;
+          top: 50%;
+          transform: translateY(-50%);
+          width: 16px;
+          height: 16px;
+          border: 2px solid transparent;
+          border-top-color: white;
+          border-radius: 50%;
+          animation: loading-rotate 1s linear infinite;
+        }
+      }
+    }
+  }
+}
+
+// 鍔犺浇鍔ㄧ敾
+@keyframes loading-rotate {
+  0% {
+    transform: translateY(-50%) rotate(0deg);
+  }
+  100% {
+    transform: translateY(-50%) rotate(360deg);
+  }
+}
+
+// 鍝嶅簲寮忚皟鏁�
+@media screen and (max-width: 1200px) {
+  .batch-patient-section,
+  .batch-task-section {
+    margin-bottom: 20px;
+  }
+
+  .el-row {
+    flex-wrap: wrap;
+  }
+
+  .el-col-12 {
+    width: 100%;
+  }
+}
+
+// 浠诲姟鍒楄〃閫変腑鎻愮ず
+.task-selected-hint {
+  margin-top: 8px;
+  font-size: 12px;
+  color: #5788fe;
+  display: flex;
+  align-items: center;
+
+  i {
+    margin-right: 4px;
+    font-size: 14px;
+  }
+
+  &.selected {
+    color: #67c23a;
+  }
+}
+
+// 寮圭獥婊氬姩浼樺寲
+.el-dialog__wrapper {
+  .el-dialog {
+    border-radius: 8px;
+    overflow: hidden;
+    box-shadow: 0 4px 20px rgba(87, 136, 254, 0.1);
+
+    .el-dialog__body {
+      max-height: 70vh;
+      overflow-y: auto;
+
+      &::-webkit-scrollbar {
+        width: 6px;
+      }
+
+      &::-webkit-scrollbar-track {
+        background: #f5f5f5;
+        border-radius: 3px;
+      }
+
+      &::-webkit-scrollbar-thumb {
+        background: #c0c4cc;
+        border-radius: 3px;
+
+        &:hover {
+          background: #a0a4ab;
+        }
+      }
+    }
+  }
 }
 </style>
diff --git a/src/views/patient/patient/indexls.vue b/src/views/patient/patient/indexls.vue
index 01ed808..7eedda4 100644
--- a/src/views/patient/patient/indexls.vue
+++ b/src/views/patient/patient/indexls.vue
@@ -143,7 +143,7 @@
           value: 4,
           label: "涓嶆墽琛�",
         },
-        {
+         {
           value: 5,
           label: "鍙戦�佸け璐�",
         },
@@ -151,6 +151,10 @@
           value: 6,
           label: "宸插畬鎴�",
         },
+         {
+          value: 7,
+          label: "瓒呮椂",
+        },
       ],
       topicoptionsyj: [
         {
diff --git a/src/views/patient/physical/index.vue b/src/views/patient/physical/index.vue
index 81b4820..8f1eb9e 100644
--- a/src/views/patient/physical/index.vue
+++ b/src/views/patient/physical/index.vue
@@ -355,11 +355,11 @@
           label="搴旈殢璁挎棩鏈�"
           width="200"
           align="center"
-          key="longSendTime"
-          prop="longSendTime"
+          key="visitTime"
+          prop="visitTime"
         >
           <template slot-scope="scope">
-            <span>{{ formatTime(scope.row.longSendTime) }}</span>
+            <span>{{ formatTime(scope.row.visitTime) }}</span>
           </template></el-table-column
         >
         <el-table-column
@@ -824,7 +824,7 @@
           value: 4,
           label: "涓嶆墽琛�",
         },
-        {
+         {
           value: 5,
           label: "鍙戦�佸け璐�",
         },
@@ -832,6 +832,10 @@
           value: 6,
           label: "宸插畬鎴�",
         },
+         {
+          value: 7,
+          label: "瓒呮椂",
+        },
       ],
       topicoptionsyj: [
         {
diff --git a/src/views/patient/propaganda/Missioncreation.vue b/src/views/patient/propaganda/Missioncreation.vue
index a789b74..cfd57e0 100644
--- a/src/views/patient/propaganda/Missioncreation.vue
+++ b/src/views/patient/propaganda/Missioncreation.vue
@@ -82,48 +82,17 @@
                     placeholder="璇疯緭鍏ヤ换鍔℃弿杩�"
                   />
                 </el-form-item>
-                <el-row>
-                  <el-col :span="20"
-                    ><el-form-item label="閫傜敤绉戝" prop="region">
-                      <el-select
-                        v-model="form.deptcode"
-                        style="width: 400px"
-                        size="medium"
-                        filterable
-                        placeholder="璇烽�夋嫨绉戝"
-                      >
-                        <el-option
-                          class="ruleFormaa"
-                          v-for="item in belongDepts"
-                          :key="item.deptCode"
-                          :label="item.deptName"
-                          :value="item.deptCode"
-                        >
-                        </el-option>
-                      </el-select> </el-form-item
-                  ></el-col>
-                </el-row>
-                <el-row>
-                  <el-col :span="20"
-                    ><el-form-item label="閫傜敤鐥呭尯" prop="region">
-                      <el-select
-                        v-model="form.leavehospitaldistrictcode"
-                        style="width: 400px"
-                        size="medium"
-                        filterable
-                        placeholder="璇烽�夋嫨鐥呭尯"
-                      >
-                        <el-option
-                          class="ruleFormaa"
-                          v-for="item in belongWards"
-                          :key="item.districtCode"
-                          :label="item.districtName"
-                          :value="item.districtCode"
-                        >
-                        </el-option>
-                      </el-select> </el-form-item
-                  ></el-col>
-                </el-row>
+                <el-form-item label="鏈嶅姟褰㈠紡">
+                  <SortCheckbox
+                    v-model="checkList"
+                    :options="checkboxlist"
+                    :initialselectedOrder="selectedOrder"
+                    value-key="value"
+                    label-key="label"
+                    @change="checkSelectionChange"
+                  />
+                </el-form-item>
+
                 <el-form-item label="鎵ц鍛ㄦ湡" prop="longTask">
                   <el-radio-group v-model="form.longTask">
                     <el-radio :label="0">鑷畾涔夊懆鏈�</el-radio>
@@ -253,27 +222,116 @@
                       /> </el-form-item
                   ></el-col>
                 </el-row>
-                <!-- <el-form-item label="鏈嶅姟褰㈠紡">
-                  <el-checkbox-group v-model="checkList">
-                    <el-checkbox
-                      v-for="(item, index) in checkboxlist"
-                      :key="index"
-                      :label="item.value"
-                    >
-                      {{ item.label }}</el-checkbox
-                    >
-                  </el-checkbox-group>
-                </el-form-item> -->
-                <el-form-item label="鏈嶅姟褰㈠紡">
-                  <SortCheckbox
-                    v-model="checkList"
-                    :options="checkboxlist"
-                    :initialselectedOrder="selectedOrder"
-                    value-key="value"
-                    label-key="label"
-                    @change="checkSelectionChange"
-                  />
+
+                <el-form-item label="浠诲姟鍏宠仈" prop="longTask">
+                  <el-radio-group v-model="form.appltype">
+                    <el-radio label="1">绉戝鍏宠仈</el-radio>
+                    <el-radio label="2">鐥呭尯鍏宠仈</el-radio>
+                    <el-radio label="3">鐤剧梾鍏宠仈</el-radio>
+                    <el-radio label="4">鎵嬫湳鍏宠仈</el-radio>
+                  </el-radio-group>
                 </el-form-item>
+                <el-row v-if="form.appltype == 1">
+                  <el-col :span="20"
+                    ><el-form-item label="閫傜敤绉戝" prop="region">
+                      <el-select
+                        v-model="deptcodesWards"
+                        @remove-tag="removetag"
+                        style="width: 400px"
+                        size="medium"
+                        multiple
+                        filterable
+                        placeholder="璇烽�夋嫨绉戝"
+                      >
+                        <el-option
+                          class="ruleFormaa"
+                          v-for="item in belongDepts"
+                          :label="item.deptName"
+                          :value="item.deptCode"
+                        >
+                        </el-option>
+                      </el-select> </el-form-item
+                  ></el-col>
+                </el-row>
+                <el-row v-if="form.appltype == 2">
+                  <el-col :span="20"
+                    ><el-form-item label="閫傜敤鐥呭尯" prop="region">
+                      <el-select
+                        v-model="leavehospitaldistrictcodes"
+                        style="width: 400px"
+                        @remove-tag="removehpsp"
+                        size="medium"
+                        multiple
+                        filterable
+                        placeholder="璇烽�夋嫨鐥呭尯"
+                      >
+                        <el-option
+                          class="ruleFormaa"
+                          v-for="item in belongWards"
+                          :label="item.districtName"
+                          :value="item.districtCode"
+                        >
+                        </el-option>
+                      </el-select> </el-form-item
+                  ></el-col>
+                </el-row>
+                <el-row v-if="form.appltype == 3">
+                  <div class="xinz-infs">
+                    <el-form-item>
+                      <template #label>
+                        <el-tooltip
+                          class="item"
+                          effect="light"
+                          content="閫夋嫨濂介�傜敤鐤剧梾鍚庯紝鍙互鏂逛究鎮ㄩ�氳繃鐤剧梾璇婃柇鏌ユ壘鍒板搴旂殑鐥呬汉!"
+                          placement="top-start"
+                        >
+                          <i class="el-icon-warning-outline"></i>
+                        </el-tooltip>
+                      </template>
+                      <div style="margin-bottom: 10px">
+                        <el-button
+                          type="warning"
+                          @click="$refs.child.handleAddpatient()"
+                          >娣诲姞鐤剧梾璇婃柇</el-button
+                        >
+                      </div>
+                      <el-tag
+                        v-for="tag in diagglist"
+                        @close="removediagg(tag.icd10code)"
+                        type="warning"
+                        closable
+                        :disable-transitions="false"
+                      >
+                        {{ tag.icdname }}
+                      </el-tag>
+                      <!-- <el-tag v-if="hasMore" type="info">+{{ remaining }} more</el-tag> -->
+                    </el-form-item>
+                  </div>
+                </el-row>
+                <el-row v-if="form.appltype == 4">
+                  <el-col :span="20"
+                    ><el-form-item label="閫傜敤鎵嬫湳" prop="region">
+                      <el-select
+                        v-model="operationcodes"
+                        style="width: 400px"
+                        @remove-tag="removeopera"
+                        size="medium"
+                        :remote-method="remoteopcode"
+                        multiple
+                        filterable
+                        remote
+                        placeholder="璇烽�夋嫨鎵嬫湳"
+                      >
+                        <el-option
+                          class="ruleFormaa"
+                          v-for="item in baseoperaList"
+                          :label="item.opdesc"
+                          :value="item.opcode"
+                        >
+                        </el-option>
+                      </el-select> </el-form-item
+                  ></el-col>
+                </el-row>
               </el-form>
             </div>
           </div>
@@ -341,45 +399,6 @@
             <div class="examine-jic">
               <div class="jic-value">
                 <el-row :gutter="20">
-                  <!--鐢ㄦ埛鏁版嵁-->
-                  <!-- <el-form
-                    :model="topqueryParams"
-                    ref="queryForm"
-                    size="small"
-                    :inline="true"
-                    v-show="showSearch"
-                    label-width="98px"
-                  >
-                    <el-form-item label="鎮h�呭悕绉�">
-                      <el-input v-model="topqueryParams.name"></el-input>
-                    </el-form-item>
-
-                    <el-form-item label="灏辫瘖绉戝">
-                      <el-input v-model="topqueryParams.deptName"></el-input>
-                    </el-form-item>
-                    <el-form-item>
-                      <el-button
-                        type="primary"
-                        icon="el-icon-search"
-                        size="medium"
-                        @click="handleQuery"
-                        >鎼滅储</el-button
-                      >
-                      <el-button
-                        icon="el-icon-refresh"
-                        size="medium"
-                        @click="resetQuery"
-                        >閲嶇疆</el-button
-                      >
-                      <el-button
-                        icon="el-icon-upload2"
-                        size="medium"
-                        type="warning"
-                        >褰撳墠鎮h�呬竴閿彂閫�</el-button
-                      >
-                    </el-form-item>
-                  </el-form> -->
-                  <!-- <el-divider></el-divider> -->
                   <el-row :gutter="10" class="mb8">
                     <el-col :span="1.5">
                       <el-select
@@ -402,7 +421,7 @@
                         icon="el-icon-plus"
                         size="medium"
                         :disabled="!patientqueryParams.allhosp"
-                        @click="handleAddpatient"
+                        @click="handleQuery"
                         >鏂板</el-button
                       >
                     </el-col>
@@ -485,6 +504,18 @@
               <el-form-item label="鎮h�咃細">
                 <el-input
                   v-model="patientqueryParams.name"
+                  @keyup.enter.native="handleQuery"
+                ></el-input>
+              </el-form-item>
+              <el-form-item label="鎮h�呰瘖鏂細">
+                <el-input
+                  v-model="patientqueryParams.leavediagname"
+                  @keyup.enter.native="handleQuery"
+                ></el-input>
+              </el-form-item>
+              <el-form-item label="涓绘不鍖荤敓锛�">
+                <el-input
+                  v-model="patientqueryParams.drname"
                   @keyup.enter.native="handleQuery"
                 ></el-input>
               </el-form-item>
@@ -733,7 +764,7 @@
                 <el-button
                   icon="el-icon-refresh"
                   size="medium"
-                  @click="resetQuery"
+                  @click="resetQuerymb"
                   >閲嶇疆</el-button
                 >
               </el-form-item>
@@ -760,6 +791,13 @@
         </div>
       </div>
     </el-drawer>
+    <Optional-Form
+      ref="child"
+      :dialogVisiblepatient="dialogVisiblepatientjb"
+      :overallCase="diagglist"
+      @addoption="dialogVisiblepatientjb = false"
+      @kkoption="dialogVisiblepatientjb = true"
+    />
   </div>
 </template>
 
@@ -770,19 +808,34 @@
 import store from "@/store";
 import {
   getTaskpatientQC,
-  getlibrarylist,
-  getFollowuplist,
+  taskoperhospgetsondel,
+  taskdiaghospgetsondel,
+  getillnesslist,
+  getbaseopera,
+  Externallist,
   getQtemplatelist,
+  getQtemplateobj,
+  taskgetQtemplateobj,
   TaskQuestioncomit,
-  getTaskInfo,
-  gethetaskinfo,
-  delhetaskinfo,
+  deleteTaskQuestioncomit,
+  Questionnairetaskgetson,
+  getTaskQuestioncomit,
+  depthospgetson,
+  getillness,
   Editsingletask,
+  getQtemplateclassify,
+  taskdepthospgetsondel,
+  taskdepthospgetsonlist,
+  taskdiaggetlist,
+  taskopergetlist,
+  getTaskInfo,
   getheLibraryAssort,
+  getlibrarylist,
 } from "@/api/AiCentre/index";
 import { listDept } from "@/api/system/dept";
 import { getToken } from "@/utils/auth";
 import SFtable from "@/components/SFtable"; //琛ㄦ牸缁勪欢
+import OptionalForm from "@/components/OptionalForm";
 import SortCheckbox from "@/components/SortCheckbox"; //琛ㄦ牸缁勪欢
 
 export default {
@@ -798,6 +851,7 @@
       libName: "",
       overallCase: [], //閫夋嫨鎮h�呮��
       allpids: [],
+      diagglist: [],
       libId: null, //妯℃澘搴撴ā鏉縤d
       Editprogress: 1, //缂栬緫杩涘害
       drawermb: false, //閫夋嫨妯℃澘寮圭獥
@@ -805,15 +859,20 @@
       loading: false, // 閬僵灞�
       patientloading: false, // 閬僵灞�
       dialogVisiblepatient: false, //娣诲姞鎮h�呭脊妗�
+      dialogVisiblepatientjb: false, //娣诲姞鐤剧梾寮规
       radio: 1,
       checkboxlist: [],
       selectedOrder: [],
+      baseoperaList: [],
       // 绉戝/鐥呭尯
-      belongWards: [],
       belongWards: [],
       tableLabel: [],
       questionList: [],
       uploadingData: [],
+      deptcodesWards: [], //绉戝鏁版嵁
+      leavehospitaldistrictcodes: [], //鐥呭尯鏁版嵁
+      operationcodes: [], //鎵嬫湳鏁版嵁
+      illnesscodes: [], //鐤剧梾鏁版嵁
       htmlRichText: "<p>Hello, <strong>world</strong>!</p>",
       // 鎮h�呰〃鍗�
       tableLabelhz: [
@@ -900,6 +959,8 @@
       patientqueryParams: {
         pageNum: 1, //
         pageSize: 10,
+        leavehospitaldistrictcodes: [],
+        leaveldeptcodes: [],
       },
       topicoptions: [{ children: [{ children: [] }] }],
       showSearch: true, //
@@ -965,6 +1026,8 @@
       ],
       tasktopic: null, //鏂板绫诲瀷
       SelectPatientslist: [],
+      belongDepts: [],
+
       form: {
         patTaskRelevances: [],
         sendType: 1,
@@ -1021,7 +1084,7 @@
       quote: false,
     };
   },
-  components: { SFtable, SortCheckbox },
+  components: { SFtable, OptionalForm, SortCheckbox },
 
   created() {
     this.id = this.$route.query.id;
@@ -1145,20 +1208,20 @@
       }
     },
     // 淇濆瓨
-   async submitForm(formName) {
+    async submitForm(formName) {
       this.form.preachform = this.checkList.join(",");
       // this.formatFn(1);
-  if (!this.form.patTaskRelevances[0] && this.form.longTask == 0) {
-    try {
-      // 绛夊緟鐢ㄦ埛纭
-      await this.$modal.confirm("褰撳墠浠诲姟鏈�夋嫨鎮h�呮槸鍚︿繚瀛橈紵");
-      // 鍙湁鐢ㄦ埛鐐瑰嚮鈥滅‘璁も�濆悗锛屼唬鐮佹墠浼氭墽琛屽埌杩欓噷
-    } catch (error) {
-      // 鐢ㄦ埛鐐瑰嚮浜嗏�滃彇娑堚�濓紝鐩存帴涓柇鍑芥暟鎵ц
-      this.$modal.msgWarning("鎿嶄綔宸插彇娑�");
-      return; // 鍏抽敭锛氳繖閲宺eturn鐩存帴閫�鍑哄嚱鏁�
-    }
-  }
+      if (!this.form.patTaskRelevances[0] && this.form.longTask == 0) {
+        try {
+          // 绛夊緟鐢ㄦ埛纭
+          await this.$modal.confirm("褰撳墠浠诲姟鏈�夋嫨鎮h�呮槸鍚︿繚瀛橈紵");
+          // 鍙湁鐢ㄦ埛鐐瑰嚮鈥滅‘璁も�濆悗锛屼唬鐮佹墠浼氭墽琛屽埌杩欓噷
+        } catch (error) {
+          // 鐢ㄦ埛鐐瑰嚮浜嗏�滃彇娑堚�濓紝鐩存帴涓柇鍑芥暟鎵ц
+          this.$modal.msgWarning("鎿嶄綔宸插彇娑�");
+          return; // 鍏抽敭锛氳繖閲宺eturn鐩存帴閫�鍑哄嚱鏁�
+        }
+      }
       if (!this.form.templatename) {
         this.$modal.msgError("鏈�夋嫨妯℃澘");
         return;
@@ -1170,6 +1233,36 @@
         this.$modal.msgError("璇烽�夋嫨鏈嶅姟绫诲瀷");
         this.submitLoading = false;
 
+        return;
+      }
+      if (this.form.appltype == 1) {
+        this.leavehospitaldistrictcodes = [];
+        this.operationcodes = [];
+        this.illnesscodes = [];
+      } else if (this.form.appltype == 2) {
+        this.deptcodesWards = [];
+        this.operationcodes = [];
+        this.illnesscodes = [];
+      } else if (this.form.appltype == 3) {
+        this.deptcodesWards = [];
+        this.leavehospitaldistrictcodes = [];
+        this.operationcodes = [];
+      } else if (this.form.appltype == 4) {
+        this.deptcodesWards = [];
+        this.illnesscodes = [];
+        this.leavehospitaldistrictcodes = [];
+      }
+      if (
+        this.deptcodesWards[0] ||
+        this.leavehospitaldistrictcodes[0] ||
+        this.diagglist[0] ||
+        this.operationcodes[0] ||
+        this.form.longTask == 2 ||
+        this.serviceType == 3
+      ) {
+      } else {
+        this.$modal.msgError("璇烽�夋嫨浠诲姟鍏宠仈鏉′欢");
+        this.submitLoading = false;
         return;
       }
       const filteredArray = this.variableList.filter(
@@ -1187,12 +1280,13 @@
       if (!this.form.type) {
         this.form.type = this.$route.query.type;
       }
-      this.form.leaveldeptcodes = store.getters.belongDepts.map(
-        (obj) => obj.deptCode
-      );
-      this.form.leavehospitaldistrictcodes = store.getters.belongWards.map(
-        (obj) => obj.districtCode
-      );
+      this.form.deptcode = this.deptcodesWards.join(",");
+      this.form.leavehospitaldistrictcode =
+        this.leavehospitaldistrictcodes.join(",");
+      this.form.opcode = this.operationcodes.join(",");
+      this.form.icd10code = this.diagglist
+        .map((item) => item.icdcode)
+        .join(",");
       Editsingletask(this.form).then((res) => {
         if (res.code == 200) {
           if (this.form.taskid) {
@@ -1437,9 +1531,54 @@
     },
     getList() {},
     handleQuery() {
+      if (this.patientqueryParams.allhosp == 6) {
+        this.Externallist();
+        console.log();
+
+        return;
+      }
+      if (this.patientqueryParams.searchscope == 1) {
+        this.patientqueryParams.leaveldeptcodes = store.getters.belongDepts.map(
+          (obj) => obj.deptCode
+        );
+        this.patientqueryParams.leavehospitaldistrictcodes = [];
+      } else if (this.patientqueryParams.searchscope == 2) {
+        this.patientqueryParams.leavehospitaldistrictcodes =
+          store.getters.belongWards.map((obj) => obj.districtCode);
+        this.patientqueryParams.leaveldeptcodes = [];
+      } else {
+        this.patientqueryParams.leaveldeptcodes = store.getters.belongDepts.map(
+          (obj) => obj.deptCode
+        );
+        this.patientqueryParams.leavehospitaldistrictcodes =
+          store.getters.belongWards.map((obj) => obj.districtCode);
+      }
+      if (
+        !this.patientqueryParams.leavehospitaldistrictcodes ||
+        !this.patientqueryParams.leavehospitaldistrictcodes[0]
+      )
+        this.patientqueryParams.leavehospitaldistrictcodes = null;
+      if (
+        !this.patientqueryParams.leaveldeptcodes ||
+        !this.patientqueryParams.leaveldeptcodes[0]
+      )
+        this.patientqueryParams.leaveldeptcodes = null;
       this.handleAddpatient();
     },
-    resetQuery() {},
+    resetQuery() {
+      this.patientqueryParams = {
+        pageNum: 1, //
+        pageSize: 10,
+        topica: 1, //0鍏ㄩ儴1绉戝2鐥呭尯
+        leavehospitaldistrictcodes: [],
+        leaveldeptcodes: [],
+      };
+      this.handleQuery();
+    },
+    resetQuerymb() {
+      this.topqueryParams = { svyname: "" };
+      this.handleQuerymb();
+    },
     handleClosehz() {
       this.dialogVisiblepatient = false;
     },
@@ -1517,6 +1656,44 @@
       console.log("褰撳墠閫変腑:", selectedValues);
       console.log("閫変腑椤哄簭:", selectedOrder);
     },
+    getillnesslist() {
+      getillnesslist({
+        pageNum: 1,
+        pageSize: 1000,
+      }).then((res) => {
+        this.donorchargeList = res.rows;
+      });
+      getbaseopera({
+        pageNum: 1,
+        pageSize: 1000,
+      }).then((res) => {
+        this.baseoperaList = res.rows;
+      });
+    },
+    // 鎵嬫湳鏌ヨ
+    remoteopcode(name) {
+      if (name) {
+        getbaseopera({
+          pageNum: 1,
+          pageSize: 1000,
+          opdesc: name,
+        }).then((res) => {
+          this.baseoperaList = res.rows;
+        });
+      }
+    },
+    // 鐤剧梾鏌ヨ
+    remotedonor(name) {
+      if (name) {
+        getbaseopera({
+          pageNum: 1,
+          pageSize: 1000,
+          opdesc: name,
+        }).then((res) => {
+          this.baseoperaList = res.rows;
+        });
+      }
+    },
     // 渚濈収鏂板鏃跺鐞�
     neWaddfn() {
       this.id = null;
@@ -1541,9 +1718,45 @@
     },
     // 鑾峰彇绉戝鍒楄〃
     listDept() {
-      listDept().then((res) => {
-        this.topicoptions = this.handleTree(res.data, "deptId");
-        console.log(this.topicoptions, "topicoptions");
+      this.leavehospitaldistrictcodes = [];
+      this.deptcodesWards = [];
+      this.queryParamsdept.taskId = this.form.taskid;
+      taskdepthospgetsonlist(this.queryParamsdept).then((res) => {
+        if (res.code == 200) {
+          let arr = res.rows;
+          arr.forEach((item) => {
+            if (item.deptType == 1) {
+              this.deptlist.push(item);
+              this.deptcodesWards.push(item.deptCode);
+            } else if (item.deptType == 2) {
+              this.hosplist.push(item);
+              this.leavehospitaldistrictcodes.push(item.deptCode);
+            }
+          });
+        }
+      });
+      taskdiaggetlist(this.queryParamsdept).then((res) => {
+        if (res.code == 200) {
+          let arr = res.rows;
+          arr.forEach((item) => {
+            getillnesslist({
+              icdcode: item.icd10code,
+            }).then((res) => {
+              item.icdname = res.rows[0].icdname;
+              this.diagglist.push(item);
+            });
+            this.illnesscodes.push(item.icd10code);
+          });
+        }
+      });
+      taskopergetlist(this.queryParamsdept).then((res) => {
+        if (res.code == 200) {
+          let arr = res.rows;
+          arr.forEach((item) => {
+            this.operlist.push(item);
+            this.operationcodes.push(item.opcode);
+          });
+        }
       });
     },
     // 鏂板娲鹃�佹偅鑰�
@@ -1649,7 +1862,7 @@
       TaskQuestioncomit(this.Tasktemplate).then((response) => {
         console.log(response);
         this.previewtf = false;
-        this.drawermb =false;
+        this.drawermb = false;
         this.form.templateid = response.data;
         this.form.libtemplateid = this.libId;
         this.form.templatename = this.libName;
@@ -1686,6 +1899,65 @@
         this.checkList = list;
       }
     },
+    // 浠诲姟绉戝鍒犻櫎瑙﹀彂
+    removetag(row) {
+      let result = this.deptlist
+        .filter((item) => item.deptCode == row)
+        .map((item) => item.id);
+
+      if (result.length) {
+        taskdepthospgetsondel(result).then((res) => {
+          if (res.code) {
+            this.$modal.msgSuccess("鍒犻櫎鎴愬姛");
+          }
+        });
+      }
+    },
+    // 闄㈠尯鍒犻櫎鍒犻櫎瑙﹀彂
+    removehpsp(row) {
+      let result = this.hosplist
+        .filter((item) => item.deptCode == row)
+        .map((item) => item.id);
+      if (result.length) {
+        taskdepthospgetsondel(result).then((res) => {
+          if (res.code) {
+            this.$modal.msgSuccess("鍒犻櫎鎴愬姛");
+          }
+        });
+      }
+    },
+    // 鎵嬫湳鍒犻櫎瑙﹀彂
+    removeopera(row) {
+      let result = this.operlist
+        .filter((item) => item.opcode == row)
+        .map((item) => item.id);
+      if (result.length) {
+        taskoperhospgetsondel(result).then((res) => {
+          if (res.code) {
+            this.$modal.msgSuccess("鍒犻櫎鎴愬姛");
+          }
+        });
+      }
+    },
+    // 鐤剧梾鍒犻櫎瑙﹀彂
+    removediagg(row) {
+      console.log(row, "row");
+      console.log(this.diagglist, "this.diagglist");
+
+      let result = this.diagglist
+        .filter((item) => item.icd10code == row)
+        .map((item) => item.id);
+      if (result.length) {
+        taskdiaghospgetsondel(result).then((res) => {
+          if (res.code) {
+            this.diagglist = this.diagglist.filter(
+              (item) => item.icd10code != row
+            );
+            this.$modal.msgSuccess("鍒犻櫎鎴愬姛");
+          }
+        });
+      }
+    },
     /** 瀵煎叆鎸夐挳鎿嶄綔 */
     handleImport() {
       this.upload.title = "鐢ㄦ埛瀵煎叆";
diff --git a/src/views/patient/propaganda/QuestionnaireTask.vue b/src/views/patient/propaganda/QuestionnaireTask.vue
index d558652..1b4d397 100644
--- a/src/views/patient/propaganda/QuestionnaireTask.vue
+++ b/src/views/patient/propaganda/QuestionnaireTask.vue
@@ -260,29 +260,6 @@
                   ></el-col>
                 </el-row>
                 <el-row v-if="form.appltype == 3">
-                  <!-- <el-col :span="20"
-                    ><el-form-item label="閫傜敤鐤剧梾" prop="region">
-                      <el-select
-                        v-model="illnesscodes"
-                        style="width: 400px"
-                        @remove-tag="removediagg"
-                        size="medium"
-                        :remote-method="remotedonor"
-                        multiple
-                        filterable
-                        remote
-                        placeholder="璇烽�夋嫨鐥呭尯"
-                      >
-                        <el-option
-                          class="ruleFormaa"
-                          v-for="item in donorchargeList"
-                          :key="item.icdcode"
-                          :label="item.icdname"
-                          :value="item.icdcode"
-                        >
-                        </el-option>
-                      </el-select> </el-form-item
-                  ></el-col> -->
                   <div class="xinz-infs">
                     <el-form-item>
                       <template #label>
@@ -319,12 +296,11 @@
                   <el-col :span="20"
                     ><el-form-item label="閫傜敤鎵嬫湳" prop="region">
                       <el-select
-                        v-model="operationcodes"
+                        v-model="form.oplevelcode"
                         style="width: 400px"
                         @remove-tag="removeopera"
                         size="medium"
                         :remote-method="remoteopcode"
-                        multiple
                         filterable
                         remote
                         placeholder="璇烽�夋嫨鎵嬫湳"
@@ -332,8 +308,8 @@
                         <el-option
                           class="ruleFormaa"
                           v-for="item in baseoperaList"
-                          :label="item.opdesc"
-                          :value="item.opcode"
+                          :label="item.label"
+                          :value="item.value"
                         >
                         </el-option>
                       </el-select> </el-form-item
@@ -917,6 +893,7 @@
   Externallist,
   getQtemplatelist,
   getQtemplateobj,
+  taskgetQtemplateobj,
   TaskQuestioncomit,
   deleteTaskQuestioncomit,
   Questionnairetaskgetson,
@@ -965,14 +942,18 @@
       dialogVisiblepatientjb: false, //娣诲姞鐤剧梾寮规
       deptcodesWards: [], //绉戝鏁版嵁
       leavehospitaldistrictcodes: [], //鐥呭尯鏁版嵁
-      operationcodes: [], //鎵嬫湳鏁版嵁
       illnesscodes: [], //鐤剧梾鏁版嵁
       radio: 1,
       checkboxlist: [],
       tableLabel: [],
       questionList: [],
       donorchargeList: [],
-      baseoperaList: [],
+      baseoperaList: [
+        { value: "1", label: "涓�绾ф墜鏈�" },
+        { value: "2", label: "浜岀骇鎵嬫湳" },
+        { value: "3", label: "涓夌骇鎵嬫湳" },
+        { value: "4", label: "鍥涚骇鎵嬫湳" },
+      ],
       usable: [
         { value: "0", label: "鍙敤" },
         { value: "1", label: "鍋滅敤" },
@@ -1318,6 +1299,10 @@
         this.form.serviceType == 15
       ) {
         this.checkboxlist = [
+           {
+            value: "1",
+            label: "浜哄伐",
+          },
           {
             value: "3",
             label: "鏅鸿兘璇煶",
@@ -1453,16 +1438,16 @@
         ];
         if (this.form.appltype == 1) {
           this.leavehospitaldistrictcodes = [];
-          this.operationcodes = [];
+          this.form.oplevelcode = null;
           this.illnesscodes = [];
         } else if (this.form.appltype == 2) {
           this.deptcodesWards = [];
-          this.operationcodes = [];
+          this.form.oplevelcode = null;
           this.illnesscodes = [];
         } else if (this.form.appltype == 3) {
           this.deptcodesWards = [];
           this.leavehospitaldistrictcodes = [];
-          this.operationcodes = [];
+          this.form.oplevelcode = null;
         } else if (this.form.appltype == 4) {
           this.deptcodesWards = [];
           this.illnesscodes = [];
@@ -1473,24 +1458,22 @@
           this.form.preachformList = this.selectedOrder;
         } else {
           this.$modal.msgError("璇烽�夋嫨鏈嶅姟绫诲瀷");
-            this.submitLoading = false;
+          this.submitLoading = false;
 
           return;
         }
-        console.log(this.operationcodes[0]);
-        console.log(this.operationcodes);
 
         if (
           this.deptcodesWards[0] ||
           this.leavehospitaldistrictcodes[0] ||
           this.diagglist[0] ||
-          this.operationcodes[0] ||
+          this.form.oplevelcode ||
           this.form.longTask == 2 ||
           this.serviceType == 3
         ) {
         } else {
           this.$modal.msgError("璇烽�夋嫨浠诲姟鍏宠仈鏉′欢");
-            this.submitLoading = false;
+          this.submitLoading = false;
           return;
         }
         //鏆傚仠浠诲姟鎮h�呴檺鍒�
@@ -1501,7 +1484,7 @@
 
         if (!this.form.templatename && !this.templateor) {
           this.$modal.msgError("鏈�夋嫨妯℃澘");
-            this.submitLoading = false;
+          this.submitLoading = false;
 
           return;
         }
@@ -1515,7 +1498,7 @@
           this.form.longTask
         ) {
         } else {
-            this.submitLoading = false;
+          this.submitLoading = false;
           return this.$modal.msgError("鏃堕棿淇℃伅缂哄け");
         }
         const filteredArray = this.variableList.filter(
@@ -1535,7 +1518,7 @@
         this.form.deptcode = this.deptcodesWards.join(",");
         this.form.leavehospitaldistrictcode =
           this.leavehospitaldistrictcodes.join(",");
-        this.form.opcode = this.operationcodes.join(",");
+        // this.form.opcode = this.operationcodes.join(",");
         this.form.icd10code = this.diagglist
           .map((item) => item.icdcode)
           .join(",");
@@ -1594,6 +1577,8 @@
     },
     // 棰勮
     previewfnmb() {
+      // taskgetQtemplateobj({ id: this.form.templateid });
+
       getTaskQuestioncomit(this.form.templateid).then((res) => {
         if (res.code == 200) {
           console.log(res, "棰勮鏁版嵁");
@@ -1604,15 +1589,17 @@
           this.getillness(this.form.libtemplateid);
 
           this.previewtf = true;
-          getQtemplateobj({ svyid: this.form.libtemplateid }).then((res) => {
+          taskgetQtemplateobj({ id: this.form.templateid }).then((res) => {
             if (res.code == 200) {
-              this.questionList = res.rows[0].svyTemplateLibScripts;
+              this.questionList = res.data.svyTaskTemplateScriptVOS;
               this.questionList.forEach((item) => {
                 item.qremark = [];
+                item.svyLibTemplateTargetoptions =
+                  item.svyTaskTemplateTargetoptions;
               });
               this.previewtftype = 1;
               this.objyl.svyTemplateLibScripts =
-                res.rows[0].svyTemplateLibScripts;
+                res.data.svyTaskTemplateScriptVOS;
             }
           });
         }
@@ -1656,36 +1643,36 @@
       }).then((res) => {
         this.donorchargeList = res.rows;
       });
-      getbaseopera({
-        pageNum: 1,
-        pageSize: 1000,
-      }).then((res) => {
-        this.baseoperaList = res.rows;
-      });
+      // getbaseopera({
+      //   pageNum: 1,
+      //   pageSize: 1000,
+      // }).then((res) => {
+      //   this.baseoperaList = res.rows;
+      // });
     },
     // 鎵嬫湳鏌ヨ
     remoteopcode(name) {
-      if (name) {
-        getbaseopera({
-          pageNum: 1,
-          pageSize: 1000,
-          opdesc: name,
-        }).then((res) => {
-          this.baseoperaList = res.rows;
-        });
-      }
+      // if (name) {
+      //   getbaseopera({
+      //     pageNum: 1,
+      //     pageSize: 1000,
+      //     opdesc: name,
+      //   }).then((res) => {
+      //     this.baseoperaList = res.rows;
+      //   });
+      // }
     },
     // 鐤剧梾鏌ヨ
     remotedonor(name) {
-      if (name) {
-        getbaseopera({
-          pageNum: 1,
-          pageSize: 1000,
-          opdesc: name,
-        }).then((res) => {
-          this.baseoperaList = res.rows;
-        });
-      }
+      // if (name) {
+      //   getbaseopera({
+      //     pageNum: 1,
+      //     pageSize: 1000,
+      //     opdesc: name,
+      //   }).then((res) => {
+      //     this.baseoperaList = res.rows;
+      //   });
+      // }
     },
     // 澶勭悊闂灞傚彉閲�
     Variablehandling(arr, type) {
@@ -1814,6 +1801,7 @@
           item.patid = item.id;
           item.hospType = this.patientqueryParams.allhosp;
           item.sfzh = item.idcardno;
+          item.telshortcode = item.telshortcode;
           item.deptCode = item.deptcode;
           item.deptName = item.dept;
           item.admindate = item.inhosptime;
@@ -2135,8 +2123,8 @@
     },
     // 鐤剧梾鍒犻櫎瑙﹀彂
     removediagg(row) {
-      console.log(row,'row');
-console.log(this.diagglist,'this.diagglist');
+      console.log(row, "row");
+      console.log(this.diagglist, "this.diagglist");
 
       let result = this.diagglist
         .filter((item) => item.icd10code == row)
@@ -2270,7 +2258,7 @@
               TaskQuestioncomit(this.objyl).then((response) => {
                 this.previewtf = false;
                 this.form.libtemplateid = this.objyl.svyid;
-              this.form.libtemplatename = this.objyl.svyname;
+                this.form.libtemplatename = this.objyl.svyname;
                 this.form.templateid = response.data;
                 this.form.templatename = this.objyl.svyname;
                 this.$modal.msgSuccess("閫夋嫨妯℃澘鎴愬姛");
diff --git a/src/views/patient/propaganda/index.vue b/src/views/patient/propaganda/index.vue
index 1e3369b..2ca5f00 100644
--- a/src/views/patient/propaganda/index.vue
+++ b/src/views/patient/propaganda/index.vue
@@ -259,11 +259,11 @@
           label="搴斿鏁欐棩鏈�"
           width="200"
           align="center"
-          key="longSendTime"
-          prop="longSendTime"
+          key="visitTime"
+          prop="visitTime"
         >
           <template slot-scope="scope">
-            <span>{{ formatTime(scope.row.longSendTime) }}</span>
+            <span>{{ formatTime(scope.row.visitTime) }}</span>
           </template></el-table-column
         >
         <el-table-column
@@ -775,7 +775,7 @@
           value: 4,
           label: "涓嶆墽琛�",
         },
-        {
+         {
           value: 5,
           label: "鍙戦�佸け璐�",
         },
@@ -783,6 +783,10 @@
           value: 6,
           label: "宸插畬鎴�",
         },
+         {
+          value: 7,
+          label: "瓒呮椂",
+        },
       ],
       topicoptionsyj: [
         {
diff --git a/src/views/patient/propaganda/particty.vue b/src/views/patient/propaganda/particty.vue
index 70b06f1..9b982b7 100644
--- a/src/views/patient/propaganda/particty.vue
+++ b/src/views/patient/propaganda/particty.vue
@@ -743,7 +743,7 @@
                     <el-radio
                       v-for="(
                         items, index
-                      ) in item.ivrTaskScriptTargetoptionList"
+                      ) in item.ivrLibaScriptTargetoptionList"
                       :key="index"
                       :label="index"
                       >{{ items.targetvalue }}</el-radio
@@ -765,7 +765,7 @@
                     <el-checkbox
                       v-for="(
                         items, index
-                      ) in item.ivrTaskScriptTargetoptionList"
+                      ) in item.ivrLibaScriptTargetoptionList"
                       :key="index"
                       :label="index"
                     >
@@ -904,6 +904,7 @@
   getbaseopera,
   getFollowuplist,
   getvFollowup,
+  selectInfoByCondition,
   Taskparticty,
   deleteTaskparticty,
   getTaskInfo,
@@ -1308,7 +1309,7 @@
       };
       this.currenttype = this.$route.query.type;
       this.title = "闅忚鍐呭鍒楄〃";
-      this.tableLabel = this.tableLabelwj;
+      this.tableLabel = this.tableLabelwj||[];
       if (this.form.serviceType == 1) {
         this.checkboxlist = [
           {
@@ -1330,6 +1331,10 @@
         ];
       } else if (this.form.serviceType == 6) {
         this.checkboxlist = [
+           {
+            value: "1",
+            label: "浜哄伐",
+          },
           {
             value: "3",
             label: "鏅鸿兘璇煶",
@@ -1477,11 +1482,11 @@
           this.leavehospitaldistrictcodes = [];
         }
         if (this.checkList) {
-          this.form.preachform = this.checkList.join(",");
-          this.form.preachformList = this.selectedOrder;
+          this.form.preachform = this.checkList.join(",")||[];
+          this.form.preachformList = this.selectedOrder||[];
         } else {
           this.$modal.msgError("璇烽�夋嫨鏈嶅姟绫诲瀷");
-            this.submitLoading = false;
+          this.submitLoading = false;
 
           return;
         }
@@ -1496,7 +1501,7 @@
         ) {
         } else {
           this.$modal.msgError("璇烽�夋嫨浠诲姟鍏宠仈鏉′欢");
-            this.submitLoading = false;
+          this.submitLoading = false;
 
           return;
         }
@@ -1507,7 +1512,7 @@
 
         if (!this.form.templatename && !this.templateor) {
           this.$modal.msgError("鏈�夋嫨妯℃澘");
-            this.submitLoading = false;
+          this.submitLoading = false;
 
           return;
         }
@@ -1521,7 +1526,7 @@
           this.form.longTask
         ) {
         } else {
-            this.submitLoading = false;
+          this.submitLoading = false;
 
           return this.$modal.msgError("鏃堕棿淇℃伅缂哄け");
         }
@@ -1610,13 +1615,18 @@
           // 鐤剧梾
           this.getillness(this.form.libtemplateid);
 
-          getvFollowup({ id: this.form.libtemplateid }).then((res) => {
+          selectInfoByCondition({id:this.form.templateid} ).then((res) => {
             if (res.code == 200) {
               this.previewtf = true;
               this.previewtftype = 1;
-              this.questionList = res.data.ivrLibaTemplateScriptVOList;
-              this.objyl.ivrLibaTemplateScriptVOList =
-                res.data.ivrLibaTemplateScriptVOList;
+              this.questionList = res.data.ivrTaskTemplateScriptVOList;
+              this.questionList.forEach((item) => {
+                item.qremark = [];
+                item.ivrLibaScriptTargetoptionList =
+                  item.ivrTaskScriptTargetoptionList;
+              });
+              this.objyl.ivrLibaScriptTargetoptionList =
+                res.data.ivrTaskScriptTargetoptionList;
             } else {
             }
           });
@@ -1930,8 +1940,8 @@
               ? this.form.patTaskRelevances
               : [];
             this.overallCase = this.form.patTaskRelevances.concat();
-            this.checkList = this.form.preachform.split(",");
-            this.selectedOrder = this.form.preachformList;
+            this.checkList = this.form.preachform.split(",") || [];
+            this.selectedOrder = this.form.preachformList||[];
 
             this.overallCase.forEach((item) => {
               if (item.endtime) {
@@ -2201,7 +2211,7 @@
         this.objyl.suitway = this.objyl.suitway.join(",");
       }
       this.objyl.ivrLibaTemplateScriptVOList.forEach((item) => {
-        item.ivrTaskScriptTargetoptionList = item.ivrTaskScriptTargetoptionList;
+        item.ivrTaskScriptTargetoptionList = item.ivrLibaScriptTargetoptionList;
       });
       this.objyl.ivrTaskTemplateScriptVOList =
         this.objyl.ivrLibaTemplateScriptVOList;
@@ -2278,7 +2288,7 @@
       });
     },
     checkSelectionChange(selectedValues, selectedOrder) {
-      this.selectedOrder = selectedValues;
+      this.selectedOrder = selectedValues||[];
       console.log("褰撳墠閫変腑:", selectedValues);
       console.log("閫変腑椤哄簭:", selectedOrder);
     },
@@ -2316,10 +2326,12 @@
               this.objyl.suitway = this.objyl.suitway.join(",");
             }
             this.objyl.templateid = this.objyl.id;
+            this.form.libtemplateid = this.objyl.id;
+
             this.objyl.isoperation = 1;
             this.objyl.ivrLibaTemplateScriptVOList.forEach((item) => {
               item.ivrTaskScriptTargetoptionList =
-                item.ivrTaskScriptTargetoptionList;
+                item.ivrLibaScriptTargetoptionList;
             });
             this.objyl.ivrTaskTemplateScriptVOList =
               this.objyl.ivrLibaTemplateScriptVOList;
diff --git a/src/views/patient/questionnaire/index.vue b/src/views/patient/questionnaire/index.vue
index c1dec41..699d84c 100644
--- a/src/views/patient/questionnaire/index.vue
+++ b/src/views/patient/questionnaire/index.vue
@@ -303,11 +303,11 @@
           label="搴旈殢璁挎棩鏈�"
           width="200"
           align="center"
-          key="longSendTime"
-          prop="longSendTime"
+          key="visitTime"
+          prop="visitTime"
         >
           <template slot-scope="scope">
-            <span>{{ formatTime(scope.row.longSendTime) }}</span>
+            <span>{{ formatTime(scope.row.visitTime) }}</span>
           </template></el-table-column
         >
         <el-table-column
@@ -789,7 +789,7 @@
           value: 4,
           label: "涓嶆墽琛�",
         },
-        {
+         {
           value: 5,
           label: "鍙戦�佸け璐�",
         },
@@ -797,6 +797,10 @@
           value: 6,
           label: "宸插畬鎴�",
         },
+         {
+          value: 7,
+          label: "瓒呮椂",
+        },
       ],
       topicoptionsyj: [
         {
diff --git a/src/views/patient/shadow/index.vue b/src/views/patient/shadow/index.vue
index f5dc402..221c5d7 100644
--- a/src/views/patient/shadow/index.vue
+++ b/src/views/patient/shadow/index.vue
@@ -303,11 +303,11 @@
           label="搴旈殢璁挎棩鏈�"
           width="200"
           align="center"
-          key="longSendTime"
-          prop="longSendTime"
+          key="visitTime"
+          prop="visitTime"
         >
           <template slot-scope="scope">
-            <span>{{ formatTime(scope.row.longSendTime) }}</span>
+            <span>{{ formatTime(scope.row.visitTime) }}</span>
           </template></el-table-column
         >
         <el-table-column
@@ -789,7 +789,7 @@
           value: 4,
           label: "涓嶆墽琛�",
         },
-        {
+         {
           value: 5,
           label: "鍙戦�佸け璐�",
         },
@@ -797,6 +797,10 @@
           value: 6,
           label: "宸插畬鎴�",
         },
+         {
+          value: 7,
+          label: "瓒呮椂",
+        },
       ],
       topicoptionsyj: [
         {
diff --git a/src/views/patient/subsequent/index.vue b/src/views/patient/subsequent/index.vue
index fb95558..8f208bf 100644
--- a/src/views/patient/subsequent/index.vue
+++ b/src/views/patient/subsequent/index.vue
@@ -382,11 +382,11 @@
           label="搴旈殢璁挎棩鏈�"
           width="200"
           align="center"
-          key="longSendTime"
-          prop="longSendTime"
+          key="visitTime"
+          prop="visitTime"
         >
           <template slot-scope="scope">
-            <span>{{ formatTime(scope.row.longSendTime) }}</span>
+            <span>{{ formatTime(scope.row.visitTime) }}</span>
           </template></el-table-column
         >
         <el-table-column
@@ -898,7 +898,7 @@
           value: 4,
           label: "涓嶆墽琛�",
         },
-        {
+         {
           value: 5,
           label: "鍙戦�佸け璐�",
         },
@@ -906,6 +906,10 @@
           value: 6,
           label: "宸插畬鎴�",
         },
+         {
+          value: 7,
+          label: "瓒呮椂",
+        },
       ],
       sextype: [
         {
diff --git a/src/views/repositoryai/templateku/configurat/index.vue b/src/views/repositoryai/templateku/configurat/index.vue
index 3ecd00e..d64c59c 100644
--- a/src/views/repositoryai/templateku/configurat/index.vue
+++ b/src/views/repositoryai/templateku/configurat/index.vue
@@ -1467,7 +1467,7 @@
   illnesslistget,
   getillness,
   getgenerallist,
-  depthospgetsondel
+  depthospgetsondel,
 } from "@/api/AiCentre/index";
 import OptionalForm from "@/components/OptionalForm"; //姝e垯缁勪欢
 import { getToken } from "@/utils/auth";
@@ -1510,7 +1510,9 @@
       ruleForm: {
         templateName: "",
         revisitBefore:
-          "浜茬埍鐨勬偅鑰�/瀹跺睘锛屾垜浠槸"+localStorage.getItem("orgname")+"鐨勫尰鎶や汉鍛橈紝涓轰簡鏇村ソ鍦颁簡瑙f偍鐨勫悍澶嶆儏鍐碉紝璇锋偍鎶戒竴鐐瑰疂璐垫椂闂达紝瀹屾垚杩欎唤闅忚銆�",
+          "浜茬埍鐨勬偅鑰�/瀹跺睘锛屾垜浠槸" +
+          localStorage.getItem("orgname") +
+          "鐨勫尰鎶や汉鍛橈紝涓轰簡鏇村ソ鍦颁簡瑙f偍鐨勫悍澶嶆儏鍐碉紝璇锋偍鎶戒竴鐐瑰疂璐垫椂闂达紝瀹屾垚杩欎唤闅忚銆�",
         revisitAfter:
           "璇锋偍娉ㄦ剰浼戞伅鍜岃惀鍏伙紝鐢熸椿涓婅鍔抽�哥粨鍚堬紝閫傚綋閿荤偧锛屾垝鐑熼檺閰掞紝淇濇寔蹇冩儏鑸掔晠锛屽畾鏈熷璇娿�傞偅鏈鍥炶灏卞埌杩欓噷锛岀鎮ㄨ韩浣撳仴搴凤紒",
         ivrLibaTemplateTagList: [],
@@ -1627,7 +1629,7 @@
     this.auxiliary();
     this.getDeptTree();
     this.mode = store.getters.mode;
-    console.log(this.mode,'this.mode');
+    console.log(this.mode, "this.mode");
     this.usable = store.getters.usable;
     this.required = store.getters.required;
     this.valuetype = store.getters.valuetype;
@@ -1704,9 +1706,9 @@
             console.log(2211);
             this.ruleForm = res.data;
             if (this.ruleForm.deptNames)
-            console.log(this.ruleForm.suitway,'suitway');
+              console.log(this.ruleForm.suitway, "suitway");
             this.ruleForm.suitway = this.ruleForm.suitway.split(",");
-            console.log(this.ruleForm.suitway,'suitway');
+            console.log(this.ruleForm.suitway, "suitway");
             if (this.ruleForm.campus)
               this.ruleForm.campus = this.ruleForm.campus.split(",");
             this.ruleForm.submoduleID = this.ruleForm.submoduleID.split(",");
@@ -2113,6 +2115,7 @@
         console.log(res, "璇︽儏");
         res.data.isoperation = 1;
         res.data.pid = this.ruleForm.id;
+        res.data.scriptAssortid = res.data.assortid;
         res.data.ivrLibaScriptTargetoptionList.forEach((item) => {
           item.isoperation = 1;
         });
@@ -2123,7 +2126,7 @@
     },
     handleDelete(row) {
       this.$modal
-        .confirm('鏄惁纭鍒犻櫎闂锛�"' + row.scriptTopic + '?')
+        .confirm('鏄惁纭鍒犻櫎闂锛�"' + row.scriptTopic + "?")
         .then(() => {
           this.ruleForm.ivrLibaTemplateScriptVOList.splice(
             this.ruleForm.ivrLibaTemplateScriptVOList.indexOf(row),
@@ -2195,7 +2198,7 @@
         } else {
           item.nextScriptno = item.sort + 1;
         }
-        if (item.ivrLibaScriptTargetoptionList&&!item.branchFlag) {
+        if (item.ivrLibaScriptTargetoptionList && !item.branchFlag) {
           item.ivrLibaScriptTargetoptionList.forEach((items) => {
             items.nextQuestion = Number(item.sort) + 1;
           });
diff --git a/src/views/sfstatistics/ProblemStatistics/index.vue b/src/views/sfstatistics/ProblemStatistics/index.vue
new file mode 100644
index 0000000..0a4f091
--- /dev/null
+++ b/src/views/sfstatistics/ProblemStatistics/index.vue
@@ -0,0 +1,536 @@
+<template>
+  <div class="indexanalysis">
+    <div class="analysis-top">
+      <div class="title-top">鏌ヨ鏉′欢</div>
+      <div class="value">
+        <el-form ref="form" :model="queryParams" label-width="120px">
+          <el-form-item label="閫夋嫨闂鍚嶇О">
+            <el-select
+              ref="questionSelect"
+              remote
+              :remote-method="remoteMethod"
+              default-first-option
+              v-model="selectedTargets"
+              @change="handleTargetChange"
+              @keyup.enter.native="handleEnterSearch"
+              filterable
+              multiple
+              collapse-tags
+              reserve-keyword
+              :loading="searchLoading"
+              placeholder="璇疯緭鍏ラ棶棰樺悕绉版悳绱紝鎸夊洖杞︾‘璁�"
+            >
+              <el-option
+                v-for="item in targetList"
+                :key="item.id"
+                :label="item.scriptContent || item.targetname"
+                :value="item.id"
+              >
+                <span>{{ item.scriptContent || item.targetname }}</span>
+                <span style="float: right; color: #8492a6; font-size: 13px">
+                  ID: {{ item.id }}
+                </span>
+              </el-option>
+            </el-select>
+          </el-form-item>
+          <el-form-item label="宸查�夐鐩�">
+            <div class="selected-ids">
+              {{ selectedContentsText }}
+            </div>
+          </el-form-item>
+        </el-form>
+      </div>
+    </div>
+
+    <div class="formindex">
+      <el-table
+        v-loading="loading"
+        :data="processedTableData"
+        :span-method="objectSpanMethod"
+        border
+        :summary-method="getSummaries"
+        show-summary
+        style="width: 100%"
+        empty-text="璇烽�夋嫨瑕佺粺璁$殑棰樼洰"
+      >
+        <el-table-column prop="targetname" label="闂鍚嶇О" width="200">
+          <template slot-scope="scope">
+            <div class="target-name-cell">
+              {{ scope.row.targetname }}
+            </div>
+          </template>
+        </el-table-column>
+        <el-table-column prop="targetShowCount" label="闂鍑虹幇娆℃暟" width="120">
+          <template slot-scope="scope">
+            {{ scope.row.targetShowCount }}娆�
+          </template>
+        </el-table-column>
+        <el-table-column prop="completedPercentage" label="棰樼洰瀹屾垚搴�" width="120">
+          <template slot-scope="scope">
+            {{ formatPercentage(scope.row.completedPercentage) }}
+          </template>
+        </el-table-column>
+        <el-table-column prop="matchedtext" label="閫夐」鍐呭" width="150">
+          <template slot-scope="scope">
+            {{ scope.row.matchedtext || '-' }}
+          </template>
+        </el-table-column>
+        <el-table-column prop="count" label="閫変腑娆℃暟" width="100">
+          <template slot-scope="scope">
+            {{ scope.row.count }}娆�
+          </template>
+        </el-table-column>
+        <el-table-column prop="percentage" label="鍗犳瘮" width="100">
+          <template slot-scope="scope">
+            <span>{{ formatPercentage(scope.row.percentage) }}</span>
+          </template>
+        </el-table-column>
+        <el-table-column label="杩涘害鏉�" min-width="200">
+          <template slot-scope="scope">
+            <el-progress
+              :percentage="Number(scope.row.percentage) * 100"
+              :show-text="false"
+              :color="customColors"
+            />
+            <span class="progress-text">{{ formatPercentage(scope.row.percentage) }}</span>
+          </template>
+        </el-table-column>
+      </el-table>
+    </div>
+  </div>
+</template>
+
+<script>
+import { getissuelist, compileissuestatistics } from "@/api/AiCentre/index";
+
+export default {
+  name: "indexanalysis",
+  data() {
+    return {
+      targetList: [],
+      selectedTargets: [], // 瀛樺偍閫変腑鐨勯鐩甀D
+      tableData: [],
+      processedTableData: [],
+      loading: false,
+      searchLoading: false,
+      queryParams: {
+        pageNum: 1,
+        pageSize: 66,
+        scriptContent: '',
+      },
+      customColors: [
+        { color: '#f56c6c', percentage: 20 },
+        { color: '#e6a23c', percentage: 40 },
+        { color: '#5cb87a', percentage: 60 },
+        { color: '#1989fa', percentage: 80 },
+        { color: '#6f7ad3', percentage: 100 }
+      ],
+      spanArr: [],
+      searchTimer: null,
+      currentSearchQuery: '', // 褰撳墠鎼滅储鍏抽敭璇�
+    };
+  },
+
+  computed: {
+    // 璁$畻閫変腑鐨勯棶棰樺唴瀹规枃鏈�
+    selectedContentsText() {
+      if (this.selectedTargets.length === 0) {
+        return '鏈�夋嫨浠讳綍棰樼洰';
+      }
+
+      // 鏍规嵁閫変腑鐨処D鑾峰彇瀵瑰簲鐨剆criptContent
+      const selectedContents = this.selectedTargets.map(id => {
+        const target = this.targetList.find(item => item.id === id);
+        return target ? (target.scriptContent || target.targetname || `棰樼洰${id}`) : `棰樼洰${id}`;
+      });
+
+      return selectedContents.join('; ');
+    },
+
+    // 鑾峰彇閫変腑椤圭殑鍐呭鏁扮粍锛堢敤浜庢樉绀猴級
+    selectedContents() {
+      return this.selectedTargets.map(id => {
+        const target = this.targetList.find(item => item.id === id);
+        return target ? (target.scriptContent || target.targetname) : `棰樼洰${id}`;
+      });
+    }
+  },
+
+  watch: {
+    processedTableData: {
+      handler(newVal) {
+        if (newVal && newVal.length > 0) {
+          this.getSpanArr(newVal);
+        } else {
+          this.spanArr = [];
+        }
+      },
+      immediate: true,
+      deep: true
+    }
+  },
+
+  created() {
+    this.getList();
+  },
+
+  methods: {
+    // 鏌ヨ闂嵎鍒楄〃
+    async getList() {
+      this.loading = true;
+      try {
+        const response = await getissuelist(this.queryParams);
+        this.targetList = response.rows || [];
+      } catch (error) {
+        console.error('鑾峰彇棰樼洰鍒楄〃澶辫触:', error);
+        this.$message.error('鑾峰彇棰樼洰鍒楄〃澶辫触');
+      } finally {
+        this.loading = false;
+      }
+    },
+
+    // 鍥炶溅閿悳绱㈠鐞哰6,8](@ref)
+    handleEnterSearch(event) {
+      const inputElement = event.target;
+      const searchQuery = inputElement.value.trim();
+
+
+        this.currentSearchQuery = searchQuery;
+        this.executeSearch(searchQuery);
+
+        // 闃叉榛樿琛屼负
+        event.preventDefault();
+        event.stopPropagation();
+
+    },
+
+    // 杩滅▼鎼滅储鏂规硶锛堝甫闃叉姈锛�
+    remoteMethod(query) {
+      if (this.searchTimer) {
+        clearTimeout(this.searchTimer);
+      }
+
+      this.searchTimer = setTimeout(() => {
+        this.currentSearchQuery = query;
+        this.executeSearch(query);
+      }, 300);
+    },
+
+    // 鎵ц鎼滅储
+    async executeSearch(query) {
+      if (query === '') {
+        this.queryParams.scriptContent = '';
+        await this.getList();
+        return;
+      }
+
+      this.searchLoading = true;
+
+      try {
+        const searchParams = {
+          pageNum: 1,
+          pageSize: 50,
+          scriptType: "1",
+          scriptContent: query
+        };
+
+        const response = await getissuelist(searchParams);
+        this.targetList = response.rows || [];
+
+        if (this.targetList.length === 0) {
+          this.$message.info(`鏈壘鍒板寘鍚�"${query}"鐨勯棶棰榒);
+        }
+      } catch (error) {
+        console.error('鎼滅储棰樼洰澶辫触:', error);
+        this.$message.error('鎼滅储鏈嶅姟寮傚父锛岃绋嶅悗閲嶈瘯');
+        this.targetList = [];
+      } finally {
+        this.searchLoading = false;
+      }
+    },
+
+    // 澶氶�夐鐩敼鍙樺鐞�
+    handleTargetChange(selectedIds) {
+      if (selectedIds && selectedIds.length > 0) {
+        this.Labelstatistics(selectedIds.join(','));
+      } else {
+        this.processedTableData = [];
+        this.spanArr = [];
+      }
+    },
+
+    // 鑾峰彇缁熻淇℃伅
+    async Labelstatistics(scriptIds) {
+      if (!scriptIds) {
+        this.processedTableData = [];
+        this.spanArr = [];
+        return;
+      }
+
+      this.loading = true;
+      try {
+        const response = await compileissuestatistics({ scriptids: scriptIds });
+        this.tableData = response.data || [];
+        this.processTableData();
+      } catch (error) {
+        console.error('鑾峰彇缁熻淇℃伅澶辫触:', error);
+        this.$message.error('鑾峰彇缁熻淇℃伅澶辫触');
+        this.processedTableData = [];
+        this.spanArr = [];
+      } finally {
+        this.loading = false;
+      }
+    },
+
+    // 澶勭悊琛ㄦ牸鏁版嵁
+    processTableData() {
+      if (!this.tableData || Object.keys(this.tableData).length === 0) {
+        this.processedTableData = [];
+        return;
+      }
+
+      const processedData = [];
+
+      Object.keys(this.tableData).forEach(scriptId => {
+        const questionData = this.tableData[scriptId];
+
+        if (questionData && questionData.details) {
+          const targetName = questionData.scriptContent || `棰樼洰${scriptId}`;
+          const targetShowCount = questionData.allQuantity || 0;
+          const completedPercentage = questionData.completedPercentage || "0";
+
+          questionData.details.forEach(detail => {
+            if (detail.optionText) {
+              processedData.push({
+                scriptid: scriptId,
+                targetname: targetName,
+                targetShowCount: targetShowCount,
+                matchedtext: detail.optionText,
+                count: detail.chosenQuantity || 0,
+                percentage: detail.chosenPercentage || "0",
+                completedPercentage: completedPercentage,
+                allQuantity: questionData.allQuantity || 0,
+                completedQuantity: questionData.completedQuantity || 0
+              });
+            }
+          });
+
+          if (questionData.details.length === 0) {
+            processedData.push({
+              scriptid: scriptId,
+              targetname: targetName,
+              targetShowCount: targetShowCount,
+              matchedtext: '-',
+              count: 0,
+              percentage: "0",
+              completedPercentage: completedPercentage,
+              allQuantity: questionData.allQuantity || 0,
+              completedQuantity: questionData.completedQuantity || 0
+            });
+          }
+        }
+      });
+
+      this.processedTableData = processedData;
+    },
+
+    // 鐢熸垚鍚堝苟淇℃伅鏁扮粍
+    getSpanArr(data) {
+      this.spanArr = [];
+
+      if (!data || data.length === 0) return;
+
+      for (let i = 0; i < data.length; i++) {
+        if (i === 0) {
+          this.spanArr.push(1);
+          this.pos = 0;
+        } else {
+          if (data[i].scriptid === data[i - 1].scriptid) {
+            this.spanArr[this.pos] += 1;
+            this.spanArr.push(0);
+          } else {
+            this.spanArr.push(1);
+            this.pos = i;
+          }
+        }
+      }
+    },
+
+    // 鍗曞厓鏍煎悎骞舵柟娉�
+    objectSpanMethod({ row, column, rowIndex, columnIndex }) {
+      if (columnIndex === 0 || columnIndex === 1 || columnIndex === 2) {
+        if (this.spanArr.length > rowIndex) {
+          const rowspan = this.spanArr[rowIndex];
+          const colspan = rowspan > 0 ? 1 : 0;
+
+          return {
+            rowspan: rowspan,
+            colspan: colspan
+          };
+        }
+      }
+    },
+
+    // 鏍煎紡鍖栫櫨鍒嗘瘮鏄剧ず
+    formatPercentage(value) {
+      const numValue = Number(value);
+      return isNaN(numValue) ? '0%' : `${(numValue * 100).toFixed(2)}%`;
+    },
+
+    // 琛ㄦ牸鍚堣琛岃绠�
+    getSummaries(param) {
+      const { columns, data } = param;
+      const sums = [];
+
+      columns.forEach((column, index) => {
+        if (index === 0) {
+          sums[index] = '鍚堣';
+          return;
+        }
+
+        if (data.length === 0) {
+          sums[index] = '-';
+          return;
+        }
+
+        switch (column.property) {
+          case 'targetShowCount':
+            const totalQuestions = new Set(data.map(item => item.scriptid)).size;
+            sums[index] = `${totalQuestions}涓鐩甡;
+            break;
+
+          case 'count':
+            const values = data.map(item => Number(item.count));
+            const totalCount = values.reduce((prev, curr) => prev + curr, 0);
+            sums[index] = `${totalCount}娆;
+            break;
+
+          case 'percentage':
+            const percentages = data.map(item => Number(item.percentage));
+            const validPercentages = percentages.filter(p => !isNaN(p));
+            if (validPercentages.length > 0) {
+              const avgPercentage = validPercentages.reduce((a, b) => a + b, 0) / validPercentages.length;
+              sums[index] = `${(avgPercentage * 100).toFixed(2)}%`;
+            } else {
+              sums[index] = '0%';
+            }
+            break;
+
+          case 'completedPercentage':
+            const completedPercentages = data.map(item => Number(item.completedPercentage));
+            const validCompleted = completedPercentages.filter(p => !isNaN(p));
+            if (validCompleted.length > 0) {
+              const avgCompleted = validCompleted.reduce((a, b) => a + b, 0) / validCompleted.length;
+              sums[index] = `${(avgCompleted * 100).toFixed(2)}%`;
+            } else {
+              sums[index] = '0%';
+            }
+            break;
+
+          default:
+            sums[index] = '-';
+            break;
+        }
+      });
+
+      return sums;
+    }
+  },
+
+  beforeDestroy() {
+    if (this.searchTimer) {
+      clearTimeout(this.searchTimer);
+    }
+  }
+};
+</script>
+
+<style lang="scss" scoped>
+.analysis-top {
+  border: 1px solid #dcdfe6;
+  -webkit-box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.12), 0 0 6px 0 rgba(0, 0, 0, 0.04);
+  margin: 15px;
+
+  .title-top {
+    background-color: #6784f2;
+    color: #fff;
+    padding: 10px 20px;
+    font-size: 20px;
+    font-weight: 500;
+    margin-bottom: 20px;
+  }
+
+  .value {
+    padding: 0 20px 20px;
+  }
+}
+
+.formindex {
+  margin: 0 15px;
+  border: 1px solid #dcdfe6;
+  -webkit-box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.12), 0 0 6px 0 rgba(0, 0, 0, 0.04);
+  padding: 20px;
+}
+
+.selected-ids {
+  padding: 8px 12px;
+  background-color: #f5f7fa;
+  border-radius: 4px;
+  border: 1px solid #e4e7ed;
+  min-height: 36px;
+  word-break: break-all;
+  line-height: 1.5;
+}
+
+.target-name-cell {
+  font-weight: 600;
+  color: #409eff;
+}
+
+.progress-text {
+  margin-left: 10px;
+  font-size: 12px;
+  color: #909399;
+}
+
+::v-deep .el-progress-bar {
+  padding-right: 0;
+  margin-right: 0;
+}
+
+::v-deep .el-select {
+  width: 100%;
+}
+
+::v-deep .el-table {
+  .cell {
+    word-break: break-word;
+  }
+
+  .el-table__body tr:hover > td.el-table__cell {
+    background-color: #f5f7fa;
+  }
+
+  .el-table__body .el-table__cell {
+    vertical-align: top;
+  }
+}
+
+.merged-cell {
+  background-color: #f0f9ff;
+  font-weight: 600;
+}
+
+::v-deep .el-select__tags {
+  .el-tag {
+    max-width: 200px;
+    overflow: hidden;
+    text-overflow: ellipsis;
+    white-space: nowrap;
+
+    .el-tag__close {
+      margin-left: 4px;
+    }
+  }
+}
+</style>
diff --git a/src/views/sfstatistics/percentage/index.vue b/src/views/sfstatistics/percentage/index.vue
index 46770d9..5cad6ba 100644
--- a/src/views/sfstatistics/percentage/index.vue
+++ b/src/views/sfstatistics/percentage/index.vue
@@ -83,12 +83,14 @@
               >
                 <el-date-picker
                   v-model="queryParams.dateRange"
-                  value-format="yyyy-MM-dd"
+                  value-format="yyyy-MM-dd HH:mm:ss"
                   type="daterange"
                   range-separator="鑷�"
                   start-placeholder="寮�濮嬫棩鏈�"
                   end-placeholder="缁撴潫鏃ユ湡"
+                  :default-time="['00:00:00', '23:59:59']"
                 >
+                  >
                 </el-date-picker>
               </el-form-item>
 
@@ -113,7 +115,7 @@
                   plain
                   icon="el-icon-download"
                   size="medium"
-                  @click="handleExport"
+                  @click="exportTable"
                   >瀵煎嚭</el-button
                 >
                 <el-button
@@ -128,6 +130,8 @@
             </el-form>
             <div class="your-table-container">
               <el-table
+                ref="exportTable"
+                id="exportTableid"
                 v-loading="loading"
                 :data="userList"
                 :border="true"
@@ -352,6 +356,7 @@
                   prop="leavehospitaldistrictname"
                   width="150"
                   :show-overflow-tooltip="true"
+                  :sort-method="sortChineseNumber"
                 />
                 <el-table-column
                   label="绉戝"
@@ -391,6 +396,21 @@
                     key="needFollowUp"
                     prop="needFollowUp"
                   >
+                    <template slot-scope="scope">
+                      <el-button
+                        size="medium"
+                        type="text"
+                        @click="
+                          viewDetails(
+                            scope.row.needFollowUpInfo,
+                            scope.row.leavehospitaldistrictname + '闇�闅忚鍒楄〃'
+                          )
+                        "
+                        ><span class="button-zx">{{
+                          scope.row.needFollowUp
+                        }}</span></el-button
+                      >
+                    </template>
                   </el-table-column>
                   <el-table-column
                     label="寰呴殢璁�"
@@ -398,6 +418,21 @@
                     key="pendingFollowUp"
                     prop="pendingFollowUp"
                   >
+                    <template slot-scope="scope">
+                      <el-button
+                        size="medium"
+                        type="text"
+                        @click="
+                          viewDetails(
+                            scope.row.pendingFollowUpInfo,
+                            scope.row.leavehospitaldistrictname + '寰呴殢璁垮垪琛�'
+                          )
+                        "
+                        ><span class="button-zx">{{
+                          scope.row.pendingFollowUp
+                        }}</span></el-button
+                      >
+                    </template>
                   </el-table-column>
                   <el-table-column
                     label="闅忚鎴愬姛"
@@ -405,6 +440,21 @@
                     key="followUpSuccess"
                     prop="followUpSuccess"
                   >
+                    <template slot-scope="scope">
+                      <el-button
+                        size="medium"
+                        type="text"
+                        @click="
+                          viewDetails(
+                            scope.row.followUpSuccessInfo,
+                            scope.row.leavehospitaldistrictname + '闅忚鎴愬姛鍒楄〃'
+                          )
+                        "
+                        ><span class="button-zx">{{
+                          scope.row.followUpSuccess
+                        }}</span></el-button
+                      >
+                    </template>
                   </el-table-column>
                   <el-table-column
                     label="闅忚澶辫触"
@@ -412,6 +462,21 @@
                     key="followUpFail"
                     prop="followUpFail"
                   >
+                    <template slot-scope="scope">
+                      <el-button
+                        size="medium"
+                        type="text"
+                        @click="
+                          viewDetails(
+                            scope.row.followUpFailInfo,
+                            scope.row.leavehospitaldistrictname + '闅忚澶辫触鍒楄〃'
+                          )
+                        "
+                        ><span class="button-zx">{{
+                          scope.row.followUpFail
+                        }}</span></el-button
+                      >
+                    </template>
                   </el-table-column>
                   <el-table-column
                     label="闅忚鐜�"
@@ -454,6 +519,21 @@
                     key="manual"
                     prop="manual"
                   >
+                    <template slot-scope="scope">
+                      <el-button
+                        size="medium"
+                        type="text"
+                        @click="
+                          viewDetails(
+                            scope.row.manualInfo,
+                            scope.row.leavehospitaldistrictname + '浜哄伐闅忚鍒楄〃'
+                          )
+                        "
+                        ><span class="button-zx">{{
+                          scope.row.manual
+                        }}</span></el-button
+                      >
+                    </template>
                   </el-table-column>
                   <el-table-column
                     label="鐭俊"
@@ -461,6 +541,21 @@
                     key="sms"
                     prop="sms"
                   >
+                    <template slot-scope="scope">
+                      <el-button
+                        size="medium"
+                        type="text"
+                        @click="
+                          viewDetails(
+                            scope.row.smsInfo,
+                            scope.row.leavehospitaldistrictname + '鐭俊闅忚鍒楄〃'
+                          )
+                        "
+                        ><span class="button-zx">{{
+                          scope.row.sms
+                        }}</span></el-button
+                      >
+                    </template>
                   </el-table-column>
                   <el-table-column
                     label="寰俊"
@@ -468,6 +563,21 @@
                     key="weChat"
                     prop="weChat"
                   >
+                    <template slot-scope="scope">
+                      <el-button
+                        size="medium"
+                        type="text"
+                        @click="
+                          viewDetails(
+                            scope.row.weChatInfo,
+                            scope.row.leavehospitaldistrictname + '寰俊闅忚鍒楄〃'
+                          )
+                        "
+                        ><span class="button-zx">{{
+                          scope.row.weChat
+                        }}</span></el-button
+                      >
+                    </template>
                   </el-table-column>
                 </el-table-column>
                 <el-table-column align="center" label="鍐嶆鍑洪櫌闅忚">
@@ -477,6 +587,22 @@
                     key="needFollowUpAgain"
                     prop="needFollowUpAgain"
                   >
+                    <template slot-scope="scope">
+                      <el-button
+                        size="medium"
+                        type="text"
+                        @click="
+                          viewDetails(
+                            scope.row.needFollowUpAgainInfo,
+                            scope.row.leavehospitaldistrictname +
+                              '鍐嶆闅忚闇�闅忚鍒楄〃'
+                          )
+                        "
+                        ><span class="button-zx">{{
+                          scope.row.needFollowUpAgain
+                        }}</span></el-button
+                      >
+                    </template>
                   </el-table-column>
                   <el-table-column
                     label="寰呴殢璁�"
@@ -484,6 +610,22 @@
                     key="pendingFollowUpAgain"
                     prop="pendingFollowUpAgain"
                   >
+                    <template slot-scope="scope">
+                      <el-button
+                        size="medium"
+                        type="text"
+                        @click="
+                          viewDetails(
+                            scope.row.pendingFollowUpAgainInfo,
+                            scope.row.leavehospitaldistrictname +
+                              '鍐嶆闅忚寰呴殢璁垮垪琛�'
+                          )
+                        "
+                        ><span class="button-zx">{{
+                          scope.row.pendingFollowUpAgain
+                        }}</span></el-button
+                      >
+                    </template>
                   </el-table-column>
                   <el-table-column
                     label="闅忚鎴愬姛"
@@ -491,6 +633,22 @@
                     key="followUpSuccessAgain"
                     prop="followUpSuccessAgain"
                   >
+                    <template slot-scope="scope">
+                      <el-button
+                        size="medium"
+                        type="text"
+                        @click="
+                          viewDetails(
+                            scope.row.followUpSuccessAgainInfo,
+                            scope.row.leavehospitaldistrictname +
+                              '鍐嶆闅忚闅忚鎴愬姛鍒楄〃'
+                          )
+                        "
+                        ><span class="button-zx">{{
+                          scope.row.followUpSuccessAgain
+                        }}</span></el-button
+                      >
+                    </template>
                   </el-table-column>
                   <el-table-column
                     label="闅忚澶辫触"
@@ -498,6 +656,22 @@
                     key="followUpFailAgain"
                     prop="followUpFailAgain"
                   >
+                    <template slot-scope="scope">
+                      <el-button
+                        size="medium"
+                        type="text"
+                        @click="
+                          viewDetails(
+                            scope.row.followUpFailAgainInfo,
+                            scope.row.leavehospitaldistrictname +
+                              '鍐嶆闅忚闅忚澶辫触鍒楄〃'
+                          )
+                        "
+                        ><span class="button-zx">{{
+                          scope.row.followUpFailAgain
+                        }}</span></el-button
+                      >
+                    </template>
                   </el-table-column>
                   <el-table-column
                     label="闅忚鐜�"
@@ -520,6 +694,22 @@
                     key="manualAgain"
                     prop="manualAgain"
                   >
+                    <template slot-scope="scope">
+                      <el-button
+                        size="medium"
+                        type="text"
+                        @click="
+                          viewDetails(
+                            scope.row.manualAgainInfo,
+                            scope.row.leavehospitaldistrictname +
+                              '鍐嶆闅忚浜哄伐闅忚鍒楄〃'
+                          )
+                        "
+                        ><span class="button-zx">{{
+                          scope.row.manualAgain
+                        }}</span></el-button
+                      >
+                    </template>
                   </el-table-column>
                   <el-table-column
                     label="鐭俊"
@@ -527,6 +717,22 @@
                     key="smsAgain"
                     prop="smsAgain"
                   >
+                    <template slot-scope="scope">
+                      <el-button
+                        size="medium"
+                        type="text"
+                        @click="
+                          viewDetails(
+                            scope.row.smsAgainInfo,
+                            scope.row.leavehospitaldistrictname +
+                              '鍐嶆闅忚鐭俊闅忚鍒楄〃'
+                          )
+                        "
+                        ><span class="button-zx">{{
+                          scope.row.smsAgain
+                        }}</span></el-button
+                      >
+                    </template>
                   </el-table-column>
                   <el-table-column
                     label="寰俊"
@@ -534,6 +740,22 @@
                     key="weChatAgain"
                     prop="weChatAgain"
                   >
+                    <template slot-scope="scope">
+                      <el-button
+                        size="medium"
+                        type="text"
+                        @click="
+                          viewDetails(
+                            scope.row.weChatAgainInfo,
+                            scope.row.leavehospitaldistrictname +
+                              '鍐嶆闅忚寰俊闅忚鍒楄〃'
+                          )
+                        "
+                        ><span class="button-zx">{{
+                          scope.row.weChatAgain
+                        }}</span></el-button
+                      >
+                    </template>
                   </el-table-column>
                 </el-table-column>
                 <el-table-column
@@ -847,8 +1069,235 @@
             :total="patienttotal"
             :page.sync="patientqueryParams.pn"
             :limit.sync="patientqueryParams.ps"
-            @pagination="Seedetails"
+            @pagination="Seedetailstion"
           />
+        </div>
+      </div>
+    </el-dialog>
+    <!-- 鍚勭被璇︽儏 -->
+    <el-dialog
+      :title="infotitle"
+      :visible.sync="infotitleVisible"
+      v-loading="infotitloading"
+      width="70%"
+      :close-on-click-modal="false"
+    >
+      <div style="margin-bottom: 16px; display: flex; align-items: center">
+        <span style="margin-right: 10px; font-weight: bold">鎮h�呭鍚嶆煡璇�:</span>
+        <el-input
+          v-model="searchName"
+          placeholder="璇疯緭鍏ユ偅鑰呭鍚嶈繘琛岀瓫閫�"
+          clearable
+          style="width: 300px"
+          @input="handleSearch"
+          @clear="handleSearch"
+        >
+        </el-input>
+        <span
+          style="margin-left: 10px; color: rgb(35, 81, 233); font-size: 16px"
+        >
+          鍏� {{ infotitlelist.length }} 鏉¤褰�
+        </span>
+      </div>
+      <div class="examine-jic">
+        <div class="jic-value">
+          <el-row :gutter="20">
+            <!-- 閫夋嫨鎮h�呭垪琛� -->
+            <div
+              class="data-list"
+              ref="dataList"
+              @scroll="handleScroll"
+              v-loading="infotitloading"
+            >
+              <el-table
+                :data="currentDisplayList"
+                height="660"
+                style="width: 100%"
+              >
+                <el-table-column
+                  prop="sendname"
+                  align="center"
+                  label="濮撳悕"
+                  width="100"
+                >
+                </el-table-column>
+                <el-table-column
+                  prop="taskName"
+                  align="center"
+                  width="200"
+                  show-overflow-tooltip
+                  label="浠诲姟鍚嶇О"
+                >
+                </el-table-column>
+                <el-table-column
+                  prop="sendstate"
+                  align="center"
+                  width="200"
+                  label="浠诲姟鐘舵��"
+                >
+                  <template slot-scope="scope">
+                    <div v-if="scope.row.sendstate == 1">
+                      <el-tag type="primary" :disable-transitions="false"
+                        >琛ㄥ崟宸查鍙�</el-tag
+                      >
+                    </div>
+                    <div v-if="scope.row.sendstate == 2">
+                      <el-tag type="primary" :disable-transitions="false"
+                        >寰呴殢璁�</el-tag
+                      >
+                    </div>
+                    <div v-if="scope.row.sendstate == 3">
+                      <el-tag type="success" :disable-transitions="false"
+                        >琛ㄥ崟宸插彂閫�</el-tag
+                      >
+                    </div>
+                    <div v-if="scope.row.sendstate == 4">
+                      <el-tag type="info" :disable-transitions="false"
+                        >涓嶆墽琛�</el-tag
+                      >
+                    </div>
+                    <div v-if="scope.row.sendstate == 5">
+                      <el-tag type="danger" :disable-transitions="false"
+                        >鍙戦�佸け璐�</el-tag
+                      >
+                    </div>
+                    <div v-if="scope.row.sendstate == 6">
+                      <el-tag type="success" :disable-transitions="false"
+                        >宸插畬鎴�</el-tag
+                      >
+                    </div>
+                  </template>
+                </el-table-column>
+                <el-table-column
+                  label="浠诲姟鎵ц鏂瑰紡"
+                  align="center"
+                  key="preachform"
+                  prop="preachform"
+                  width="160"
+                  :show-overflow-tooltip="true"
+                >
+                  <template slot-scope="scope">
+                    <span v-for="item in scope.row.preachform"
+                      >{{ item }}銆�
+                    </span>
+                  </template>
+                </el-table-column>
+                <el-table-column
+                  prop="visitTime"
+                  align="center"
+                  label="搴旈殢璁挎椂闂�"
+                  width="200"
+                  show-overflow-tooltip
+                >
+                </el-table-column>
+                <el-table-column
+                  prop="finishtime"
+                  align="center"
+                  label="闅忚瀹屾垚鏃堕棿"
+                  width="200"
+                  show-overflow-tooltip
+                >
+                </el-table-column>
+                <el-table-column
+                  label="鍑洪櫌鏃ユ湡"
+                  width="200"
+                  align="center"
+                  key="endtime"
+                  prop="endtime"
+                >
+                  <template slot-scope="scope">
+                    <span>{{ formatTime(scope.row.endtime) }}</span>
+                  </template></el-table-column
+                >
+                <el-table-column
+                  label="璐d换鎶ゅ+"
+                  width="120"
+                  align="center"
+                  key="nurseName"
+                  prop="nurseName"
+                />
+                <el-table-column
+                  label="涓绘不鍖荤敓"
+                  width="120"
+                  align="center"
+                  key="drname"
+                  prop="drname"
+                />
+
+                <el-table-column
+                  label="缁撴灉鐘舵��"
+                  align="center"
+                  key="excep"
+                  prop="excep"
+                  width="120"
+                >
+                  <template slot-scope="scope">
+                    <dict-tag
+                      :options="dict.type.sys_yujing"
+                      :value="scope.row.excep"
+                    />
+                  </template>
+                </el-table-column>
+                <el-table-column
+                  label="澶勭悊鎰忚"
+                  align="center"
+                  key="suggest"
+                  prop="suggest"
+                  width="120"
+                >
+                  <template slot-scope="scope">
+                    <dict-tag
+                      :options="dict.type.sys_suggest"
+                      :value="scope.row.suggest"
+                    />
+                  </template>
+                </el-table-column>
+
+                <el-table-column
+                  prop="templatename"
+                  align="center"
+                  label="鏈嶅姟妯℃澘"
+                  width="200"
+                  show-overflow-tooltip
+                >
+                </el-table-column>
+                <el-table-column
+                  prop="remark"
+                  align="center"
+                  label="鏈嶅姟璁板綍"
+                  width="200"
+                  show-overflow-tooltip
+                >
+                </el-table-column>
+
+                <el-table-column
+                  prop="bankcardno"
+                  align="center"
+                  label="鍛煎彨鐘舵��"
+                  width="210"
+                >
+                </el-table-column>
+                <el-table-column
+                  label="鎿嶄綔"
+                  fixed="right"
+                  align="center"
+                  width="200"
+                  class-name="small-padding fixed-width"
+                >
+                  <template slot-scope="scope">
+                    <el-button
+                      size="medium"
+                      type="text"
+                      @click="SeedetailsgGo(scope.row)"
+                      ><span class="button-zx"
+                        ><i class="el-icon-s-order"></i>鏌ョ湅</span
+                      ></el-button
+                    >
+                  </template>
+                </el-table-column>
+              </el-table>
+            </div>
+          </el-row>
         </div>
       </div>
     </el-dialog>
@@ -864,7 +1313,10 @@
 } from "@/api/system/label";
 import store from "@/store";
 import { getSfStatistics, selectTimelyRate } from "@/api/system/user";
-
+import * as XLSX from "xlsx";
+import FileSaver from "file-saver";
+import ExcelJS from "exceljs";
+import { saveAs } from "file-saver";
 import Treeselect from "@riophae/vue-treeselect";
 import "@riophae/vue-treeselect/dist/vue-treeselect.css";
 const shortcuts = [
@@ -901,10 +1353,19 @@
       activeName: "first", //渚ц竟閫夋嫨
       orgname: "",
       expands: [],
+      infotitlelist: [],
+      currentDisplayList: [], // 褰撳墠鏄剧ず鐨勬暟鎹�
+      loadIndex: 0, // 褰撳墠宸插姞杞界殑鏁版嵁绱㈠紩
+      pageSize: 100, // 姣忔鍔犺浇鐨勬暟鎹噺
+      isLoading: false, // 闃叉婊氬姩鏃堕噸澶嶅姞杞�
       // 閬僵灞�
       loading: false,
       Seedloading: false,
       chartDialogVisible: false,
+      infotitleVisible: false,
+      searchName: "", // 鎼滅储鍏抽敭璇�
+      infotitloading: false,
+      infotitle: "",
       pieChart: null,
       barLineChart: null,
       // 閫変腑鏁扮粍
@@ -967,6 +1428,7 @@
       allDeptCodes: [],
       // 瀛樺偍鎵�鏈夌梾鍖轰唬鐮�
       allWardCodes: [],
+      checkboxlist: [],
       // 琛ㄥ崟鍙傛暟
       form: {},
       forms: {
@@ -994,8 +1456,6 @@
       },
       // 鏌ヨ鏍囩鍒楄〃鍙傛暟
       queryParams: {
-        pageNum: 1,
-        pageSize: 10,
         serviceType: [2],
         dateRange: [],
         statisticaltype: 1,
@@ -1018,6 +1478,7 @@
   created() {
     this.getDeptTree();
     this.getList();
+    this.checkboxlist = store.getters.checkboxlist;
     this.orgname = localStorage.getItem("orgname");
   },
 
@@ -1036,14 +1497,205 @@
           ? this.allDeptCodes
           : this.queryParams.deptcodes,
       };
-
+      this.loading = true;
       // 绉婚櫎鍙兘瀛樺湪鐨�"all"鍊�
       delete params.leavehospitaldistrictcodes.all;
       delete params.deptcodes.all;
       getSfStatistics(params).then((response) => {
-        console.log(response);
-        // this.total = response.total;
-        this.userList = response.data;
+        this.loading = false;
+
+        this.total = response.total;
+        // this.userList = response.data;
+        this.userList = this.customSort(response.data);
+      });
+    },
+    sortChineseNumber(aRow, bRow) {
+      const a = aRow.leavehospitaldistrictname;
+      const b = bRow.leavehospitaldistrictname;
+
+      // 涓枃鏁板瓧鍒伴樋鎷変集鏁板瓧鐨勬槧灏勶紙鎵╁睍鍒�45锛�
+      const chineseNumMap = {
+        涓�: 1,
+        浜�: 2,
+        涓�: 3,
+        鍥�: 4,
+        浜�: 5,
+        鍏�: 6,
+        涓�: 7,
+        鍏�: 8,
+        涔�: 9,
+        鍗�: 10,
+        鍗佷竴: 11,
+        鍗佷簩: 12,
+        鍗佷笁: 13,
+        鍗佸洓: 14,
+        鍗佷簲: 15,
+        鍗佸叚: 16,
+        鍗佷竷: 17,
+        鍗佸叓: 18,
+        鍗佷節: 19,
+        浜屽崄: 20,
+        浜屽崄涓�: 21,
+        浜屽崄浜�: 22,
+        浜屽崄涓�: 23,
+        浜屽崄鍥�: 24,
+        浜屽崄浜�: 25,
+        浜屽崄鍏�: 26,
+        浜屽崄涓�: 27,
+        浜屽崄鍏�: 28,
+        浜屽崄涔�: 29,
+        涓夊崄: 30,
+        涓夊崄涓�: 31,
+        涓夊崄浜�: 32,
+        涓夊崄涓�: 33,
+        涓夊崄鍥�: 34,
+        涓夊崄浜�: 35,
+        涓夊崄鍏�: 36,
+        涓夊崄涓�: 37,
+        涓夊崄鍏�: 38,
+        涓夊崄涔�: 39,
+        鍥涘崄: 40,
+        鍥涘崄涓�: 41,
+        鍥涘崄浜�: 42,
+        鍥涘崄涓�: 43,
+        鍥涘崄鍥�: 44,
+        鍥涘崄浜�: 45,
+      };
+
+      // 鎻愬彇涓枃鏁板瓧
+      const getNumberFromText = (text) => {
+        if (!text || typeof text !== "string") return -1;
+
+        // 鍖归厤涓枃鏁板瓧锛屾敮鎸佷竴鍒板洓鍗佷簲
+        const match = text.match(/^([涓�浜屼笁鍥涗簲鍏竷鍏節鍗乚+)/);
+
+        if (match && match[1]) {
+          const chineseNum = match[1];
+          return chineseNumMap[chineseNum] !== undefined
+            ? chineseNumMap[chineseNum]
+            : -1;
+        }
+
+        // 濡傛灉娌℃湁鍖归厤鍒颁腑鏂囨暟瀛楋紝灏濊瘯鍖归厤闃挎媺浼暟瀛�
+        const arabicMatch = text.match(/^(\d+)/);
+        if (arabicMatch && arabicMatch[1]) {
+          const num = parseInt(arabicMatch[1], 10);
+          return num >= 1 && num <= 45 ? num : -1;
+        }
+
+        return -1;
+      };
+
+      const numA = getNumberFromText(a);
+      const numB = getNumberFromText(b);
+
+      // 澶勭悊鏃犳硶瑙f瀽鐨勬儏鍐�
+      if (numA === -1 && numB === -1) {
+        return (a || "").localeCompare(b || "");
+      }
+      if (numA === -1) return 1;
+      if (numB === -1) return -1;
+
+      return numA - numB;
+    },
+    // 鎼滅储澶勭悊鍑芥暟
+    handleSearch() {
+      if (!this.searchName.trim()) {
+        // 濡傛灉鎼滅储妗嗕负绌猴紝鏄剧ず鎵�鏈夋暟鎹�
+        this.currentDisplayList = [...this.infotitlelist];
+      } else {
+        // 鏍规嵁鎮h�呭鍚嶈繘琛岀瓫閫夛紙涓嶅尯鍒嗗ぇ灏忓啓锛�
+        const keyword = this.searchName.toLowerCase();
+        this.currentDisplayList = this.infotitlelist.filter((item) => {
+          return item.sendname && item.sendname.toLowerCase().includes(keyword);
+        });
+      }
+    },
+    customSort(data) {
+      // 瀹氫箟鎮ㄦ湡鏈涚殑鐥呭尯椤哄簭锛堟墿灞曞埌鍥涘崄浜旓級
+      const order = [
+        "涓�",
+        "浜�",
+        "涓�",
+        "鍥�",
+        "浜�",
+        "鍏�",
+        "涓�",
+        "鍏�",
+        "涔�",
+        "鍗�",
+        "鍗佷竴",
+        "鍗佷簩",
+        "鍗佷笁",
+        "鍗佸洓",
+        "鍗佷簲",
+        "鍗佸叚",
+        "鍗佷竷",
+        "鍗佸叓",
+        "鍗佷節",
+        "浜屽崄",
+        "浜屽崄涓�",
+        "浜屽崄浜�",
+        "浜屽崄涓�",
+        "浜屽崄鍥�",
+        "浜屽崄浜�",
+        "浜屽崄鍏�",
+        "浜屽崄涓�",
+        "浜屽崄鍏�",
+        "浜屽崄涔�",
+        "涓夊崄",
+        "涓夊崄涓�",
+        "涓夊崄浜�",
+        "涓夊崄涓�",
+        "涓夊崄鍥�",
+        "涓夊崄浜�",
+        "涓夊崄鍏�",
+        "涓夊崄涓�",
+        "涓夊崄鍏�",
+        "涓夊崄涔�",
+        "鍥涘崄",
+        "鍥涘崄涓�",
+        "鍥涘崄浜�",
+        "鍥涘崄涓�",
+        "鍥涘崄鍥�",
+        "鍥涘崄浜�",
+      ];
+
+      return data.sort((a, b) => {
+        // 鎻愬彇鐥呭尯鍚嶇О涓殑涓枃鏁板瓧閮ㄥ垎
+        const getIndex = (name) => {
+          if (!name || typeof name !== "string") return -1;
+
+          // 鍖归厤涓枃鏁板瓧
+          const chineseMatch = name.match(/^([涓�浜屼笁鍥涗簲鍏竷鍏節鍗乚+)/);
+          if (chineseMatch && chineseMatch[1]) {
+            return order.indexOf(chineseMatch[1]);
+          }
+
+          // 鍖归厤闃挎媺浼暟瀛�
+          const arabicMatch = name.match(/^(\d+)/);
+          if (arabicMatch && arabicMatch[1]) {
+            const num = parseInt(arabicMatch[1], 10);
+            if (num >= 1 && num <= 45) {
+              return num - 1; // 鍥犱负鏁扮粍绱㈠紩浠�0寮�濮�
+            }
+          }
+
+          return -1;
+        };
+
+        const indexA = getIndex(a.leavehospitaldistrictname);
+        const indexB = getIndex(b.leavehospitaldistrictname);
+
+        // 鎺掑簭閫昏緫
+        if (indexA === -1 && indexB === -1) {
+          return (a.leavehospitaldistrictname || "").localeCompare(
+            b.leavehospitaldistrictname || ""
+          );
+        }
+        if (indexA === -1) return 1;
+        if (indexB === -1) return -1;
+        return indexA - indexB;
       });
     },
     getRowKey(row) {
@@ -1065,9 +1717,16 @@
       const params = {
         ...this.queryParams,
         // 濡傛灉閫夋嫨浜�"鍏ㄩ儴"锛屽垯浼犳墍鏈夌梾鍖�/绉戝浠g爜
+        deptcodes: this.queryParams.deptcodes.includes("all")
+          ? this.allDeptCodes
+          : this.queryParams.deptcodes,
         leavehospitaldistrictcodes: [row.leavehospitaldistrictcode],
         drcode: "1",
       };
+
+      // 绉婚櫎鍙兘瀛樺湪鐨�"all"鍊�
+      delete params.leavehospitaldistrictcodes.all;
+      delete params.deptcodes.all;
       // 濡傛灉璇ヨ杩樻病鏈夊姞杞藉尰鐢熸暟鎹紝鍒欏姞杞�
       if (!row.doctorStats) {
         this.loading = true;
@@ -1089,7 +1748,7 @@
           sums[index] = "鍚堣";
           return;
         }
-         if (index === 1||index === 2) {
+        if (index === 1 || index === 2) {
           sums[index] = "/";
           return;
         }
@@ -1324,6 +1983,75 @@
         this.Seedloading = false;
       });
     },
+    Seedetailstion() {
+      selectTimelyRate(this.patientqueryParams).then((response) => {
+        this.logsheetlist = response.data.detail;
+        this.patienttotal = response.data.total;
+        this.Seedloading = false;
+      });
+    },
+    viewDetails(row, title) {
+      this.infotitleVisible = true;
+      this.infotitle = title;
+      this.infotitlelist = row; // 鍋囪row灏辨槸闇�瑕佸睍绀虹殑璇︾粏鏁扮粍
+      console.log(this.infotitlelist, "this.infotitlelist");
+
+      this.infotitlelist.forEach((item) => {
+        let idArray = null;
+
+        if (item.preachform) {
+          if (item.endtime) {
+            item.preachformson = item.preachform;
+            idArray = item.preachform.split(",");
+          }
+
+          item.preachform = idArray.map((value) => {
+            // 鏌ユ壘id瀵瑰簲鐨勫璞�
+            const item = this.checkboxlist.find((item) => item.value == value);
+            // 濡傛灉鎵惧埌瀵瑰簲鐨刬d锛岃繑鍥瀕abel鍊硷紝鍚﹀垯杩斿洖null
+            return item ? item.label : null;
+          });
+        }
+      });
+      // 鍒濆鍖栧姞杞�
+      this.loadIndex = 0;
+      this.currentDisplayList = [];
+      this.$nextTick(() => {
+        this.loadMoreData();
+      });
+    },
+    loadMoreData() {
+      if (this.isLoading) return;
+      this.isLoading = true;
+
+      // 妯℃嫙寮傛鍔犺浇锛屽疄闄呭彲鑳芥槸鐩存帴鍒囩墖鏈湴鏁版嵁
+      setTimeout(() => {
+        console.log(this.infotitlelist, "this.infotitlelist");
+
+        const nextChunk = this.infotitlelist.slice(
+          this.loadIndex,
+          this.loadIndex + this.pageSize
+        );
+        this.currentDisplayList = this.currentDisplayList.concat(nextChunk);
+        this.loadIndex += this.pageSize;
+        this.isLoading = false;
+      }, 200);
+    },
+    handleScroll(event) {
+      const scrollContainer = event.target;
+      // 鍒ゆ柇鏄惁婊氬姩鍒板簳閮�
+      const isAtBottom =
+        scrollContainer.scrollTop + scrollContainer.clientHeight >=
+        scrollContainer.scrollHeight - 10;
+
+      if (
+        isAtBottom &&
+        !this.isLoading &&
+        this.loadIndex < this.infotitlelist.length
+      ) {
+        this.loadMoreData();
+      }
+    },
     SeedetailsgGo(row) {
       this.SeedetailsVisible = false;
       let type = "";
@@ -1460,29 +2188,353 @@
         })
         .catch(() => {});
     },
-    /** 瀵煎嚭鎸夐挳鎿嶄綔 */
-    handleExport() {
-      const params = {
-        ...this.queryParams,
-        // 濡傛灉閫夋嫨浜�"鍏ㄩ儴"锛屽垯浼犳墍鏈夌梾鍖�/绉戝浠g爜
-        leavehospitaldistrictcodes:
-          this.queryParams.leavehospitaldistrictcodes.includes("all")
-            ? this.allWardCodes
-            : this.queryParams.leavehospitaldistrictcodes,
-        deptcodes: this.queryParams.deptcodes.includes("all")
-          ? this.allDeptCodes
-          : this.queryParams.deptcodes,
-      };
-       delete params.leavehospitaldistrictcodes.all;
-      delete params.deptcodes.all;
-      this.download(
-        "smartor/serviceSubtask/getSfStatisticsExport",
-        {
-          ...params,
-        },
-        `user_${new Date().getTime()}.xlsx`
-      );
+    // 瀵煎嚭鏂规硶
+    // 鏇挎崲鎮ㄥ師鏉ョ殑 exportTable 鏂规硶
+    async exportTable() {
+      try {
+        // 1. 鑾峰彇骞舵牸寮忓寲鏃ユ湡鑼冨洿
+        let dateRangeString = ""; // 鐢ㄤ簬鏂囦欢鍚�
+        let sheetNameSuffix = ""; // 鐢ㄤ簬宸ヤ綔琛ㄥ悕
+
+        // 妫�鏌ユ槸鍚﹀瓨鍦ㄩ�変腑鐨勬棩鏈熻寖鍥�
+        if (
+          this.queryParams.dateRange &&
+          this.queryParams.dateRange.length === 2
+        ) {
+          const startDateStr = this.queryParams.dateRange[0]; // 寮�濮嬫棩鏈熷瓧绗︿覆锛屼緥濡� "2026-01-01 00:00:00"
+          const endDateStr = this.queryParams.dateRange[1]; // 缁撴潫鏃ユ湡瀛楃涓�
+
+          // 鏍煎紡鍖栨棩鏈熶负 YYYY-MM-DD锛堝幓鎺夋椂闂撮儴鍒嗭級
+          const formatDateForDisplay = (dateTimeStr) => {
+            return dateTimeStr.split(" ")[0]; // 鍙栫┖鏍煎墠鐨勯儴鍒嗭紝鍗� "YYYY-MM-DD"
+          };
+
+          const startDateFormatted = formatDateForDisplay(startDateStr);
+          const endDateFormatted = formatDateForDisplay(endDateStr);
+
+          // 鏋勫缓鏃ユ湡鑼冨洿瀛楃涓�
+          dateRangeString = `${startDateFormatted}鑷�${endDateFormatted}`;
+          sheetNameSuffix = `${startDateFormatted}鑷�${endDateFormatted}`;
+        } else {
+          // 濡傛灉娌℃湁閫夋嫨鏃ユ湡鑼冨洿锛屽垯浣跨敤褰撳墠鏈堜唤浣滀负澶囬�夋柟妗�
+          const now = new Date();
+          const currentMonth = now.getMonth() + 1;
+          dateRangeString = `${currentMonth}鏈坄;
+          sheetNameSuffix = `${currentMonth}鏈坄;
+        }
+
+        // 2. 鍔ㄦ�佹瀯寤烘枃浠跺悕鍜屽伐浣滆〃鍚�
+        const excelName = `鍑洪櫌闅忚缁熻琛╛${dateRangeString}.xlsx`;
+        const worksheetName = `闅忚缁熻_${sheetNameSuffix}`; // 宸ヤ綔琛ㄥ悕涓嶈兘瓒呰繃31涓瓧绗2](@ref)
+        // 鍒涘缓鏂扮殑宸ヤ綔绨垮拰宸ヤ綔琛�
+        const workbook = new ExcelJS.Workbook();
+        const worksheet = workbook.addWorksheet(worksheetName); // 浣跨敤鍔ㄦ�佸伐浣滆〃鍚�
+        // 瀹氫箟鏍峰紡锛堟柊澧炴�绘爣棰樻牱寮忥級
+        const titleStyle = {
+          font: {
+            name: "寰蒋闆呴粦",
+            size: 16,
+            bold: true,
+            color: { argb: "FF000000" },
+          },
+          fill: {
+            type: "pattern",
+            pattern: "solid",
+            fgColor: { argb: "FFE6F3FF" },
+          },
+          alignment: {
+            vertical: "middle",
+            horizontal: "center",
+            wrapText: true,
+          },
+          border: {
+            top: { style: "thin", color: { argb: "FFD0D0D0" } },
+            left: { style: "thin", color: { argb: "FFD0D0D0" } },
+            bottom: { style: "thin", color: { argb: "FFD0D0D0" } },
+            right: { style: "thin", color: { argb: "FFD0D0D0" } },
+          },
+        };
+        // 瀹氫箟鏍峰紡
+        const headerStyle = {
+          font: {
+            name: "寰蒋闆呴粦",
+            size: 11,
+            bold: true,
+            color: { argb: "FF000000" },
+          },
+          fill: {
+            type: "pattern",
+            pattern: "solid",
+            fgColor: { argb: "FFF5F7FA" },
+          },
+          alignment: {
+            vertical: "middle",
+            horizontal: "center",
+            wrapText: true,
+          },
+          border: {
+            top: { style: "thin", color: { argb: "FFD0D0D0" } },
+            left: { style: "thin", color: { argb: "FFD0D0D0" } },
+            bottom: { style: "thin", color: { argb: "FFD0D0D0" } },
+            right: { style: "thin", color: { argb: "FFD0D0D0" } },
+          },
+        };
+
+        const cellStyle = {
+          font: {
+            name: "瀹嬩綋",
+            size: 10,
+            color: { argb: "FF000000" },
+          },
+          alignment: {
+            vertical: "middle",
+            horizontal: "center",
+          },
+          border: {
+            top: { style: "thin", color: { argb: "FFD0D0D0" } },
+            left: { style: "thin", color: { argb: "FFD0D0D0" } },
+            bottom: { style: "thin", color: { argb: "FFD0D0D0" } },
+            right: { style: "thin", color: { argb: "FFD0D0D0" } },
+          },
+        };
+
+        const summaryStyle = {
+          font: {
+            name: "瀹嬩綋",
+            size: 10,
+            bold: true,
+            color: { argb: "FF409EFF" },
+          },
+          fill: {
+            type: "pattern",
+            pattern: "solid",
+            fgColor: { argb: "FFF5F7FA" },
+          },
+          alignment: {
+            vertical: "middle",
+            horizontal: "center",
+          },
+          border: {
+            top: { style: "thin", color: { argb: "FFD0D0D0" } },
+            left: { style: "thin", color: { argb: "FFD0D0D0" } },
+            bottom: { style: "thin", color: { argb: "FFD0D0D0" } },
+            right: { style: "thin", color: { argb: "FFD0D0D0" } },
+          },
+        };
+        // 1. 娣诲姞鎬绘爣棰樿锛堢涓�琛岋級
+        worksheet.mergeCells(1, 1, 1, 23); // 鍚堝苟A1鍒癢1鐨勬墍鏈夊垪[1,4](@ref)
+        const titleCell = worksheet.getCell(1, 1);
+        titleCell.value = `${sheetNameSuffix}鍑洪櫌闅忚缁熻琛╜; // 浣跨敤鏂囦欢鍚嶄綔涓烘�绘爣棰�
+        titleCell.style = titleStyle;
+        worksheet.getRow(1).height = 35; // 璁剧疆鎬绘爣棰樿楂�
+        // 1. 棣栧厛锛屽垱寤哄苟璁剧疆绗簩琛岋紙瀛愯〃澶达級鐨勬墍鏈夊崟鍏冩牸
+        const secondRowHeaders = [
+          "", // A2 灞曞紑鍒楀崰浣嶏紙鍏跺�煎皢鐢辩涓�琛屽悎骞跺悗鐨勪富鍗曞厓鏍煎喅瀹氾級
+          "鍑洪櫌鐥呭尯",
+          "绉戝",
+          "鍑洪櫌浜烘",
+          "鏃犻渶闅忚浜烘",
+          "搴旈殢璁夸汉娆�", // B2 to F2
+          // 棣栨鍑洪櫌闅忚瀛愯〃澶�
+          "闇�闅忚",
+          "寰呴殢璁�",
+          "闅忚鎴愬姛",
+          "闅忚澶辫触",
+          "闅忚鐜�",
+          "鍙婃椂鐜�",
+          "浜哄伐",
+          "鐭俊",
+          "寰俊",
+          // 鍐嶆鍑洪櫌闅忚瀛愯〃澶�
+          "闇�闅忚",
+          "寰呴殢璁�",
+          "闅忚鎴愬姛",
+          "闅忚澶辫触",
+          "闅忚鐜�",
+          "浜哄伐",
+          "鐭俊",
+          "寰俊",
+        ];
+
+        // 娣诲姞绗簩琛岋紙鍘熺涓�琛屼笅绉伙級
+        secondRowHeaders.forEach((header, index) => {
+          const cell = worksheet.getCell(3, index + 1); // 鏀逛负绗�3琛�
+          cell.value = header;
+          cell.style = headerStyle;
+        });
+
+        // 3. 璋冩暣鍘熷悎骞跺崟鍏冩牸浣嶇疆锛堝師绗�1琛屽悎骞跺崟鍏冩牸涓嬬Щ鍒扮2琛岋級
+        // 鍚堝苟 A2:A3
+        worksheet.mergeCells(2, 1, 3, 1);
+        worksheet.getCell(2, 1).value = "";
+        worksheet.getCell(2, 1).style = headerStyle;
+
+        // 鍚堝苟 B2:B3
+        worksheet.mergeCells(2, 2, 3, 2);
+        worksheet.getCell(2, 2).value = "鍑洪櫌鐥呭尯";
+        worksheet.getCell(2, 2).style = headerStyle;
+
+        // 鍚堝苟 C2:C3
+        worksheet.mergeCells(2, 3, 3, 3);
+        worksheet.getCell(2, 3).value = "绉戝";
+        worksheet.getCell(2, 3).style = headerStyle;
+
+        // 鍚堝苟 D2:D3
+        worksheet.mergeCells(2, 4, 3, 4);
+        worksheet.getCell(2, 4).value = "鍑洪櫌浜烘";
+        worksheet.getCell(2, 4).style = headerStyle;
+
+        // 鍚堝苟 E2:E3
+        worksheet.mergeCells(2, 5, 3, 5);
+        worksheet.getCell(2, 5).value = "鏃犻渶闅忚浜烘";
+        worksheet.getCell(2, 5).style = headerStyle;
+
+        // 鍚堝苟 F2:F3
+        worksheet.mergeCells(2, 6, 3, 6);
+        worksheet.getCell(2, 6).value = "搴旈殢璁夸汉娆�";
+        worksheet.getCell(2, 6).style = headerStyle;
+
+        // 4. 璋冩暣妯悜鍚堝苟鏍囬浣嶇疆锛堜笅绉诲埌绗�2琛岋級
+        // 棣栨鍑洪櫌闅忚锛堝悎骞禛2:O2锛�
+        worksheet.mergeCells(2, 7, 2, 15); // G2:O2
+        worksheet.getCell(2, 7).value = "棣栨鍑洪櫌闅忚";
+        worksheet.getCell(2, 7).style = headerStyle;
+
+        // 鍐嶆鍑洪櫌闅忚锛堝悎骞禤2:W2锛�
+        worksheet.mergeCells(2, 16, 2, 23); // P2:W2
+        worksheet.getCell(2, 16).value = "鍐嶆鍑洪櫌闅忚";
+        worksheet.getCell(2, 16).style = headerStyle;
+
+        // 5. 璁剧疆琛岄珮
+        worksheet.getRow(1).height = 35; // 鎬绘爣棰樿楂�
+        worksheet.getRow(2).height = 28; // 鍘熺涓�琛屼笅绉�
+        worksheet.getRow(3).height = 25; // 鍘熺浜岃涓嬬Щ
+
+        // 6. 娣诲姞鏁版嵁琛岋紙娉ㄦ剰琛岀储寮曢渶瑕�+1锛屽洜涓轰笂闈㈡彃鍏ヤ簡涓�琛岋級
+        this.userList.forEach((item, rowIndex) => {
+          const dataRow = worksheet.addRow(
+            [
+              "", // 灞曞紑鍒�
+              item.leavehospitaldistrictname || "",
+              item.deptname || "",
+              item.dischargeCount || 0,
+              item.nonFollowUp || 0,
+              item.followUpNeeded || 0,
+              // 棣栨鍑洪櫌闅忚鏁版嵁
+              item.needFollowUp || 0,
+              item.pendingFollowUp || 0,
+              item.followUpSuccess || 0,
+              item.followUpFail || 0,
+              item.followUpRate || "0%",
+              item.rate ? (Number(item.rate) * 100).toFixed(2) + "%" : "0%",
+              item.manual || 0,
+              item.sms || 0,
+              item.weChat || 0,
+              // 鍐嶆鍑洪櫌闅忚鏁版嵁
+              item.needFollowUpAgain || 0,
+              item.pendingFollowUpAgain || 0,
+              item.followUpSuccessAgain || 0,
+              item.followUpFailAgain || 0,
+              item.followUpRateAgain || "0%",
+              item.manualAgain || 0,
+              item.smsAgain || 0,
+              item.weChatAgain || 0,
+            ],
+            rowIndex + 4
+          ); // 浠庣4琛屽紑濮嬫坊鍔犳暟鎹紙鍘熺3琛岋級
+
+          // 搴旂敤鏁版嵁琛屾牱寮�
+          dataRow.eachCell((cell) => {
+            cell.style = cellStyle;
+          });
+          dataRow.height = 24;
+        });
+
+        // 娣诲姞鍚堣琛�
+        const summaries = this.getSummaries({
+          columns: [
+            { property: "" },
+            { property: "leavehospitaldistrictname" },
+            { property: "deptname" },
+            { property: "dischargeCount" },
+            { property: "nonFollowUp" },
+            { property: "followUpNeeded" },
+            { property: "needFollowUp" },
+            { property: "pendingFollowUp" },
+            { property: "followUpSuccess" },
+            { property: "followUpFail" },
+            { property: "followUpRate" },
+            { property: "rate" },
+            { property: "manual" },
+            { property: "sms" },
+            { property: "weChat" },
+            { property: "needFollowUpAgain" },
+            { property: "pendingFollowUpAgain" },
+            { property: "followUpSuccessAgain" },
+            { property: "followUpFailAgain" },
+            { property: "followUpRateAgain" },
+            { property: "manualAgain" },
+            { property: "smsAgain" },
+            { property: "weChatAgain" },
+          ],
+          data: this.userList,
+        });
+
+        const summaryRow = worksheet.addRow(summaries);
+        summaryRow.eachCell((cell, colNumber) => {
+          cell.style = summaryStyle;
+          // 绗竴鍒楁樉绀�"鍚堣"
+          if (colNumber === 1) {
+            cell.value = "鍚堣";
+          }
+        });
+        summaryRow.height = 28;
+
+        // 璁剧疆鍒楀
+        worksheet.columns = [
+          { width: 8 }, // 灞曞紑鍒�
+          { width: 20 }, // 鍑洪櫌鐥呭尯
+          { width: 15 }, // 绉戝
+          { width: 12 }, // 鍑洪櫌浜烘
+          { width: 12 }, // 鏃犻渶闅忚浜烘
+          { width: 12 }, // 搴旈殢璁夸汉娆�
+          // 棣栨鍑洪櫌闅忚鍒�
+          { width: 10 },
+          { width: 10 },
+          { width: 10 },
+          { width: 10 },
+          { width: 12 },
+          { width: 12 },
+          { width: 8 },
+          { width: 8 },
+          { width: 8 },
+          // 鍐嶆鍑洪櫌闅忚鍒�
+          { width: 10 },
+          { width: 10 },
+          { width: 10 },
+          { width: 10 },
+          { width: 12 },
+          { width: 8 },
+          { width: 8 },
+          { width: 8 },
+        ];
+
+        // 鐢熸垚骞朵笅杞芥枃浠�
+        const buffer = await workbook.xlsx.writeBuffer();
+        const blob = new Blob([buffer], {
+          type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
+        });
+        saveAs(blob, excelName);
+
+        this.$message.success("瀵煎嚭鎴愬姛");
+        return true;
+      } catch (error) {
+        console.error("瀵煎嚭澶辫触:", error);
+        this.$message.error(`瀵煎嚭澶辫触: ${error.message}`);
+        return false;
+      }
     },
+
     // 鏄剧ず鍥捐〃寮圭獥
 
     showChartDialog() {
@@ -1944,9 +2996,21 @@
 }
 
 // 鐧惧垎姣斿瓧娈电壒娈婃牱寮�
-.your-table-container ::v-deep .el-table__footer .el-table__cell[data-field="followUpRate"] .cell,
-.your-table-container ::v-deep .el-table__footer .el-table__cell[data-field="rate"] .cell,
-.your-table-container ::v-deep .el-table__footer .el-table__cell[data-field="followUpRateAgain"] .cell {
+.your-table-container
+  ::v-deep
+  .el-table__footer
+  .el-table__cell[data-field="followUpRate"]
+  .cell,
+.your-table-container
+  ::v-deep
+  .el-table__footer
+  .el-table__cell[data-field="rate"]
+  .cell,
+.your-table-container
+  ::v-deep
+  .el-table__footer
+  .el-table__cell[data-field="followUpRateAgain"]
+  .cell {
   color: #e6a23c !important;
   font-weight: 700 !important;
 }
@@ -2016,6 +3080,10 @@
   width: 100px;
   height: 50px;
 }
+.data-list {
+  max-height: 800px;
+  overflow-y: auto;
+}
 .documentf {
   display: flex;
   justify-content: flex-end;
diff --git a/src/views/sfstatistics/percentage/satisfaction.vue b/src/views/sfstatistics/percentage/satisfaction.vue
index 75de5a7..be3d69b 100644
--- a/src/views/sfstatistics/percentage/satisfaction.vue
+++ b/src/views/sfstatistics/percentage/satisfaction.vue
@@ -61,7 +61,7 @@
                 </el-select>
               </el-form-item>
 
-              <el-form-item label="缁熻棰樼洰" prop="userName">
+              <el-form-item label="鏈嶅姟绫诲瀷" prop="userName">
                 <el-select
                   v-model="queryParams.serviceType"
                   multiple
@@ -224,10 +224,8 @@
               >
                 <template slot-scope="scope">
                   <span class="button-zx"
-                      >{{
-                        (Number(scope.row.joyTotal) * 100).toFixed(2)
-                      }}%</span
-                    >
+                    >{{ (Number(scope.row.joyTotal) * 100).toFixed(2) }}%</span
+                  >
                 </template>
               </el-table-column>
               <el-table-column
@@ -510,24 +508,37 @@
       </div>
     </el-dialog>
     <!-- 鍗曠瀹ょ粺璁¤鎯� -->
-     <el-dialog :visible.sync="topicVisible" width="45%">
+    <el-dialog :visible.sync="topicVisible" width="45%">
       <div class="topicdia">
-        <div class="top-text">{{ topicvalue.name }}</div>
-        <div class="top-mintext">闅忚瀹屾垚鏁皗{ topicvalue.number }}</div>
+        <div class="top-text">
+          {{ topicvalue.name }}<span>婊℃剰搴︽寚鏍囪鎯�</span>
+        </div>
         <div style="overflow-x: hidden; overflow-y: auto; max-height: 65vh">
-          <div class="ttaabbcc" v-for="item in topiclist" :key="item.name">
+          <div
+            class="ttaabbcc"
+            v-for="(item, index) in topiclist"
+            :key="item.name"
+          >
             <div class="describe">
-              绗瑊{ item.number }}棰橈細 {{ item.name }}?<span
-                >[{{ item.type == 1 ? "鍗曢�夐" : "澶氶�夐" }}]</span
+              绗瑊{ index }}棰橈細 {{ item.scriptContent }}?<span
+                >[{{ item.scriptType == 1 ? "鍗曢�夐" : "澶氶�夐" }}]</span
               >
             </div>
             <div>
-              <el-table :data="tableData" style="width: 100%">
-                <el-table-column prop="date" label="闂閫夐」">
+              <el-table :data="item.details" style="width: 100%">
+                <el-table-column prop="optionText" label="闂閫夐」">
                 </el-table-column>
-                <el-table-column prop="name" label="閫夋嫨浜烘暟">
+                <el-table-column prop="chosenQuantity" label="閫夋嫨浜烘暟">
                 </el-table-column>
-                <el-table-column prop="address" label="姣斾緥"> </el-table-column>
+                <el-table-column prop="chosenPercentage" label="姣斾緥">
+                  <template slot-scope="scope">
+                    <span class="button-zx"
+                      >{{
+                        (Number(scope.row.chosenPercentage) * 100).toFixed(2)
+                      }}%</span
+                    >
+                  </template>
+                </el-table-column>
               </el-table>
             </div>
           </div>
@@ -541,19 +552,15 @@
 </template>
 
 <script>
-import {
-  toamendtag,
-  addapitag,
-  deletetag,
-  changetagcategory,
-} from "@/api/system/label";
+
 import store from "@/store";
 import {
-  getSfStatisticsJoydetails,
   getSfStatisticsJoy,
+  getSfStatisticsJoyInfo,
   selectTimelyRate,
 } from "@/api/system/user";
-
+import ExcelJS from "exceljs";
+import { saveAs } from "file-saver";
 import Treeselect from "@riophae/vue-treeselect";
 import "@riophae/vue-treeselect/dist/vue-treeselect.css";
 const shortcuts = [
@@ -641,7 +648,7 @@
           type: 1,
         },
       ],
-        tableData: [
+      tableData: [
         {
           date: "濂�",
           name: 12,
@@ -721,8 +728,6 @@
       },
       // 鏌ヨ鏍囩鍒楄〃鍙傛暟
       queryParams: {
-        pageNum: 1,
-        pageSize: 10,
         serviceType: [2],
         dateRange: [],
         statisticaltype: 1,
@@ -752,6 +757,7 @@
     getList() {
       // 澶勭悊鏌ヨ鍙傛暟
       const params = {
+        configKey: "joyCount",
         ...this.queryParams,
         // 濡傛灉閫夋嫨浜�"鍏ㄩ儴"锛屽垯浼犳墍鏈夌梾鍖�/绉戝浠g爜
         leavehospitaldistrictcodes:
@@ -762,13 +768,15 @@
           ? this.allDeptCodes
           : this.queryParams.deptcodes,
       };
+      this.loading = true;
 
       // 绉婚櫎鍙兘瀛樺湪鐨�"all"鍊�
       delete params.leavehospitaldistrictcodes.all;
       delete params.deptcodes.all;
       getSfStatisticsJoy(params).then((response) => {
-        console.log(response);
-        // this.total = response.total;
+        this.loading = false;
+
+        this.total = response.total;
         this.userList = response.data;
       });
     },
@@ -887,28 +895,28 @@
     // 璋冭捣璇︽儏
     getinfo(row) {
       this.topicVisible = true;
-
-    },
-    // 娣诲姞/淇敼鏍囩
-    Maintenancetag() {
-      if (this.lstamendtag) {
-        toamendtag(this.addDateRange(this.tagform)).then((response) => {
-          console.log(response);
-          this.getList();
-        });
-      } else {
-        addapitag(this.addDateRange(this.tagform)).then((response) => {
-          console.log(response);
-          this.getList();
-        });
-      }
-      this.tagform = {
-        isupload: "",
-        tagname: "",
-        tagcategoryid: "",
-        tagdescription: "",
-        tagid: "",
+      // 澶勭悊鏌ヨ鍙傛暟
+      const params = {
+        configKey: "joyCount",
+        ...this.queryParams,
       };
+      if (this.queryParams.statisticaltype == 1) {
+        this.topicvalue.name = row.leavehospitaldistrictname;
+
+        params.leavehospitaldistrictcodes = [row.leavehospitaldistrictcode];
+      } else {
+        this.topicvalue.name = row.deptname;
+
+        params.deptcodes = [row.deptcode];
+      }
+
+      // 绉婚櫎鍙兘瀛樺湪鐨�"all"鍊�
+      delete params.leavehospitaldistrictcodes.all;
+      delete params.deptcodes.all;
+      getSfStatisticsJoyInfo(params).then((response) => {
+        console.log(response);
+        this.topiclist = response.data;
+      });
     },
     routerErr(row) {
       console.log(row, "璺宠浆寮傚父");
@@ -939,22 +947,7 @@
       };
       this.resetForm("form");
     },
-    // 鏍囩鐘舵�佷慨鏀�
-    handleStatusChange(row) {
-      console.log(row.isupload);
-      let text = row.isupload === "0" ? "鍚敤" : "鍋滅敤";
-      this.$modal
-        .confirm('纭瑕�"' + text + '""' + row.tagname + '"鏍囩鍚楋紵')
-        .then(function () {
-          return changetagcategory(row.tagid, row.isupload);
-        })
-        .then(() => {
-          this.$modal.msgSuccess(text + "鎴愬姛");
-        })
-        .catch(function () {
-          row.isupload = row.isupload === "0" ? "1" : "0";
-        });
-    },
+
     /** 鎼滅储鎸夐挳鎿嶄綔 */
     handleQuery() {
       this.queryParams.pageNum = 1;
@@ -985,36 +978,193 @@
       this.multiple = !selection.length;
     },
 
-    /** 鍒犻櫎鎸夐挳鎿嶄綔 */
-    handleDelete(row) {
-      console.log(row, "鍒犻櫎寮圭獥");
-      const tagids = row.tagid || this.ids;
-      console.log(tagids);
-      const tagname = row.tagname;
-      this.$modal
-        .confirm(
-          tagname
-            ? '鏄惁纭鍒犻櫎鏍囩鍚嶇О涓�"' + tagname + '"鐨勬暟鎹」锛�'
-            : "鏄惁纭鍒犻櫎閫変腑鐨勬暟鎹」锛�"
-        )
-        .then(function () {
-          return deletetag(tagids);
-        })
-        .then(() => {
-          this.getList();
-          this.$modal.msgSuccess("鍒犻櫎鎴愬姛");
-        })
-        .catch(() => {});
-    },
+
     /** 瀵煎嚭鎸夐挳鎿嶄綔 */
-    handleExport() {
-      this.download(
-        "smartor/serviceSubtask/getSfStatisticsExport",
-        {
-          ...this.queryParams,
-        },
-        `user_${new Date().getTime()}.xlsx`
-      );
+    /** 瀵煎嚭鎸夐挳鎿嶄綔 */
+    async handleExport() {
+      try {
+        // 鑾峰彇骞舵牸寮忓寲鏃ユ湡鑼冨洿
+        let dateRangeString = "";
+        let sheetNameSuffix = "";
+
+        // 妫�鏌ユ槸鍚﹀瓨鍦ㄩ�変腑鐨勬棩鏈熻寖鍥�
+        if (
+          this.queryParams.dateRange &&
+          this.queryParams.dateRange.length === 2
+        ) {
+          const startDateStr = this.queryParams.dateRange[0]; // 寮�濮嬫棩鏈燂紝鏍煎紡 "yyyy-MM-dd"
+          const endDateStr = this.queryParams.dateRange[1]; // 缁撴潫鏃ユ湡
+
+          // 鐩存帴浣跨敤鏃ユ湡閮ㄥ垎锛堝凡缁忔槸 yyyy-MM-dd 鏍煎紡锛�
+          const startDateFormatted = startDateStr;
+          const endDateFormatted = endDateStr;
+
+          // 鏋勫缓鏃ユ湡鑼冨洿瀛楃涓�
+          dateRangeString = `${startDateFormatted}鑷�${endDateFormatted}`;
+          sheetNameSuffix = `${startDateFormatted}鑷�${endDateFormatted}`;
+        } else {
+          // 濡傛灉娌℃湁閫夋嫨鏃ユ湡鑼冨洿锛屽垯浣跨敤褰撳墠鏈堜唤浣滀负澶囬�夋柟妗�
+          const now = new Date();
+          const currentMonth = now.getMonth() + 1;
+          dateRangeString = `${currentMonth}鏈坄;
+          sheetNameSuffix = `${currentMonth}鏈坄;
+        }
+
+        // 鏋勫缓鏂囦欢鍚嶅拰宸ヤ綔琛ㄥ悕
+        const excelName = `婊℃剰搴︾粺璁¤〃_${dateRangeString}.xlsx`;
+        const worksheetName = `婊℃剰搴︾粺璁${sheetNameSuffix}`;
+
+        // 鍒涘缓宸ヤ綔绨垮拰宸ヤ綔琛�
+        const workbook = new ExcelJS.Workbook();
+        const worksheet = workbook.addWorksheet(worksheetName);
+
+        // 瀹氫箟鏍峰紡
+        const titleStyle = {
+          font: {
+            name: "寰蒋闆呴粦",
+            size: 16,
+            bold: true,
+            color: { argb: "FF000000" },
+          },
+          fill: {
+            type: "pattern",
+            pattern: "solid",
+            fgColor: { argb: "FFE6F3FF" },
+          },
+          alignment: {
+            vertical: "middle",
+            horizontal: "center",
+            wrapText: true,
+          },
+          border: {
+            top: { style: "thin", color: { argb: "FFD0D0D0" } },
+            left: { style: "thin", color: { argb: "FFD0D0D0" } },
+            bottom: { style: "thin", color: { argb: "FFD0D0D0" } },
+            right: { style: "thin", color: { argb: "FFD0D0D0" } },
+          },
+        };
+
+        const headerStyle = {
+          font: {
+            name: "寰蒋闆呴粦",
+            size: 11,
+            bold: true,
+            color: { argb: "FF000000" },
+          },
+          fill: {
+            type: "pattern",
+            pattern: "solid",
+            fgColor: { argb: "FFF5F7FA" },
+          },
+          alignment: {
+            vertical: "middle",
+            horizontal: "center",
+            wrapText: true,
+          },
+          border: {
+            top: { style: "thin", color: { argb: "FFD0D0D0" } },
+            left: { style: "thin", color: { argb: "FFD0D0D0" } },
+            bottom: { style: "thin", color: { argb: "FFD0D0D0" } },
+            right: { style: "thin", color: { argb: "FFD0D0D0" } },
+          },
+        };
+
+        const cellStyle = {
+          font: {
+            name: "瀹嬩綋",
+            size: 10,
+            color: { argb: "FF000000" },
+          },
+          alignment: {
+            vertical: "middle",
+            horizontal: "center",
+          },
+          border: {
+            top: { style: "thin", color: { argb: "FFD0D0D0" } },
+            left: { style: "thin", color: { argb: "FFD0D0D0" } },
+            bottom: { style: "thin", color: { argb: "FFD0D0D0" } },
+            right: { style: "thin", color: { argb: "FFD0D0D0" } },
+          },
+        };
+
+        // 娣诲姞鎬绘爣棰�
+        worksheet.mergeCells(1, 1, 1, 10);
+        const titleCell = worksheet.getCell(1, 1);
+        titleCell.value = `婊℃剰搴︾粺璁¤〃锛�${sheetNameSuffix}锛塦;
+        titleCell.style = titleStyle;
+        worksheet.getRow(1).height = 35;
+
+        // 娣诲姞琛ㄥご
+        const headers = [
+          "鍑洪櫌鐥呭尯",
+          "绉戝",
+          "鍑洪櫌浜烘",
+          "鏃犻渶闅忚浜烘",
+          "搴旈殢璁夸汉娆�",
+          "闅忚鐜�",
+          "鍙婃椂鐜�",
+          "婊℃剰搴﹂鐩�婚噺",
+          "婊℃剰搴﹀~鎶ラ噺",
+          "瀹屾垚姣旂巼",
+        ];
+
+        const headerRow = worksheet.addRow(headers);
+        headerRow.eachCell((cell) => {
+          cell.style = headerStyle;
+        });
+        headerRow.height = 25;
+
+        // 娣诲姞鏁版嵁琛�
+        this.userList.forEach((item) => {
+          const dataRow = worksheet.addRow([
+            item.leavehospitaldistrictname || "",
+            item.deptname || "",
+            item.dischargeCount || 0,
+            item.nonFollowUp || 0,
+            item.followUpNeeded || 0,
+            item.followUpRate || "0%",
+            item.rate ? (Number(item.rate) * 100).toFixed(2) + "%" : "0%",
+            item.joyAllCount || 0,
+            item.joyCount || 0,
+            item.joyTotal
+              ? (Number(item.joyTotal) * 100).toFixed(2) + "%"
+              : "0%",
+          ]);
+
+          dataRow.eachCell((cell) => {
+            cell.style = cellStyle;
+          });
+          dataRow.height = 22;
+        });
+
+        // 璁剧疆鍒楀
+        worksheet.columns = [
+          { width: 20 }, // 鍑洪櫌鐥呭尯
+          { width: 15 }, // 绉戝
+          { width: 12 }, // 鍑洪櫌浜烘
+          { width: 12 }, // 鏃犻渶闅忚浜烘
+          { width: 12 }, // 搴旈殢璁夸汉娆�
+          { width: 12 }, // 闅忚鐜�
+          { width: 12 }, // 鍙婃椂鐜�
+          { width: 15 }, // 婊℃剰搴﹂鐩�婚噺
+          { width: 15 }, // 婊℃剰搴﹀~鎶ラ噺
+          { width: 12 }, // 瀹屾垚姣旂巼
+        ];
+
+        // 鐢熸垚骞朵笅杞芥枃浠�
+        const buffer = await workbook.xlsx.writeBuffer();
+        const blob = new Blob([buffer], {
+          type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
+        });
+
+        // 浣跨敤FileSaver.js淇濆瓨鏂囦欢[2,3](@ref)
+        saveAs(blob, excelName);
+
+        this.$message.success("瀵煎嚭鎴愬姛");
+      } catch (error) {
+        console.error("瀵煎嚭澶辫触:", error);
+        this.$message.error(`瀵煎嚭澶辫触: ${error.message}`);
+      }
     },
     // 鏄剧ず鍥捐〃寮圭獥
 
@@ -1429,6 +1579,76 @@
     height: 400px;
   }
 }
+.topicdia {
+  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
+    "Helvetica Neue", Arial, sans-serif;
+  color: #333; /* 涓绘枃瀛楄壊 */
+}
+
+/* 澶撮儴鏍囬鏍峰紡 */
+.top-text {
+  font-size: 18px;
+  font-weight: 600;
+  padding-bottom: 16px;
+  margin-bottom: 20px;
+  border-bottom: 1px solid #e8e8e8; /* 绾ょ粏鐨勫垎闅旂嚎 */
+  color: #1f2d3d; /* 娣辫壊鏍囬 */
+}
+.top-text span {
+  font-size: 14px;
+  font-weight: normal;
+  color: #666; /* 鍓爣棰橀鑹茬◢娴� */
+  margin-left: 10px;
+}
+
+/* 棰樼洰瀹瑰櫒鏍峰紡 */
+.ttaabbcc {
+  background: #fafafa; /* 闈炲父娴呯殑鐏拌壊鑳屾櫙 */
+  border-radius: 6px;
+  padding: 16px;
+  margin-bottom: 20px;
+  border-left: 4px solid #4794c5; /* 宸︿晶瑁呴グ鑹叉潯锛屽鍔犲眰娆℃劅 */
+}
+
+/* 棰樼洰鎻忚堪鏍峰紡 */
+.describe {
+  font-size: 15px;
+  line-height: 1.6;
+  margin-bottom: 12px;
+  color: #1f2d3d;
+}
+.describe span {
+  font-size: 13px;
+  color: #999; /* 棰樺瀷鎻愮ず淇℃伅棰滆壊鏇存祬 */
+  font-style: italic;
+  margin-left: 8px;
+}
+
+/* 琛ㄦ牸鏁翠綋鏍峰紡璋冩暣 */
+.ttaabbcc .el-table {
+  border-radius: 4px;
+  overflow: hidden;
+  font-size: 14px;
+}
+
+/* 琛ㄥご鏍峰紡 */
+.ttaabbcc .el-table th {
+  background-color: #f1f5f9; /* 娴呰摑鑹茶〃澶磋儗鏅� */
+  color: #333;
+  font-weight: 600;
+}
+
+/* 鍗曞厓鏍兼牱寮� */
+.ttaabbcc .el-table td {
+  border-bottom: 1px solid #f0f0f0; /* 绾ょ粏鐨勮鍒嗛殧绾� */
+  padding: 12px 0;
+}
+
+/* 姣斾緥鏁版嵁鏍峰紡 */
+.button-zx {
+  color: #4794c5; /* 浣跨敤涓庝富棰樺懠搴旂殑钃濊壊 */
+  font-weight: 500;
+}
 ::v-deep.el-tabs--left,
 .el-tabs--right {
   overflow: hidden;
diff --git a/src/views/system/user/index.vue b/src/views/system/user/index.vue
index 71bb1b1..7b132b3 100644
--- a/src/views/system/user/index.vue
+++ b/src/views/system/user/index.vue
@@ -907,7 +907,7 @@
             updateUser(this.form).then((response) => {
               this.$modal.msgSuccess("淇敼鎴愬姛");
               this.open = false;
-              this.adduserdept();
+              // this.adduserdept();
             });
           } else {
             addUser(this.form).then((response) => {
@@ -916,7 +916,7 @@
               this.form.userId = response.data;
               console.log("寮�濮嬪姞閮ㄩ棬");
 
-              this.adduserdept();
+              // this.adduserdept();
             });
           }
         }
diff --git a/vue.config.js b/vue.config.js
index aaaa772..7ce923e 100644
--- a/vue.config.js
+++ b/vue.config.js
@@ -36,12 +36,12 @@
       // detail: https://cli.vuejs.org/config/#devserver-proxy
       [process.env.VUE_APP_BASE_API]: {
         // target: `https://www.health-y.cn/lssf`,
-        // target: `http://192.168.100.127:8095`,
+        // target: `http://192.168.100.10:8096`,
         // target: `http://192.168.100.10:8094`,//鐪佺珛鍚屽痉
-        target: `http://192.168.100.10:8095`,//鏂板崕
-        // target:`http://localhost:8095`,
+        // target: `http://192.168.100.10:8095`,//鏂板崕
+        target:`http://localhost:8095`,
         // target:`http://35z1t16164.qicp.vip`,
-        // target: `http://192.168.100.193:8095`,
+        // target: `http://192.168.100.172:8095`,
         // target: `http://192.168.101.166:8093`,
         // target: `http://192.168.191.181:8095`,
         changeOrigin: true,

--
Gitblit v1.9.3