From 52fcab294f28efd0fb6fcacdd3bfd039fbc1d1a9 Mon Sep 17 00:00:00 2001
From: WXL (wul) <wl_5969728@163.com>
Date: 星期三, 01 七月 2026 11:38:47 +0800
Subject: [PATCH] 测试完成

---
 src/components/Assistant/index.vue |  546 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 539 insertions(+), 7 deletions(-)

diff --git a/src/components/Assistant/index.vue b/src/components/Assistant/index.vue
index 2ee2946..18d0aa5 100644
--- a/src/components/Assistant/index.vue
+++ b/src/components/Assistant/index.vue
@@ -152,17 +152,246 @@
                   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>
+              <!-- 鉁� 鏂板鐭俊鍥炬爣 -->
+              <svg
+                v-else-if="action.icon === 'IconMessageSquare'"
+                viewBox="0 0 24 24"
+                fill="none"
+                stroke="currentColor"
+                stroke-width="2"
+              >
+                <rect x="3" y="3" width="18" height="18" rx="2" ry="2" />
+                <line x1="8" y1="9" x2="16" y2="9" />
+                <line x1="8" y1="13" x2="14" y2="13" />
+                <line x1="8" y1="17" x2="12" y2="17" />
+              </svg>
             </div>
             <div class="action-label">{{ action.label }}</div>
           </div>
         </div>
       </div>
     </transition>
