login.html 16.2 KB
<!DOCTYPE html>
<html lang="zh-CN" class="pos-app-root">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover, maximum-scale=5">
  <title>PongGame 收银台 · 登录</title>
  <link rel="stylesheet" href="css/style.css">
  <link rel="stylesheet" href="css/pos-unified.css">
  <link rel="stylesheet" href="css/pos-login-reflow.css">
  <script src="./js/vue.min.js"></script>
  <script src="./axios-1.x/axios-1.x/dist/axios.js"></script>
  <script src="./axios-1.x/axios-1.x/dist/axios.min.js"></script>
  <script type="text/javascript" src="./js/jquery.min.js"></script>
  <!-- 引入 crypto-js 库 - 使用多个CDN源作为备选 -->
  <script>
    // 动态加载CryptoJS库,支持多个CDN源
    (function() {
      var cryptoJsLoaded = false;
      var cdnSources = [
        'https://cdn.jsdelivr.net/npm/crypto-js@4.1.1/crypto-js.js',
        'https://unpkg.com/crypto-js@4.1.1/crypto-js.js',
        'https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.1.1/crypto-js.min.js'
      ];
      var currentIndex = 0;
      
      function loadCryptoJS() {
        if (currentIndex >= cdnSources.length) {
          console.error('所有CDN源加载失败,请检查网络连接');
          alert('CryptoJS库加载失败,请检查网络连接或联系管理员');
          return;
        }
        
        var script = document.createElement('script');
        script.src = cdnSources[currentIndex];
        script.onload = function() {
          cryptoJsLoaded = true;
          console.log('CryptoJS库加载成功,来源:', cdnSources[currentIndex]);
        };
        script.onerror = function() {
          console.warn('CDN源加载失败:', cdnSources[currentIndex]);
          currentIndex++;
          loadCryptoJS(); // 尝试下一个CDN源
        };
        document.head.appendChild(script);
      }
      
      loadCryptoJS();
    })();
  </script>
</head>

