鸿蒙智能电子锁前端项目
whychdw
2024-11-27 393eceedc6ed2382fe60901294f978b73f709fa4
内容提交
11个文件已修改
6个文件已添加
246 ■■■■ 已修改文件
package-lock.json 16 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
package.json 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/user.js 28 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/layout/index.vue 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/store/modules/settings.ts 7 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/store/modules/user.ts 30 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/styles/element-ui.scss 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/styles/element/blue.scss 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/styles/element/index.scss 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/styles/index.scss 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/utils/RSA.js 30 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/utils/changeTheme.js 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/utils/const/const_num.js 40 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/utils/const/const_theme.js 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/utils/formatPassword.js 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/device/lock/index.vue 27 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/login/index.vue 9 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
package-lock.json
@@ -1,11 +1,11 @@
{
  "name": "vue3-element-admin",
  "name": "hm-lock",
  "version": "1.0.0",
  "lockfileVersion": 3,
  "requires": true,
  "packages": {
    "": {
      "name": "vue3-element-admin",
      "name": "hm-lock",
      "version": "1.0.0",
      "dependencies": {
        "axios": "^1.7.2",
@@ -17,6 +17,8 @@
        "file-saver": "^2.0.5",
        "fuse.js": "^6.6.2",
        "js-cookie": "^3.0.5",
        "js-md5": "^0.8.3",
        "jsencrypt": "^3.3.2",
        "jszip": "^3.10.1",
        "nprogress": "^0.2.0",
        "path-browserify": "^1.0.1",
@@ -4717,6 +4719,11 @@
        "node": ">=14"
      }
    },
    "node_modules/js-md5": {
      "version": "0.8.3",
      "resolved": "https://r.cnpmjs.org/js-md5/-/js-md5-0.8.3.tgz",
      "integrity": "sha512-qR0HB5uP6wCuRMrWPTrkMaev7MJZwJuuw4fnwAzRgP4J4/F8RwtodOKpGp4XpqsLBFzzgqIO42efFAyz2Et6KQ=="
    },
    "node_modules/js-tokens": {
      "version": "9.0.0",
      "resolved": "https://registry.npmmirror.com/js-tokens/-/js-tokens-9.0.0.tgz",
@@ -4735,6 +4742,11 @@
        "js-yaml": "bin/js-yaml.js"
      }
    },
    "node_modules/jsencrypt": {
      "version": "3.3.2",
      "resolved": "https://r.cnpmjs.org/jsencrypt/-/jsencrypt-3.3.2.tgz",
      "integrity": "sha512-arQR1R1ESGdAxY7ZheWr12wCaF2yF47v5qpB76TtV64H1pyGudk9Hvw8Y9tb/FiTIaaTRUyaSnm5T/Y53Ghm/A=="
    },
    "node_modules/json-buffer": {
      "version": "3.0.1",
      "resolved": "https://registry.npmmirror.com/json-buffer/-/json-buffer-3.0.1.tgz",
package.json
@@ -21,6 +21,8 @@
    "file-saver": "^2.0.5",
    "fuse.js": "^6.6.2",
    "js-cookie": "^3.0.5",
    "js-md5": "^0.8.3",
    "jsencrypt": "^3.3.2",
    "jszip": "^3.10.1",
    "nprogress": "^0.2.0",
    "path-browserify": "^1.0.1",
src/api/user.js
@@ -1,25 +1,31 @@
import request from '@/utils/request';
import formatPassword from '@/utils/formatPassword.js';
export function login(data) {
export function login(uname, usnId) {
  return request({
    url: '/user/login',
    method: 'post',
    data
    method: 'GET',
    url: '/login/login',
    params: {
      uname,
      usnId: encodeURIComponent(formatPassword(usnId))
    }
  });
}
export function getInfo(token) {
export function getInfo(uname, usnId) {
  return request({
    url: '/vue-element-admin/user/info',
    method: 'get',
    params: { token }
    method: 'GET',
    url: '/login/login',
    params: {
      uname,
      usnId: encodeURIComponent(formatPassword(usnId))
    }
  });
}
export function logout(token) {
  return request({
    url: '/vue-element-admin/user/logout',
    method: 'post',
    params: { token }
    url: '/login/logout',
    method: 'post'
  });
}
src/layout/index.vue
@@ -22,6 +22,7 @@
import { mapState } from 'pinia';
import store from '@/store';
import { defineComponent } from 'vue';
import changeTheme from '@/utils/changeTheme.js';
export default defineComponent({
  name: 'LayoutIndex',
@@ -33,10 +34,16 @@
    Sidebar,
    TagsView
  },
  watch: {
    theme() {
      changeTheme(this.theme);
    }
  },
  mixins: [ResizeMixin],
  computed: {
    ...mapState(store.app, ['sidebar', 'device']),
    ...mapState(store.settings, {
      theme: 'theme',
      showSettings: 'showSettings',
      needTagsView: 'tagsView',
      fixedHeader: 'fixedHeader'
@@ -54,13 +61,19 @@
    handleClickOutside() {
      store.app().closeSidebar({ withoutAnimation: false });
    }
  },
  beforeMount() {
    changeTheme(this.theme);
  },
  mounted() {
  }
});
</script>
<style lang="scss" scoped>
@import "@/styles/mixin.scss";
// @import "@/styles/variables.module.scss";
@import "@/styles/element/index.scss";
.app-wrapper {
  @include clearfix;
src/store/modules/settings.ts
@@ -1,12 +1,13 @@
import { defineStore } from 'pinia';
import defaultSettings from '@/settings';
import changeTheme from '@/utils/changeTheme';
const { showSettings, tagsView, fixedHeader, sidebarLogo, secondMenuPopup } = defaultSettings;
export default defineStore({
  id: 'settings',
  state: () => ({
    theme: '#1890ff',
    theme: 'blue',
    showSettings: showSettings,
    tagsView: tagsView,
    fixedHeader: fixedHeader,
@@ -19,6 +20,10 @@
      // eslint-disable-next-line no-prototype-builtins
      if (this.hasOwnProperty(key)) {
        this[key] = value;
        // 如果是修改主题,就切换html标签的class
        if (key === 'theme') {
          changeTheme(value);
        }
      }
    }
  }
src/store/modules/user.ts
@@ -1,6 +1,6 @@
import { defineStore } from 'pinia';
import { logout as apiLogout, getInfo as apiGetInfo } from '@/api/user';
import { getToken, setToken, removeToken } from '@/utils/auth';
import { login as apiLogin, logout as apiLogout } from '@/api/user';
import { getToken, removeToken, setToken } from '@/utils/auth';
import router, { resetRouter } from '@/router';
import tagsViewStore from './tagsView';
import permissionStore from './permission';
@@ -27,19 +27,17 @@
  getters: {},
  actions: {
    // user login
    login():Promise<void> {
      // const { username, password } = userInfo;
      return new Promise((resolve) => {
        setToken('admin');
        resolve();
        // apiLogin({ username: username.trim(), password: password }).then(response => {
        //   const { data } = response;
        //   this.token = data.token;
        //   setToken(data.token);
        //   resolve();
        // }).catch(error => {
        //   reject(error);
        // });
    login(userInfo):Promise<void> {
      const { username, password } = userInfo;
      return new Promise((resolve, reject) => {
        apiLogin(username.trim(), password).then(response => {
          this.token = 'admin';
          setToken('admin');
          console.log(response);
          resolve();
        }).catch(error => {
          reject(error);
        });
      });
    },
@@ -64,7 +62,7 @@
    // user logout
    logout():Promise<void> {
      return new Promise((resolve, reject) => {
        apiLogout(this.token).then(() => {
        apiLogout().then(() => {
          this.token = '';
          this.roles = [];
          removeToken();
src/styles/element-ui.scss
@@ -0,0 +1 @@
src/styles/element/blue.scss
New file
@@ -0,0 +1,4 @@
.hdw-card {
  border: 2px solid #143a92;
}
src/styles/element/index.scss
@@ -21,7 +21,7 @@
// comment next lines to use default color
@forward "element-plus/theme-chalk/src/common/var.scss" with ( // do not use same name, it will override.
  $colors: $--colors,
  $button-padding-horizontal: ("default": 50px) //
  $button-padding-horizontal: ("default": 50px) //
);
// if you want to import all
@@ -31,4 +31,5 @@
// @debug $--colors;
// custom dark variables
@use "./dark.scss";
@use "./dark.scss";
@use './blue.scss';
src/styles/index.scss
@@ -16,6 +16,7 @@
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
  margin: 0;
  color: #ffffff;
}
label {
src/utils/RSA.js
New file
@@ -0,0 +1,30 @@
import { JSEncrypt } from 'jsencrypt';
import const_num from '@/utils/const/const_num.js';
export default {
  /**
   * 非对称加密算法-加密
   * @param word  需要加密的字符串
   * @returns {string | false}
   */
  encrypt(word) {
    const encryptor = new JSEncrypt();
    const publicKey = const_num.publicKey;
    encryptor.setPublicKey(publicKey);
    return encryptor.encrypt(word);
  },
  /**
   * 非对称加密算法-解密
   * @param word
   * @param privateKey
   * @returns {string | false}
   */
  decrypt(word, privateKey) {
    if (!privateKey) {
      return '请写入私钥';
    }
    const decrypt = new JSEncrypt();
    decrypt.setPrivateKey(privateKey);
    return decrypt.decrypt(word);
  }
};
src/utils/changeTheme.js
New file
@@ -0,0 +1,8 @@
function changeTheme(theme) {
  const htmlTag = document.querySelector('html');
  // 清空所有类
  htmlTag.className = '';
  htmlTag.classList.add(theme);
}
export default changeTheme;
src/utils/const/const_num.js
New file
@@ -0,0 +1,40 @@
export default {
  //privateKey: "MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAI+kneP5IdDr2Wqr5KF"+
  //   "Xt14DjRj7ytitrquvhF44n5QTt6Ty2wkmtzLXEw7VKimEl0ddfBI1tlaGclb0aUirVSboimWTAVz8C3Kh4kM/cQm1RmAjkfp"+
  //   "9LPQE8sUefXwLQ3HPUGvXT1TTsOpB0yxqtwGYpdhDD7ahk7PQqkDlvQVrAgMBAAECgYA8ASdX4W2n6a4kKnRSleLqqg8aHazqAP"+
  //   "vTinmAJqU65VW02SJ42yxyV3gFnTSErXfIfxviO3/U+0ruWiFVEwV5oDEh0dOd+HHGm4YzFXIRglMeRBgLuVJ+owzoVDwZsti"+
  //   "IBa69DIjaJtmpSf5FjwxAth+gtCv3e11IXHraKN720QJBAMPMB1WtmpRGYHxWVYjKSL+RGw+h3gMQLk3exZjhmYRlXuqfVZ2Zol+NazDc59"+
  //   "K5f+geMdJ0/X2kKnKLVjWzYHMCQQC7z1cFYswtLemxGfj+dwlVC01VL4pKa7HGHl/FAQ2UNYZY2d5hE/nXYbTpfI0gMowX926/aFpia7Nb"+
  //   "AUJO7WEpAkAyUFa+LJthaOhYazMVsK2bFKW4kabkcJ8Fga6TR73UaNxIPGOa2SUBmuylpM6ptuNoeYHiDBAr3ijOQIIJ0KuDAkBy9fPahCNe9F+73"+
  //   "J4hhVPdDtIDdto7u7hSAX215XMeabUW5iXNXqDsSg6nbWolb0t50CemWoYZALwE1Lx1+7AhAkEAoZtFt+2skjAxHEqNUye4vKBqB2Ng/wmfitCfT34"+
  //   "lXWQsxs4BGk/8eQMzkam9bcB7FcinolxHF/1UjsUYpI+AgA==",
  //privateKey: "",
  //publicKey: "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCPpJ3j+SHQ69lqq+ShV7deA40Y+8rYra6rr4ReOJ+UE7ek8tsJJrcy1xMO1SophJdH"+
  //   "XXwSNbZWhnJW9GlIq1Um6IplkwFc/AtyoeJDP3EJtUZgI5H6fSz0BPLFHn18C0Nxz1Br109U07DqQdMsarcBmKXYQw+2oZOz0KpA5b0FawIDAQAB"
  publicKey: "MIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIBigKCAYEAu7CdCMIoWXUX584JpmE1bTE1r1MtmZGswsSbsm4s9zqETQ4BmUT2kz/wvvGsI8" +
    "T3ZvTT4KIyKP4Ez+yNVejMM5XwR95KF4e3UwMc724buWKl4pVL09kvkCZt8ZKf359VAvhyHHz80wIiVmJs6xbho7OBsv/s7Hwho0n4HPL4u/eNR5vWa" +
    "2rtgQG1+fi1XP0UiSRKKW15Va9R2CI3zB+sffquhyX5fi+06NibWzk7OPU+EGvAwkaJtrmfLAvpwr4+G0MBLIsPVFV17Sgpoj62rtfbhHwmLSo1JTw+" +
    "/JskDQOjxXfw+w3uHAZgPTlEmn2Ya9ssIljqCBfvM9nbGUWcnmppKlPm6kECa4RsgPiRgPFV+nT/Q98kfUTb798Sy63x4NIZkLQn1DDbmcAgUqLR6y" +
    "1r0fD8Ne3vVtuZlVR/8ZlcRAfb+th2cNN0rytrnUreJo7kPtTFdkNtmj0KdUkRO8ea0YymEQal+b0tCl3V8osSy+qO2OVRd7yCvpOWEYOBAgMBAAE=",
  privateKey: "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"
}
src/utils/const/const_theme.js
New file
@@ -0,0 +1,14 @@
export default [
  {
    label: '默认主题',
    value: 'default'
  },
  {
    label: '暗黑主题',
    value: 'dark'
  },
  {
    label: '科技主题',
    value: 'blue'
  }
];
src/utils/formatPassword.js
New file
@@ -0,0 +1,9 @@
import { md5 } from 'js-md5';
import RSA from '@/utils/RSA.js';
function formatPassword(pwd) {
  const password = pwd + '&&&&&&&&&&' + md5(pwd);
  return RSA.encrypt(password);
}
export default formatPassword;
src/views/device/lock/index.vue
@@ -1,12 +1,16 @@
<script lang="ts">
import { defineComponent } from 'vue';
import HdwCard from '@/components/HdwCard/index.vue';
import const_theme from '@/utils/const/const_theme';
import store from '@/store';
export default defineComponent({
  name: 'LockManage',
  components: { HdwCard },
  data() {
    return {
      theme: store.settings().theme,
      themes: const_theme,
      tableData: [
        {
          type: '蓝牙',
@@ -28,7 +32,13 @@
    };
  },
  methods: {
    handleChangeTheme(val) {
      console.log(val);
      store.settings().changeSetting({
        key: 'theme',
        value: val
      });
    }
  }
});
</script>
@@ -93,6 +103,21 @@
                  </el-select>
                </div>
              </div>
              <div class="tools-filter-item">
                <div class="filter-label">主题:</div>
                <div class="filter-content">
                  <el-select
                      v-model="theme"
                      placeholder="请选择"
                      size="small"
                      @change="handleChangeTheme"
                      style="width: 180px">
                    <el-option
                        v-for="item in themes" :key="item.label"
                        :label="item.label" :value="item.value"/>
                  </el-select>
                </div>
              </div>
            </div>
            <el-button type="primary" size="small" :icon="Search">查询</el-button>
          </div>
src/views/login/index.vue
@@ -50,7 +50,7 @@
  name: 'Login',
  data() {
    const validateUsername: FormItemRule['validator'] = (_rule, value, callback) => {
      if (!validUsername(value)) {
      if (!value.trim()) {
        callback(new Error('请输入用户名'));
      } else {
        callback();
@@ -101,11 +101,18 @@
    } else if (this.loginForm.password === '') {
      (this.$refs.password as HTMLElement).focus();
    }
    this.themeChange('blue');
  },
  unmounted() {
    // window.removeEventListener('storage', this.afterQRScan)
  },
  methods: {
    themeChange(val) {
      store.settings().changeSetting({
        key: 'theme',
        value: val
      });
    },
    checkCapslock(e) {
      const { key } = e;
      this.capsTooltip = key && key.length === 1 && (key >= 'A' && key <= 'Z');