Newer
Older
safe_production_front / src / views / smGateway.vue
dutingting on 17 Jan 13 KB gm大屏第一版
<route lang="yaml">
meta:
  title: 网关集成
  constant: true
  layout: false
</route>

<script lang="ts" setup name="SmGateway">
import type { FormInstance, FormRules } from 'element-plus'
import { ElMessage, ElMessageBox } from 'element-plus'
import useUserStore from '@/store/modules/user'
import { RSAdecrypt, RSAencrypt } from '@/utils/security'
import { getPrivateKey, removePrivateKey } from '@/utils/auth'
import JIT_GW_ExtInterface from '/public/smGateway/pnxclient.js'
import JIT_AUTHEN from '/public/smGateway/authen.js'
import { debounce } from 'lodash-es'
// import { fetchGwUrl } from '@/api/smGateway/smGateway'
const route = useRoute()
const router = useRouter()
const userStore = useUserStore()
const showKaptcha = ref(false)
const publicKey = ref('') // 公钥
const sid = ref('') // sid
const haveExe = ref(true) // 是否有安装插件
const preventReclick = ref(0) // 网关认证允许几秒点击一次
const passwordType = ref('password') // 密码类型:password 密码
const form = ref({
  username: '',
  password: '',
})

const btnColor = ref('#2af598')

const resultForm = ref({ // 认证结果
  certAttributeNodeMap: '', // 证书信息
  umsAttributeNodeMap: '', // UMS信息
  pmsAttributeNodeMap: '', // PMS信息
  customAttributeNodeMap: '', // 自定义信息
  result: '', // 认证结果
  errCode: '', // 错误码
  errDesc: '', // 错误描述
})

// 校验规则
const rules: FormRules = reactive({
  username: [{ required: true, message: '用户名必填', trigger: ['blur', 'change'] }],
  password: [{ required: true, message: '密码必填', trigger: ['blur', 'change'] }],
})// 前端校验规则
// 获取系统基础配置: 公钥,是否开启验证码
function getBaseConfig() {
  userStore.getBaseConfig().then((res) => {
    showKaptcha.value = res.kaptcha
    publicKey.value = res.publicKey
    sid.value = res.sid
    ElMessage({
      message: '连接服务器成功',
      type: 'success',
    })
  })
}

// 获取控件版本-如果未安装插件,则提示安装。
const fetchVersion = () => {
  try {
    console.log('JIT_GW_ExtInterface', JIT_GW_ExtInterface)
    const res = JIT_GW_ExtInterface.GetVersion()
    console.log('new: 获取网关插件版本', res)
    haveExe.value = true
  }
  catch (e) {
    haveExe.value = false
    console.log('new: 获取网关版本插件失败, 没有插件')
    ElMessageBox.confirm(
      '未安装PNXClient插件,请先下载安装插件?',
      '警告',
      {
        confirmButtonText: '下载并安装',
        cancelButtonText: '取消',
        type: 'warning',
      },
    )
      .then(() => {
        installExe()
      })
      .catch(() => {
      })
  }
}

// 点击安装插件
function installExe() {
  fetch('./smGateway/PNXClient.exe').then((res: any) => {
    res.blob().then((blob: any) => {
      const blobUrl = window.URL.createObjectURL(blob)
      const filename = 'PNXClient.exe'
      const a = document.createElement('a')
      a.href = blobUrl
      a.download = filename
      a.click()
      window.URL.revokeObjectURL(blobUrl)
    })
  })
}

// 重新认证
const reAuthentication = () => {
  resultForm.value = { // 认证结果
    certAttributeNodeMap: '', // 证书信息
    umsAttributeNodeMap: '', // UMS信息
    pmsAttributeNodeMap: '', // PMS信息
    customAttributeNodeMap: '', // 自定义信息
    result: '', // 认证结果
    errCode: '', // 错误码
    errDesc: '', // 错误描述
  }
}
// async function authentication() {
//   const token = '20d8008f-44ee-46dc-ac67-f5eba0dcb493'
//   localStorage.setItem('token', token)
//   await userStore.setToken(token)
//   router.push({ path: '/dashboard' })
// }