<body class="pos-page pos-page--login">
  <div id="app">
    <main class="pos-login-page" role="main">
      <div class="pos-login-center">
        <div class="pos-login-split">
          <aside class="pos-login-split__brand" aria-label="PongGame 收银台">
            <div class="pos-login-split__brand-bg" aria-hidden="true"></div>
            <div class="pos-login-split__brand-inner">
              <div class="pos-login-split__logo" aria-hidden="true">
                <svg class="pos-inline-svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5">
                  <path stroke-linecap="round" stroke-linejoin="round" d="M13.5 21v-7.5a.75.75 0 01.75-.75h3a.75.75 0 01.75.75V21m-9 0H3.75A2.25 2.25 0 012 18.75v-9.5A2.25 2.25 0 014.25 7h4.379a2.25 2.25 0 001.59-.659l.816-.816A2.25 2.25 0 0112.122 4.5h7.128A2.25 2.25 0 0122 6.628V18.75A2.25 2.25 0 0119.75 21H13.5z" />
                </svg>
              </div>
              <h1 class="pos-login-split__title">
                <span class="pos-login-split__title-main">PongGame</span>
                <span class="pos-login-split__title-sub">收银台</span>
              </h1>
              <p class="pos-login-split__welcome">欢迎回来,登录后继续营业</p>
            </div>
            <div class="pos-login-split__pill">
              <svg class="pos-inline-svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" aria-hidden="true">
                <path stroke-linecap="round" stroke-linejoin="round" d="M9 17.25v1.007a3 3 0 01-.879 2.122L7.5 21h9l-.621-.621A3 3 0 0115 18.257V17.25m6-12V15a2.25 2.25 0 01-2.25 2.25H5.25A2.25 2.25 0 013 15V5.25m18 0A2.25 2.25 0 0018.75 3H5.25A2.25 2.25 0 003 5.25m18 0V12a2.25 2.25 0 01-2.25 2.25H5.25A2.25 2.25 0 013 12V5.25" />
              </svg>
              <span>高效运营 · 对接 ERP</span>
            </div>
          </aside>
          <div class="pos-login-split__panel">
            <div class="pos-login-split__panel-inner">
              <header class="pos-login-welcome-head">
                <h2 class="pos-login-welcome-head__title">欢迎登录</h2>
                <p class="pos-login-welcome-head__sub">请输入门店账号信息</p>
              </header>
              <form id="loginForm" @submit.prevent="gain">
                <div class="pos-login-fieldset">
                  <div class="pos-form-group">
                    <label for="username">用户名</label>
                    <div class="pos-login-input-row">
                      <span class="pos-login-input-row__icon" aria-hidden="true">
                        <svg class="pos-inline-svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5">
                          <path stroke-linecap="round" stroke-linejoin="round" d="M15.75 6a3.75 3.75 0 11-7.5 0 3.75 3.75 0 017.5 0zM4.501 20.118a7.5 7.5 0 0114.998 0A17.933 17.933 0 0112 21.75c-2.676 0-5.216-.584-7.499-1.632z" />
                        </svg>
                      </span>
                      <input id="username" class="pos-input" type="text" v-model="username" placeholder="请输入用户名或手机号" autocomplete="username" @input="loginError = ''">
                    </div>
                  </div>
                  <div class="pos-form-group">
                    <label for="password">密码</label>
                    <div class="pos-login-input-row">
                      <span class="pos-login-input-row__icon" aria-hidden="true">
                        <svg class="pos-inline-svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5">
                          <path stroke-linecap="round" stroke-linejoin="round" d="M16.5 10.5V6.75a4.5 4.5 0 10-9 0v3.75m-.75 11.25h10.5a2.25 2.25 0 002.25-2.25v-6.75a2.25 2.25 0 00-2.25-2.25H6.75a2.25 2.25 0 00-2.25 2.25v6.75a2.25 2.25 0 002.25 2.25z" />
                        </svg>
                      </span>
                      <input id="password" class="pos-input" type="password" v-model="password" placeholder="请输入密码" autocomplete="current-password" @input="loginError = ''">
                    </div>
                  </div>
                </div>
                <div class="pos-form-group pos-form-group--store">
                  <div class="pos-login-store-shell">
                    <div id="pos-store-field-label" class="pos-store-label">选择门店 <span class="pos-store-label__hint">点击卡片选择</span></div>
                    <div v-if="storeListLoading" class="pos-store-grid pos-store-grid--loading" role="status" aria-live="polite">门店列表加载中…</div>
                    <div v-else-if="!storeList.length" class="pos-store-grid pos-store-grid--empty" role="status">暂无门店数据,请检查网络或后台配置</div>
                    <div
                      v-else
                      class="pos-store-grid pos-store-grid--matrix"
                      role="listbox"
                      aria-labelledby="pos-store-field-label"
                    >
                      <button
                        v-for="store in storeList"
                        :key="store.id"
                        type="button"
                        class="pos-store-tile pos-store-tile--cell settlement-touch"
                        :class="{ 'pos-store-tile--active': isStoreSelected(store) }"
                        role="option"
                        :aria-selected="isStoreSelected(store) ? 'true' : 'false'"
                        @click="pickStore(store); loginError = ''"
                      >
                        <span class="pos-store-tile__name">{{ store.mdmc || '无' }}</span>
                      </button>
                    </div>
                  </div>
                </div>
                <div v-if="loginError" class="pos-login-form-error" role="alert">{{ loginError }}</div>
                <button type="submit" class="pos-btn pos-btn--primary settlement-touch">登录</button>
                <p class="pos-login-footnote">门店账号,对接结算 ERP 系统</p>
              </form>
            </div>
          </div>
        </div>
      </div>
    </main>
  </div>

  <script>
    const app = new Vue({
      el: '#app',
      data: {
        baseUrl: (() => {
          const currentOrigin = window.location.origin;
          if (currentOrigin.includes('localhost') || currentOrigin.includes('127.0.0.1')) {
            return 'http://localhost:2011';
          } else {
            return currentOrigin.replace(/:\d+$/, '');
          }
        })(),
        password: '',
        username: '',
        selectedStore: '',
        storeList: [],
        storeListLoading: true,
        loginError: ''
      },
      created() {
          localStorage.setItem('userId', '');
          localStorage.setItem('token', '');
          localStorage.setItem('username', '');
          this.loadStoreList();
      },
  
      methods: {
        storeIdStr(id) {
          return id == null ? '' : String(id);
        },
        isStoreSelected(store) {
          return this.storeIdStr(store.id) === this.storeIdStr(this.selectedStore);
        },
        pickStore(store) {
          this.selectedStore = this.storeIdStr(store.id);
        },
        loadStoreList() {
          var that = this;
          that.storeListLoading = true;
          axios({
            url: that.baseUrl + "/api/Extend/WtMd",
            method: 'GET',
            // 列表接口分页:不传 pageSize 时后端默认 50,门店多于 50 时登录页显示不全
            params: {
              currentPage: 1,
              pageSize: 2000,
              sort: 'asc',
              sidx: 'mdmc'
            },
            headers: {
              'accept': 'text/plain',
              'Content-Type': 'application/json',
            }
          }).then((res) => {
            if (res.data.code === 200) {
              var raw = res.data.data.list || [];
              // 门店主键必须当字符串用,避免 JSON 数字精度丢失导致与后台 wt_skzhb.ssmd 对不上
              that.storeList = raw.map(function (s) {
                var o = Object.assign({}, s);
                if (o.id != null && o.id !== '') o.id = String(o.id);
                return o;
              });
              console.log('门店列表加载成功:', that.storeList);
            } else {
              console.error('获取门店列表失败:', res.data);
            }
          }).catch((error) => {
            console.error('获取门店列表出错:', error);
          }).finally(function () {
            that.storeListLoading = false;
          });
        },
        gain() {
          var that = this;
          that.loginError = '';

          // ✅ 登录时立即清除客户选择,确保每次登录后都是未选择客户状态
          localStorage.removeItem('hyinfo');

          function fail(msg) {
            that.loginError = msg;
            try {
              window.alert(msg);
            } catch (e) {}
          }

          if (that.storeListLoading) {
            fail('门店列表正在加载,请稍候再试');
            return;
          }

          var account = (that.username || '').trim();
          if (!account) {
            fail('请输入用户名');
            return;
          }

          if (that.password === undefined || that.password === null || String(that.password).length === 0) {
            fail('请输入密码');
            return;
          }

          if (!that.selectedStore) {
            fail('请选择门店');
            return;
          }

          if (typeof CryptoJS === 'undefined') {
            fail('加密库正在加载中,请稍候再试。若持续失败请刷新页面或检查网络。');
            console.error('CryptoJS未定义,请检查CDN是否加载成功');
            return;
          }
          
          // 对密码进行 MD5 加密
          const encryptedPassword = CryptoJS.MD5(that.password).toString();
          const formData = new URLSearchParams();
          formData.append('account', account);
          formData.append('password', encryptedPassword);

          console.log({
            account: account,
            password: encryptedPassword
          });

          axios({
            url: that.baseUrl + "/api/oauth/Login",
            headers: {
              'accept': 'text/plain',
              'Content-Type': 'application/x-www-form-urlencoded',
            },
            method: 'POST',
            data: formData.toString()
          }).then((res) => {
            if(res.data.code === 200){
              console.log('登录成功,获取到的 token 为:', res.data.data.token);
              axios({
                url: this.baseUrl + "/api/oauth/CurrentUser",
                method: 'GET',
                headers: {
                  Authorization: res.data.data.token
                },
              }).then((res1) => {
                console.error(res1)
                if (res1.data.code === 200) {
                  localStorage.setItem('userId', res1.data.data.userInfo.userId);
                  localStorage.setItem('token', res.data.data.token);
                  localStorage.setItem('username', res1.data.data.userInfo.userName);
                  
                  // 存储选中的门店信息
                  const selectedStoreInfo = that.storeList.find(function (store) {
                    return that.storeIdStr(store.id) === that.storeIdStr(that.selectedStore);
                  });
                  if (selectedStoreInfo) {
                    var toSave = Object.assign({}, selectedStoreInfo);
                    if (toSave.id != null && toSave.id !== '') toSave.id = String(toSave.id);
                    localStorage.setItem('selectedStore', JSON.stringify(toSave));
                    console.log('门店信息已存储:', toSave);
                  }
                  // window.alert('登录成功')
                  axios({
                    url: this.baseUrl + "/api/permission/Users/"+res1.data.data.userInfo.userId,
                    method: 'GET',
                    headers: {
                      Authorization: res.data.data.token
                    },
                  }).then((res2) => {
                    console.error(res2)
                    if (res2.data.code === 200) {
                      // 使用用户选择的门店ID,而不是用户信息中的默认门店
                      // 这样收银员可以选择任意门店进行收银
                      const storeIdToUse = String(that.selectedStore || res2.data.data.mdxx || '').trim();
                      localStorage.setItem('mdId', storeIdToUse); 
                      axios({
                        url: this.baseUrl + "/api/Extend/WtCk?pageSize=1&ssmd=" + storeIdToUse,
                        method: 'GET',
                        headers: {
                          Authorization: res.data.data.token
                        },
                      }).then((res3) => {
                        console.error(res3)
                        if (res3.data.code === 200 && res3.data.data.list.length > 0) {
                          localStorage.setItem('ckinfo', JSON.stringify(res3.data.data.list[0])); 
                        }else {
                          localStorage.setItem('ckinfo', null); 
                        }
                        // ✅ 再次确保清除客户选择(防止其他地方设置)
                        localStorage.removeItem('hyinfo');
                        // 使用相对路径,部署在 /sy/ 下时跳转到 /sy/home.html
                        window.location.href = 'home.html?fromLogin=true';
                      }) 
                    }
                  }) 
                  
                }
              })

           
              // 将 token 存储到本地存储
              
            } else {
              that.loginError = '登录失败,请检查用户名或密码是否正确。';
              try {
                window.alert(that.loginError);
              } catch (e) {}
              console.log('登录失败,错误码:', res.data.code);
            }
          }).catch(function (err) {
            console.error('登录请求异常:', err);
            that.loginError = '网络异常,请检查网络后重试。';
            try {
              window.alert(that.loginError);
            } catch (e) {}
          });
        }
        // 可添加登录相关方法
      }
    });
  </script>
</body>

</html>