单应用项目,可以创建很多独立工具类页面 ,不用登录 初始化的页面
zhangchen
2025-07-25 64aaf44b6b2948631ebd0d9840d51e5e31ae5479
src/views/mobile/bedsideAuxiliaryScreen/components/SettingDeviceDialog.vue
New file
@@ -0,0 +1,330 @@
<template>
  <div class="setting-device-dialog-container">
    <el-dialog
      v-model="isShow"
      center
      title="设置编号"
      width="80%"
      :show-close="false"
      class="scheduled-task-dialog"
    >
      <template #header>
        <div class="setting-dialog-header">
          <span class="header-title">设置编号</span>
          <img
            :src="closeImg"
            class="header-close"
            @click="handleCancel"
            alt=""
          />
        </div>
      </template>
      <div class="setting-device-dialog-content">
        <div class="content-row1">
          <div class="row1-label">设备编号</div>
          <div class="row1-inp-box">
            <input
              v-model="devcieCode"
              type="text"
              class="row1-inp"
              placeholder="请输入设备编号或扫码二维码"
            />
          </div>
        </div>
        <div class="content-row2">
          <el-upload
            v-loading="isUploading"
            class="upload-demo"
            drag
            :show-file-list="false"
            accept="image/*"
            :limit="1"
            :before-upload="onBeforeUpload"
          >
            <div class="el-upload__text">
              <img :src="uploadImg" class="upload-img" alt="" />
              <p class="upload-text">点击虚线区域选择文件并识别二维码</p>
              <div class="upload-btn">二维码上传</div>
            </div>
          </el-upload>
        </div>
      </div>
      <template #footer>
        <div class="my-button cancel" @click="handleCancel">取消</div>
        <div class="my-button confirm" @click="handleConfirm">确认</div>
        <div class="my-button refresh" @click="handleRefresh">刷新</div>
      </template>
    </el-dialog>
  </div>