// 认证
async function authentication() {
  if (resultForm.value.result === '失败') {
    reAuthentication()
    return false
  }
  // 1发起随机数请求
  const random = JIT_AUTHEN.random()
  if (random != '') {
    // 2对随机数做p7签名
    const P7SignResutl = JIT_AUTHEN.AuthP7Sign(random)
    if (P7SignResutl != '') {
      // 3请求网关认证
      const authResult = JIT_AUTHEN.P7certAuth(random, P7SignResutl)
      // const contextForm = JSON.stringify(authResult)
      // localStorage.setItem('contextForm', contextForm)
      if (authResult.isSuccess != null && authResult.isSuccess == 'true') {
        resultForm.value.result = '成功'
        resultForm.value.certAttributeNodeMap = authResult.certAttributeNodeMap
        resultForm.value.umsAttributeNodeMap = authResult.umsAttributeNodeMap
        resultForm.value.pmsAttributeNodeMap = authResult.pmsAttributeNodeMap
        resultForm.value.customAttributeNodeMap = authResult.customAttributeNodeMap

        // ======================认证成功跳转首页=======================
        const token = authResult.casicToken
        if (authResult.casicToken) {
          localStorage.setItem('token', token)
          await userStore.setToken(token)
          router.push({ path: '/dashboard' })
        }
        else {
          ElMessage.warning('该用户未授权,请联系管理员')
        }
      }
      else if (authResult.isSuccess != null && authResult.isSuccess == 'false') {
        resultForm.value.result = '失败'
        resultForm.value.errCode = authResult.errCode
        resultForm.value.errDesc = authResult.errDesc
        ElMessage.warning(`网关认证失败:${authResult.errDesc}`)
        resultForm.value.result = '失败'
        btnColor.value = '#fcbb02'
      }
    }
    else {
      console.log('验证接口返回空字符串, 验证失败')
    }
  }
  else {
    resultForm.value.result = '失败'
    resultForm.value.errDesc = '随机数获取失败!'
  }
}

onBeforeMount(async () => {
  getBaseConfig()
  fetchVersion()
})

onMounted(() => {
  preventReclick.value = Number(localStorage.getItem('preventReclick')) || 2000
})
</script>

<template>
  <div class="bg-banner" />
  <div style="display: flex;justify-content: center;align-items: center;height: 100%;margin-top: -120px;">
    <div class="main">
      <div class="main-title">
        <span style="color: #fff;">安全生产智慧监管系统</span>
        <!-- <span class="load-span">安</span>
        <span class="load-span">全</span>
        <span class="load-span">生</span>
        <span class="load-span">产</span>
        <span class="load-span">智</span>
        <span class="load-span">慧</span>
        <span class="load-span">监</span>
        <span class="load-span">管</span>
        <span class="load-span">系</span>
        <span class="load-span">统</span> -->
      </div>
      <div class="exe">
        <!-- <el-result v-if="!haveExe" icon="warning" title="警告提示" sub-title="未安装PNXClient插件,请先下载安装插件">
          <template #extra>
            <el-button type="primary" size="large" @click="installExe">
              下载插件
            </el-button>
          </template>
        </el-result> -->

        <!-- <el-result v-if="resultForm.result === '失败'" icon="error" title="认证失败" :sub-title="resultForm.errDesc">
          <template #extra>
            <el-button type="primary" size="large" @click="reAuthentication">重新认证</el-button>
          </template>
        </el-result> -->

        <!-- <el-result v-if="resultForm.result === '成功'" icon="success" title="认证成功">
        </el-result> -->

        <!-- <div v-if="resultForm.result === ''" class="form">
          <el-form
            ref="dataFormRef"
            label-position="left"
            label-width="80px"
            :model="form"
            :rules="rules"
          >
            <el-row :gutter="24">
              <el-col :span="24">
                <el-form-item label="用户名" prop="oldpassword">
                  <el-input v-model.trim="form.username" disabled placeholder="请输入用户名" />
                </el-form-item>
              </el-col>
              <el-col :span="24">
                <el-form-item label="密码" prop="oldpassword">
                  <el-input v-model="form.password" disabled placeholder="请输入密码" show-password />
                </el-form-item>
              </el-col>
              <el-col :span="24" style="display: flex;justify-content: center;">
                <el-button plain style="margin-top: 32px;" type="primary" size="large" @click="authentication">认证</el-button>
              </el-col>
            </el-row>
          </el-form>
        </div> -->

        <div class="button-container">
          <button v-prevent-reclick="preventReclick" class="glow-button" :style="{ '--btn-color': btnColor }" @click="authentication">
            <span>{{ resultForm.result === '失败' ? '重新认证' : '网关认证' }}</span>
            <div class="border-lines">
              <span class="line top" />
              <span class="line right" />
              <span class="line bottom" />
              <span class="line left" />
            </div>
          </button>
        </div>
      </div>
    </div>
  </div>
</template>

<style lang="scss" scoped>
.bg-banner {
  position: fixed;
  z-index: -1;
  top: 0;
  width: 100%;
  height: 100%;
  // background: radial-gradient(circle at center, const(--el-fill-color-lighter), const(--el-bg-color-page));
  background: url("../assets/images/login-image/bg.png") no-repeat center / cover;
}

