WXL (wul)
昨天 52fcab294f28efd0fb6fcacdd3bfd039fbc1d1a9
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="患者名称">
          <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: "", // 选中的模板ID
      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("患者电话不能为空");
        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;