</template>
<script lang="ts" setup>
import { ElMessage, UploadRawFile } from "element-plus";
import { ref } from "vue";
import {
  BrowserMultiFormatReader,
  NotFoundException,
  ChecksumException,
  FormatException,
} from "@zxing/library";
import closeImg from "@/img/close.png";
import uploadImg from "@/img/upload.png";
import { useBedsideAuxiliaryScreenStore } from "@/store/bedsideAuxiliaryScreen";
const bedsideAuxiliaryScreenStore = useBedsideAuxiliaryScreenStore();
const isShow = ref(false);
const isUploading = ref(false);
const devcieCode = ref("");
const openDialog = () => {
  devcieCode.value = bedsideAuxiliaryScreenStore.deviceCode + "";
  isShow.value = true;
};
const onBeforeUpload = async (uploadFile: UploadRawFile) => {
  const file = uploadFile;
  if (!file) return;
  isUploading.value = true;
  try {
    const result = await decodeQRCodeFromFile(file);
    devcieCode.value = result;
    ElMessage.success("识别成功");
  } catch (err) {
    if (err instanceof NotFoundException) {
      ElMessage.error("未找到二维码");
    } else if (err instanceof ChecksumException) {
      ElMessage.error("校验错误");
    } else if (err instanceof FormatException) {
      ElMessage.error("格式错误");
    } else {
      ElMessage.error("识别错误请重新识别");
      console.error(err);
    }
  } finally {
    isUploading.value = false;
  }
  return false;
};
const decodeQRCodeFromFile = async (file: File): Promise<string> => {
  return new Promise((resolve, reject) => {
    const reader = new FileReader();
    reader.onload = async (e: any) => {
      const imageBase64 = e.target.result;
      const codeReader = new BrowserMultiFormatReader();
      try {
        const result = await codeReader.decodeFromImage(undefined, imageBase64);
        resolve(result.getText());
      } catch (err) {
        reject(err);
      }
    };
    reader.onerror = () => reject(new Error("读取文件失败"));
    reader.readAsDataURL(file);
  });
};
const handleCancel = () => {
  isShow.value = false;
};
const handleConfirm = () => {
  bedsideAuxiliaryScreenStore.setDeviceCode(devcieCode.value + "");
  handleRefresh();
  handleCancel();
};
const handleRefresh = () => {
    bedsideAuxiliaryScreenStore.refresh(
    `${import.meta.env.VITE_SSE_BASE_URL}${devcieCode.value}`
  );
};
defineExpose({
  openDialog,
});
</script>
<style lang="less" scoped>
.setting-device-dialog-container {
  ::v-deep(.el-dialog) {
    padding: 0;
    border-radius: 6px;
    overflow: hidden;
  }
  ::v-deep(.el-dialog__footer) {
    padding: 4px;
  }
  ::v-deep(.el-upload-dragger) {
    height: 65px;
    padding: 0 !important;
    display: flex;
    align-items: center;
    justify-content: center;
  }
  ::v-deep(.el-upload-dragger .el-icon--upload) {
    display: none;
  }
  ::v-deep(.el-dialog__header) {
    padding-bottom: 6px;
  }
  .setting-dialog-header {
    position: relative;
    height: 16px;
    background: #769aff;
    .header-title {
      position: absolute;
      left: 50%;
      top: 50%;
      transform: translateX(-50%) translateY(-50%);
      font-family: AlibabaPuHuiTi, AlibabaPuHuiTi;
      font-weight: 500;
      font-size: 8px;
      color: #ffffff;
      line-height: 11px;
      text-align: center;
    }
    .header-close {
      position: absolute;
      top: 50%;
      transform: translateY(-50%);
      right: 6px;
      width: 15px;
      height: 15px;
      transition: transform 0.2s;
      &:active {
        opacity: 0.6;
        transform: translateY(-50%) scale(0.95);
      }
    }
  }
  .setting-device-dialog-content {
    padding: 0 12px 6px;
    margin-bottom: 4px;
    border-bottom: 1px solid #d8d8d8;
    .content-row1 {
      display: flex;
      align-items: center;
      margin-bottom: 6px;
      .row1-label {
        margin-right: 6px;
        padding: 0 4px;
        background: #769aff;
        border-radius: 2px;
        font-family: PingFangSC, PingFang SC;
        font-weight: 600;
        font-size: 8px;
        line-height: 16px;
        color: #ffffff;
        font-style: normal;
      }
      .row1-inp-box {
        flex: 1;
        height: 16px;
        border-radius: 2px;
        border: 1px solid #979797;
        overflow: hidden;
        .row1-inp {
          width: 100%;
          height: 100%;
          border: none;
          outline: none;
          padding: 0 4px;
          line-height: 16px;
          font-size: 9px;
          font-family: PingFangSC, PingFang SC;
          vertical-align: middle;
          box-sizing: border-box; // 避免padding撑高
          &::placeholder {
            font-family: inherit;
            font-size: inherit;
            line-height: inherit;
            color: #aaaaaa;
            opacity: 1;
          }
        }
      }
    }
    .el-upload__text {
      display: flex;
      align-items: center;
      flex-direction: column;
      justify-content: center;
      .upload-img {
        height: 8px;
      }
      .upload-text {
        font-family: PingFangSC, PingFang SC;
        font-weight: 500;
        font-size: 5px;
        color: #5a6470;
        letter-spacing: 0px;
        text-align: center;
        font-style: normal;
      }
      .upload-btn {
        padding: 0 2px;
        background-color: #409eff;
        border-radius: 1px;
        font-family: PingFangSC, PingFang SC;
        font-size: 4px;
        color: #fff;
        letter-spacing: 0px;
        line-height: 8px;
        text-align: center;
        font-style: normal;
      }
    }
  }
  .my-button {
    display: inline-block;
    border-radius: 2px;
    padding: 0px 10px;
    font-family: PingFangSC, PingFang SC;
    font-weight: 500;
    font-size: 7px;
    color: #ffffff;
    line-height: 16px;
    letter-spacing: 1px;
    text-align: center;
    font-style: normal;
    transition: transform 0.1s ease, opacity 0.1s ease;
    cursor: pointer;
    &:active {
      transform: scale(0.95);
      opacity: 0.8;
    }
    &:not(:first-child) {
      margin-left: 6px;
    }
    &.cancel {
      background: #bbc6dd;
    }
    &.confirm {
      background: #769aff;
    }
    &.refresh {
      background: #e6a23c;
    }
  }
}
</style>
<style>
.scheduled-task-dialog {
  margin: 0 auto;
  top: 50% !important;
  transform: translateY(-50%) !important;
}
</style>