.main {
  // position: fixed;
  // width: 500px;
  // top: 20%;
  // left: 37%;
  z-index: 0;

  .main-title {
    // text-align: center;
    // font-size: 30px;
    // color: #fff;
    // font-weight: 700;
    // letter-spacing: 2px;
    height: 48px;
    font-size: 52px;
    font-weight: 800;
    letter-spacing: 24px;
    color: black;
    display: flex;
    justify-content: center;
    align-items: center;
  }

  .main-title .load-span {
    animation: text-load17 2.8s linear infinite;
  }

  .main-title .load-span:nth-of-type(1) {
    color: #3185fa;
    animation-delay: 0.4s;
  }

  .main-title .load-span:nth-of-type(2) {
    color: #38e740;
    animation-delay: 0.8s;
  }

  .main-title .load-span:nth-of-type(3) {
    color: #fcbb02;
    animation-delay: 0.12s;
  }

  .main-title .load-span:nth-of-type(4) {
    color: #3285ff;
    animation-delay: 1.6s;
  }

  .main-title .load-span:nth-of-type(5) {
    color: #2ab148;
    animation-delay: 2s;
  }

  .main-title .load-span:nth-of-type(6) {
    color: #7737d7;
    animation-delay: 4s;
  }

  .main-title .load-span:nth-of-type(7) {
    color: #c41dc1;
    animation-delay: 3.6s;
  }

  .main-title .load-span:nth-of-type(8) {
    color: #20fbae;
    animation-delay: 1.4s;
  }

  .main-title .load-span:nth-of-type(9) {
    color: #ebe008;
    animation-delay: 1.8s;
  }

  .main-title .load-span:nth-of-type(10) {
    color: #f03985;
    animation-delay: 0.8s;
  }

  @keyframes text-load17 {
    0% {
      transform: translateY(0);
    }

    50% {
      transform: translateY(-20px);
    }

    100% {
      transform: translateY(0);
    }
  }

  .exe {
    margin-top: 80px;
  }

  .form {
    width: 500px;
    background: url("../assets//images/login_images/theme2/bg-blue.png") no-repeat center / cover;
    padding: 50px 30px 20px;
    border-radius: 8px;
    margin-top: 20px;
  }

  // =========================按钮===================================
  .button-container {
    position: relative;
    display: flex;
    justify-content: center;
    align-items: center;
    margin-top: 160px;
  }

  .glow-button {
    position: relative;
    width: 240px;
    height: 72px;
    border: none;
    border-radius: 4px;
    background: transparent;
    color: var(--btn-color);
    font-size: 32px;
    font-weight: 700;
    text-align: center;
    line-height: 72px;
    cursor: pointer;
    overflow: hidden;
    box-shadow: 0 0 1px var(--btn-color);
    transition: box-shadow 0.3s, background-color 0.3s, color 0.3s;
    margin-top: 80px;
  }

  // .glow-button:hover {
  //   background-color: var(--btn-color);
  //   color: #fff;
  //   box-shadow: 0 0 5px var(--btn-color), 0 0 25px var(--btn-color), 0 0 50px var(--btn-color), 0 0 100px var(--btn-color);
  // }

  // .glow-button:active {
  //   background-color: var(--btn-color);
  //   color: #fff;
  //   box-shadow: 0 0 15px var(--btn-color), 0 0 30px var(--btn-color), 0 0 60px var(--btn-color), 0 0 120px var(--btn-color);
  //   transform: scale(0.95);
  // }

  .border-lines {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    pointer-events: none;
  }

  .line {
    position: absolute;
    display: block;
    background: linear-gradient(90deg, transparent, var(--btn-color));
  }

  .top {
    top: 0;
    left: -100%;
    width: 100%;
    height: 2px;
    animation: topAnim 4s linear infinite;
  }

  @keyframes topAnim {
    0% {
      left: -100%;
    }

    50%,
    100% {
      left: 100%;
    }
  }

  .right {
    top: -100%;
    right: 0;
    width: 2px;
    height: 100%;
    animation: rightAnim 4s linear infinite 1s;
    background: linear-gradient(180deg, transparent, var(--btn-color));
  }

  @keyframes rightAnim {
    0% {
      top: -100%;
    }

    50%,
    100% {
      top: 100%;
    }
  }

  .bottom {
    bottom: 0;
    right: -100%;
    width: 100%;
    height: 2px;
    animation: bottomAnim 4s linear infinite 2s;
    background: linear-gradient(270deg, transparent, var(--btn-color));
  }

  @keyframes bottomAnim {
    0% {
      right: -100%;
    }

    50%,
    100% {
      right: 100%;
    }
  }

  .left {
    bottom: -100%;
    left: 0;
    width: 2px;
    height: 100%;
    animation: leftAnim 4s linear infinite 3s;
    background: linear-gradient(360deg, transparent, var(--btn-color));
  }

  @keyframes leftAnim {
    0% {
      bottom: -100%;
    }

    50%,
    100% {
      bottom: 100%;
    }
  }
  // ===========================================================
}
</style>