+    <!-- 鐭俊鍙戦�佸璇濇 -->
+    <el-dialog
+      title="鐭俊鍙戦��"
+      :visible.sync="smsDialogVisible"
+      width="800px"
+      :close-on-click-modal="false"
+      append-to-body
+    >
+      <el-form ref="smsForm" :model="smsForm" label-width="100px">
+        <el-form-item label="鎮h�呭悕绉�">
+          <el-input v-model="smsForm.sendname"></el-input>
+        </el-form-item>
+        <el-form-item label="骞撮緞">
+          <el-input v-model="smsForm.age"></el-input>
+        </el-form-item>
+        <el-form-item label="鐢佃瘽">
+          <el-input v-model="smsForm.telcode"></el-input>
+        </el-form-item>
+        <el-form-item label="绉戝">
+          <el-input v-model="smsForm.deptname"></el-input>
+        </el-form-item>
+        <el-form-item label="鐥呭尯">
+          <el-input v-model="smsForm.leavehospitaldistrictname"></el-input>
+        </el-form-item>
+        <el-form-item label="閫夋嫨妯℃澘">
+          <el-row :gutter="10">
+            <el-col :span="7">
+              <el-select
+                v-model="templateFilterDept"
+                placeholder="鎸夌瀹�"
+                filterable
+                clearable
+                style="width: 100%"
+                @change="filterTemplates"
+              >
+                <el-option
+                  v-for="dept in departmentOptions"
+                  :key="dept.value"
+                  :label="dept.label"
+                  :value="dept.value"
+                />
+              </el-select>
+            </el-col>
+            <el-col :span="7">
+              <el-select
+                v-model="templateFilterWard"
+                placeholder="鎸夌梾鍖�"
+                filterable
+                clearable
+                style="width: 100%"
+                @change="filterTemplates"
+              >
+                <el-option
+                  v-for="ward in wardOptions"
+                  :key="ward.value"
+                  :label="ward.label"
+                  :value="ward.value"
+                />
+              </el-select>
+            </el-col>
+            <el-col :span="10">
+              <el-select
+                v-model="selectedTemplateId"
+                placeholder="璇烽�夋嫨鐭俊妯℃澘"
+                filterable
+                clearable
+                style="width: 100%"
+                @change="handleTemplateSelect"
+              >
+                <el-option
+                  v-for="tmpl in filteredTemplateOptions"
+                  :key="tmpl.templetid"
+                  :label="tmpl.templetname"
+                  :value="tmpl.templetid"
+                >
+                  <div class="template-option-content">
+                    <div class="template-option-text">
+                      {{ tmpl.templetcontent || "鏆傛棤鍐呭" }}
+                    </div>
+                    <div class="template-option-meta">
+                      <span>{{ tmpl.deptName || "閫氱敤" }}</span>
+                      <span class="meta-separator">/</span>
+                      <span>{{ tmpl.wardName || "鍏ㄩ儴" }}</span>
+                    </div>
+                  </div>
+                </el-option>
+              </el-select>
+            </el-col>
+            <el-col :span="6">
+              <el-button
+                type="primary"
+                plain
+                icon="el-icon-plus"
+                @click="openQuickCreateTemplate"
+              >
+                鏂板缓
+              </el-button>
+            </el-col>
+          </el-row>
+        </el-form-item>
+
+        <el-form-item label="鐭俊鍐呭">
+          <el-input
+            type="textarea"
+            :rows="4"
+            v-model="smsContent"
+            placeholder="璇疯緭鍏ョ煭淇″唴瀹�..."
+            maxlength="500"
+            show-word-limit
+          ></el-input>
+        </el-form-item>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button @click="smsDialogVisible = false">鍙� 娑�</el-button>
+        <el-button type="primary" @click="sendSms" :loading="smsLoading">
+          纭鍙戦��
+        </el-button>
+      </div>
+      <!-- 鍐呭祵锛氬揩閫熸柊寤烘ā鏉垮璇濇 -->
+      <!-- 蹇�熸柊寤烘ā鏉垮璇濇锛堝寮虹増锛� -->
+      <el-dialog
+        title="鏂板缓鐭俊妯℃澘"
+        :visible.sync="quickCreateVisible"
+        width="500px"
+        append-to-body
+        :close-on-click-modal="false"
+      >
+        <el-form
+          :model="quickTemplateForm"
+          :rules="quickTemplateRules"
+          ref="quickTemplateForm"
+          label-width="90px"
+        >
+          <el-form-item label="妯℃澘缂栧彿" prop="templetno">
+            <el-input
+              v-model="quickTemplateForm.templetno"
+              placeholder="璇疯緭鍏ユā鏉跨紪鍙�"
+            />
+          </el-form-item>
+          <el-form-item label="妯℃澘鍚嶇О" prop="templetname">
+            <el-input
+              v-model="quickTemplateForm.templetname"
+              placeholder="璇疯緭鍏ユā鏉垮悕绉�"
+            />
+          </el-form-item>
+          <el-form-item label="鎵�灞炵瀹�">
+            <el-select
+              v-model="quickTemplateForm.deptCode"
+              placeholder="璇烽�夋嫨绉戝"
+              filterable
+              clearable
+              style="width: 100%"
+              @change="
+                (val) => {
+                  const dept = departmentOptions.find((d) => d.value === val);
+                  quickTemplateForm.deptName = dept ? dept.label : '';
+                }
+              "
+            >
+              <el-option
+                v-for="dept in departmentOptions"
+                :key="dept.value"
+                :label="dept.label"
+                :value="dept.value"
+              />
+            </el-select>
+          </el-form-item>
+          <el-form-item label="鎵�灞炵梾鍖�">
+            <el-select
+              v-model="quickTemplateForm.wardCode"
+              placeholder="璇烽�夋嫨鐥呭尯"
+              filterable
+              clearable
+              style="width: 100%"
+            >
+              <el-option
+                v-for="ward in wardOptions"
+                :key="ward.value"
+                :label="ward.label"
+                :value="ward.value"
+              />
+            </el-select>
+          </el-form-item>
+          <el-form-item label="妯℃澘鍐呭" prop="templetcontent">
+            <el-input
+              v-model="quickTemplateForm.templetcontent"
+              type="textarea"
+              :rows="4"
+              placeholder="璇疯緭鍏ョ煭淇℃ā鏉垮唴瀹�"
+              maxlength="500"
+              show-word-limit
+            />
+          </el-form-item>
+        </el-form>
+        <div slot="footer">
+          <el-button @click="quickCreateVisible = false">鍙� 娑�</el-button>
+          <el-button
+            type="primary"
+            @click="submitQuickTemplate"
+            :loading="quickCreateLoading"
+          >
+            淇濆瓨骞朵娇鐢�
+          </el-button>
+        </div>
+      </el-dialog>
+    </el-dialog>
   </div>
 </template>
 
 <script>
-import { getCurrentUserServiceSubtaskCount } from "@/api/AiCentre/index";
+import {
+  getCurrentUserServiceSubtaskCount,
+  sendMsg,
+} from "@/api/AiCentre/index";
+import {
+  listSmstemplet,
+  getSmstemplet,
+  addSmstemplet,
+  updateSmstemplet,
+  delSmstemplet,
+} from "@/api/smartor/smstemplet";
 export default {
   name: "FloatBall",
 
@@ -210,6 +439,45 @@
       hideTimer: null,
       updateTime: "",
       roles: null,
+      templateOptions: [], // 妯℃澘涓嬫媺鍒楄〃
+      selectedTemplateId: "", // 閫変腑鐨勬ā鏉縄D
+      templateLoading: false, // 妯℃澘鍒楄〃鍔犺浇鐘舵��
+      // 妯℃澘绛涢��
+      templateFilterDept: "",
+      templateFilterWard: "", // 鏂板锛氱梾鍖虹瓫閫�
+      filteredTemplateOptions: [],
+
+      // 绉戝閫夐」锛堜粠 Vuex 鑾峰彇锛�
+      departmentOptions: [],
+      // 鏂板锛氱梾鍖洪�夐」锛堜粠 Vuex 鑾峰彇锛�
+      wardOptions: [],
+      // 蹇�熸柊寤烘ā鏉�
+      quickCreateVisible: false,
+      quickCreateLoading: false,
+      quickTemplateForm: {
+        templetno: "",
+        templetname: "",
+        templetcontent: "",
+      },
+      quickTemplateRules: {
+        templetname: [
+          { required: true, message: "璇疯緭鍏ユā鏉垮悕绉�", trigger: "blur" },
+        ],
+        templetcontent: [
+          { required: true, message: "璇疯緭鍏ユā鏉垮唴瀹�", trigger: "blur" },
+        ],
+      },
+      // 鐭俊鍙戦�佸璇濇
+      // smsDialogVisible: false,
+      smsLoading: false, // 鉁� 鏂板鍔犺浇鐘舵��
+      smsContent: "",
+      smsForm: {
+        sendname: "",
+        age: "",
+        telcode: "",
+        deptname: "",
+        leavehospitaldistrictname: "",
+      },
       // 缁熻鏁版嵁
       statsItems: [
         {
@@ -269,12 +537,12 @@
           icon: "IconPhone",
           url: "/followvisit/particty?type=1&serviceType=2",
         },
-        // {
-        //   id: 'chat',
-        //   label: '鍦ㄧ嚎鑱婂ぉ',
-        //   icon: 'IconMessageCircle',
-        //   url: '/chat'
-        // }
+        {
+          id: "sendSms", // 鉁� 鏂板鐭俊鍙戦��
+          label: "鐭俊鍙戦��",
+          icon: "IconMessageSquare",
+          action: "openSmsDialog", // 鏍囪涓哄脊妗嗘搷浣�
+        },
       ],
     };
   },
@@ -283,8 +551,41 @@
     totalUnread() {
       return this.statsItems.reduce((sum, item) => sum + item.unread, 0);
     },
+    // 鉁� Vuex 鍙屽悜缁戝畾
+    smsDialogVisible: {
+      get() {
+        return this.$store.state.sms.smsDialogVisible;
+      },
+      set(val) {
+        if (!val) {
+          this.$store.dispatch("sms/closeSmsDialog");
+        }
+      },
+    },
   },
+  watch: {
+    // 鉁� 鐩戝惉 Vuex 瀵硅瘽妗嗙姸鎬�
+    "$store.state.sms.smsDialogVisible": {
+      handler(val) {
+        if (val) {
+          const patientData = this.$store.state.sms.patientData;
+          this.smsForm = { ...patientData };
+          this.smsContent = this.$store.state.sms.smsTemplate || "";
 
+          // 灞曞紑鎮诞鐞�
+          if (!this.isExpanded) {
+            this.isExpanded = true;
+            this.isHidden = false;
+            clearTimeout(this.hideTimer);
+          }
+
+          // 鈽呪槄鈽� 鍏抽敭淇锛氬湪杩欓噷鍒濆鍖栨ā鏉跨浉鍏虫暟鎹� 鈽呪槄鈽�
+          this.initTemplateData();
+        }
+      },
+      immediate: false,
+    },
+  },
   mounted() {
     this.roles = this.$store.state.user.roles;
     this.loadPosition();
@@ -307,6 +608,33 @@
   },
 
   methods: {
+    initTemplateData() {
+      // 鍒濆鍖栫瀹ら�夐」
+      if (this.$store.getters.belongDepts) {
+        this.departmentOptions = this.$store.getters.belongDepts.map(
+          (dept) => ({
+            label: dept.deptName,
+            value: dept.deptCode,
+          })
+        );
+      }
+
+      // 鈽呪槄鈽� 鏂板锛氬垵濮嬪寲鐥呭尯閫夐」 鈽呪槄鈽�
+      if (this.$store.getters.belongWards) {
+        this.wardOptions = this.$store.getters.belongWards.map((ward) => ({
+          label: ward.districtName,
+          value: ward.districtCode,
+        }));
+      }
+
+      // 閲嶇疆绛涢��
+      this.templateFilterDept = "";
+      this.templateFilterWard = ""; // 鏂板
+      this.selectedTemplateId = "";
+
+      // 鍔犺浇妯℃澘鍒楄〃
+      this.loadTemplates();
+    },
     toggleExpand() {
       this.isExpanded = !this.isExpanded;
       if (this.isExpanded) {
@@ -315,7 +643,85 @@
         this.updateStats();
       }
     },
+    async loadTemplates() {
+      this.templateLoading = true;
+      try {
+        // const { listSmstemplet } = await import("@/api/smartor/smstemplet");
+        const res = await listSmstemplet({ pageNum: 1, pageSize: 999 });
+        this.templateOptions = res.rows || [];
+        this.filterTemplates(); // 搴旂敤绛涢��
+      } catch (error) {
+        console.error("鍔犺浇鐭俊妯℃澘澶辫触:", error);
+        this.templateOptions = [];
+        this.filteredTemplateOptions = [];
+      } finally {
+        this.templateLoading = false;
+      }
+    },
+    handleTemplateSelect(templateId) {
+      if (!templateId) {
+        this.smsContent = "";
+        return;
+      }
+      const selected = this.templateOptions.find(
+        (t) => t.templetid === templateId
+      );
+      if (selected) {
+        this.smsContent = selected.templetcontent || "";
+      }
+    },
+    openQuickCreateTemplate() {
+      this.quickTemplateForm = {
+        templetno: "",
+        templetname: "",
+        templetcontent: "",
+      };
+      this.quickCreateVisible = true;
+      this.$nextTick(() => {
+        if (this.$refs.quickTemplateForm) {
+          this.$refs.quickTemplateForm.clearValidate();
+        }
+      });
+    },
+    /**
+     * 鎻愪氦蹇�熸柊寤烘ā鏉�
+     */
+    async submitQuickTemplate() {
+      this.$refs.quickTemplateForm.validate(async (valid) => {
+        if (!valid) return;
 
+        this.quickCreateLoading = true;
+        try {
+          // const { addSmstemplet } = await import("@/api/smartor/smstemplet");
+          const res = await addSmstemplet(this.quickTemplateForm);
+
+          if (res.code === 200) {
+            this.$modal.msgSuccess("妯℃澘鍒涘缓鎴愬姛");
+
+            // 鍒锋柊妯℃澘鍒楄〃
+            await this.loadTemplates();
+
+            // 鑷姩閫変腑鍒氬垱寤虹殑妯℃澘
+            const newTmpl = this.templateOptions.find(
+              (t) => t.templetname === this.quickTemplateForm.templetname
+            );
+            if (newTmpl) {
+              this.selectedTemplateId = newTmpl.templetid;
+              this.smsContent = newTmpl.templetcontent;
+            }
+
+            this.quickCreateVisible = false;
+          } else {
+            this.$modal.msgError(res.msg || "鍒涘缓澶辫触");
+          }
+        } catch (error) {
+          console.error("鍒涘缓妯℃澘澶辫触:", error);
+          this.$modal.msgError("鍒涘缓澶辫触锛岃绋嶅悗閲嶈瘯");
+        } finally {
+          this.quickCreateLoading = false;
+        }
+      });
+    },
     handleMouseEnter() {
       this.isHovering = true;
       if (this.autoHide) {
@@ -424,6 +830,15 @@
     },
 
     handleActionClick(action) {
+      // 濡傛灉鏄煭淇″彂閫佹搷浣滐紝鎵撳紑瀵硅瘽妗�
+      console.log(action);
+
+      if (action.action === "openSmsDialog") {
+        this.openSmsDialog();
+        return;
+      }
+
+      // 鍘熸湁閫昏緫淇濇寔涓嶅彉
       console.log(this.roles, "this.roles");
       if (
         action.url &&
@@ -435,7 +850,90 @@
         this.$modal.msgError("闈炵鐞嗗憳鐢ㄦ埛鏆傛棤鍒涘缓浠诲姟鏉冮檺");
       }
     },
+    // 鎵撳紑鐭俊鍙戦�佸璇濇
+    /**
+     * 鏀归�犲師鏈夌殑 openSmsDialog 鏂规硶
+     */
+    openSmsDialog(patientData = {}) {
+      // 閲嶇疆绛涢��
+      this.templateFilterDept = "";
 
+      // 閲嶇疆閫夋嫨
+      this.selectedTemplateId = "";
+      this.smsContent = patientData.smsTemplate || "";
+
+      // 鍔犺浇妯℃澘鍒楄〃
+      this.loadTemplates();
+
+      // 鎵撳紑瀵硅瘽妗嗭紙閫氳繃 Vuex锛�
+      this.$store.dispatch("sms/openSmsDialog", {
+        name: patientData.name || "",
+        age: patientData.age || "",
+        phone: patientData.phone || "",
+        deptName: patientData.deptName || "",
+        wardName: patientData.wardName || "",
+        smsTemplate: patientData.smsTemplate || "",
+      });
+    },
+    // 鏂板锛氱瓫閫夋ā鏉�
+    filterTemplates() {
+      let filtered = [...this.templateOptions];
+
+      // 鎸夌瀹ょ瓫閫�
+      if (this.templateFilterDept) {
+        filtered = filtered.filter(
+          (tmpl) => tmpl.deptCode === this.templateFilterDept || !tmpl.deptCode
+        );
+      }
+
+      // 鈽呪槄鈽� 鏂板锛氭寜鐥呭尯绛涢�� 鈽呪槄鈽�
+      if (this.templateFilterWard) {
+        filtered = filtered.filter(
+          (tmpl) => tmpl.wardCode === this.templateFilterWard || !tmpl.wardCode
+        );
+      }
+
+      this.filteredTemplateOptions = filtered;
+
+      // 娓呯┖宸查��
+      this.selectedTemplateId = "";
+      this.smsContent = "";
+    },
+    // 鍙戦�佺煭淇�
+    async sendSms() {
+      if (!this.smsContent.trim()) {
+        this.$modal.msgError("璇疯緭鍏ョ煭淇″唴瀹�");
+        return;
+      }
+
+      if (!this.smsForm.telcode) {
+        this.$modal.msgError("鎮h�呯數璇濅笉鑳戒负绌�");
+        return;
+      }
+
+      this.smsLoading = true;
+      try {
+        const res = await sendMsg({
+          phone: this.smsForm.telcode,
+          content: this.smsContent,
+        });
+
+        if (res.code === 200) {
+          this.$modal.msgSuccess("鐭俊鍙戦�佹垚鍔�");
+          // 鉁� 閫氳繃 Vuex 鍏抽棴瀵硅瘽妗�
+          this.$store.dispatch("sms/closeSmsDialog");
+          this.smsContent = "";
+        } else {
+          this.$modal.msgError(res.msg || "鍙戦�佸け璐�");
+        }
+      } catch (error) {
+        console.error("鍙戦�佺煭淇″け璐�:", error);
+        this.$modal.msgError("鍙戦�佸け璐ワ紝璇风◢鍚庨噸璇�");
+      } finally {
+        this.smsLoading = false;
+        this.selectedTemplateId = "";
+      }
+    },
     async updateStats() {
       try {
         // 杩欓噷鍙互鏇挎崲涓哄疄闄呯殑 API 璋冪敤
@@ -525,6 +1023,40 @@
 </script>
 
 <style scoped>
+.wide-template-popper {
+  width: 420px !important; /* 杩涗竴姝ュ姞瀹斤紝閫傚簲鍐呭灞曠ず */
+}
+
+.template-option-content {
+  padding: 8px 0;
+  display: flex;
+  flex-direction: column;
+  gap: 6px;
+}
+
+.template-option-text {
+  font-size: 13px;
+  color: #303133;
+  line-height: 1.6;
+  display: -webkit-box;
+  -webkit-line-clamp: 3; /* 鏈�澶氭樉绀�3琛� */
+  -webkit-box-orient: vertical;
+  overflow: hidden;
+  text-overflow: ellipsis;
+  word-break: break-all;
+}
+
+.template-option-meta {
+  font-size: 12px;
+  color: #909399;
+  display: flex;
+  align-items: center;
+  gap: 4px;
+}
+
+.meta-separator {
+  color: #dcdfe6;
+}
 .float-ball {
   position: fixed;
   z-index: 9999;

--
Gitblit v1.9.3