药品销售管理系统 ——上(<-分页)

1.登录界面 login.html

<!DOCTYPE html>
<html lang="en">
<head>
    <style>
        body{
            background-color: #e9ecef;

        }
        main{
            background-color:whitesmoke;
            width: 25rem;
            margin:auto;
            /* 水平方向,左右同时占据一半空间;实现水平居中 */
            margin-top:20vh;
            /* vh:相对整个浏览器网页内容的显示框viewport的宽度和高度 ;100vh 就是 100% 的 viewport高度;它会随着窗口高度的调整,字体大小跟着变化 */
            text-align: center;
            /* 指定文本内容的对齐方式 */
        }
    </style>
</head>
<body>
    <main>
        <br>
        <div style="display: flex; justify-content: center;">
            <img src="/assets/images/logo.jpg" style="border-radius:50%;width:2.5rem;margin-right:1rem">
            <!-- main属于block类型元素 ;block元素特征:垂直方向,占据的空间由其内容大小决定 -->
            <!-- rem用来修饰 元素的 宽度、高度 ,同样也是相对于 根元素 html 的字体大小 -->
            <!-- 相对的是 根元素 html 的字体大小 -->
            <!-- margin:盒子模型,外边距,盒子与盒子间的距离 -->
            <span style="font-size: 1.8rem">黑羽医疗</span> 
        </div>
 
        <p>输入用户名、密码登录</p>
        <div>
         <input type="text" placeholder="用户名"> 
         <!-- 提供可描述输入字段预期值的提示信息 --> 
        </div>

        <br>
        <div>
        <!-- div 块级元素 ;特点独占一行 -->
         <input type="password"  placeholder="密码">   
        </div>

        <br>
        <div>
            <button id="loginButton">登录</button>
        </div>

        <br>
        <div>
            <a href="/register.html">没有账号?请先注册</a>
        </div>
        
        <br>
    </main>
    
</body>
</html>

登录功能的实现(head内的style上)

    <script src="https://cdn.jsdelivr.net/npm/jquery/dist/jquery.min.js"></script>

    <!-- 事件处理:1.DOM对象的addEventListener方法 2.DOM对象的事件属性指定事件处理函数;事件属性名以on开头后面跟事件名称 -->
    <!-- 注意:放head里面的话会导致网页内容还没渲染完就先被执行,DOM里面的内容还没创建都还没有body节点 => 指定一个页面加载事件,等页面加载完之后再执行箭头函数 -->
    <script>
        // 先选择登录按钮
        window.onload =() => {
        document.querySelector('#loginButton').onclick = () => {
            //1.获取用户名、密码
            //alert('执行登录')
            //value:input标签属性,对应的是输入框里面的文本
            let username = document.querySelector('#username').value
            let password = document.querySelector('#password').value

            //2.把他们放到HTTP消息里发出去(使用jQuery) , 看请求消息的接口文档
            //byhy 88888888
            $.post(
            '/api/mgr/signin',//请求网址
            {
                username:username,
                password:password,
            }
            )
            //3.当服务端返回ret=0时,跳转到真正的网址 /hyms.html
            //jQuery解析响应消息
            $.ajax({
                url: '/api/mgr/signin',        
                type: 'POST', 
                data: 'username=byhy&password=88888888',
                // 正确返回;回调函数被传入3个参数:data 从服务端返回的数据 ,textStatus 返回的状态文本描述,xhr XMLHttpRequest的扩展类型jqXHR的对象
                success: function(data, textStatus, xhr) { 
                    if(data.ret === 0){
                        //重定向网址
                        location.href = 'hyms.html'
                    }
                    else{
                        alert('登陆失败: ' + data.msg)
                    }
                },
                //错误
                error:function (xhr, textStatus, errorThrown ){
                    console.error(`${xhr.status} \n${textStatus} \n${errorThrown }`)
                }
            })
        }
    };
    </script>

2.主页各区域样式 hyms.html

<!DOCTYPE html>
<html lang="en">
    <head>
      <meta charset="utf-8">
      <title>药品销管</title>
        <style>
        body{
          height: 100vh;
          max-width: 1250px;
          /* 上下设成0;左右均分 */
          margin: 0 auto;
          display: grid;
          grid-template-rows:  auto 1fr auto;
          /* 右边占据所有剩余宽度 */
          grid-template-columns: minmax(15rem,20rem) 1fr;
        }    
        .nav-logo{
          border-left: 1px solid #e5eaef;
          color:rgb(8, 96, 8);
          display:flex;
          align-items: center;
          justify-content: center;
        }
        nav{
          background-color: rgb(4, 115, 155);
          color: white;
          display: flex;
          flex-flow: row wrap;
          /* 保证不会挤到一起去,再小出现滚动条 */
          min-width: 30rem;
        }
        .sub-nav-bar{
          list-style-type: none;
          display:flex;
          flex-flow: row wrap;
          gap:2rem;
          align-items: center;
          justify-content: center;
        }
        .side-menu{
          border-left: 1px solid #e5eaef;
          border-top: 1px solid #e5eaef;
          padding:1rem;
        }
        main{
          background-color: #d0d0d1;
          padding:1rem;
        }
        .footer-left{
          border-left: 1px solid #e5eaef;
        }
        footer{
          background-color: #e5eaef;
          text-align: center;
          padding:1rem;
        }
        </style>
    </head>
    <body>
        <div class="nav-logo">管理员操作</div> 
        <nav>

            <ol class="sub-nav-bar">
              <li>产品</li>
              <li>客户</li>
              <li>渠道</li>
              <li>订单</li>
              <li>统计</li>
            </ol>
       
         
            <ol class="sub-nav-bar" style="margin-left: auto; margin-right: 1rem;">
              <li>白月黑羽</li>
            </ol>
        
        </nav>

        <div class="side-menu">
          操作菜单
          <pre>
              2
              2
              2
              2
              2
              2
              2        
          </pre>
        </div>
        <main>正文</main>
        <div class="footer-left"></div>
        <footer>
          白月黑羽版权所有
          <br>
          <!-- 自己试在style里加style="padding:1rem;",注意一点:白月黑羽版权所有 是content,不是盒子-->
          <small>2020-2022 @copy rights reserved</small>
        </footer>
    </body>
</html>

侧边栏菜单样式

<!DOCTYPE html>
<html lang="en">
    <head>
      <meta charset="utf-8">
      <title>药品销管</title>
        <style>
        body{
          height: 100vh;
          max-width: 1250px;
          /* 上下设成0;左右均分 */
          margin: 0 auto;
          display: grid;
          grid-template-rows:  auto 1fr auto;
          /* 右边占据所有剩余宽度 */
          grid-template-columns: minmax(15rem,20rem) 1fr;
        }    
        .nav-logo{
          border-left: 1px solid #e5eaef;
          color:rgb(8, 96, 8);
          display:flex;
          align-items: center;
          justify-content: center;
        }
        nav{
          background-color: rgb(4, 115, 155);
          color: white;
          display: flex;
          flex-flow: row wrap;
          /* 保证不会挤到一起去,再小出现滚动条 */
          min-width: 30rem;
        }
        .sub-nav-bar{
          list-style-type: none;
          display:flex;
          flex-flow: row wrap;
          gap:2rem;
          align-items: center;
          justify-content: center;
        }
        .side-menu{
          border-left: 1px solid #e5eaef;
          border-top: 1px solid #e5eaef;
          margin: 0;
          padding:1rem;
          list-style-type: none;
          /* 根字体的90% */
          font-size:.9rem;
          display:flex;
          /* 列排 */
          flex-direction: column;
          gap:1rem;
        }
        .sub-menu{
          list-style-type: none;
          display:flex;
          /* 列排 */
          flex-direction: column;
          gap: .5rem;

          font-size: .85rem;
          padding:0 1rem;

        }
        .side-menu .menu-item{
          padding-left: 1rem;
        }
        /* 交集选择器,是menu-item又是menu-open的 */
        .side-menu .menu-item.menu-open{
          border-left:1px solid gray;
        }
        main{
          background-color: #d0d0d1;
          padding:1rem;
        }
        .footer-left{
          border-left: 1px solid #e5eaef;
        }
        footer{
          background-color: #e5eaef;
          text-align: center;
          padding:1rem;
        }
        </style>
    </head>
    <body>
        <div class="nav-logo">管理员操作</div> 
        <nav>

            <ol class="sub-nav-bar">
              <li>产品</li>
              <li>客户</li>
              <li>渠道</li>
              <li>订单</li>
              <li>统计</li>
            </ol>
       
         
            <ol class="sub-nav-bar" style="margin-left: auto; margin-right: 1rem;">
              <li>白月黑羽</li>
            </ol>
        
        </nav>

        <ul class="side-menu">
          <!-- 菜单头部 -->
          <li class="menu-header">操作菜单</li>
          <li class="menu-item">产品</li>
          <li class="menu-item">客户</li>
          <li class="menu-item menu-open">渠道
            <ul class="sub-menu">
              <li class="menu-item">子菜单1</li>
              <li class="menu-item">子菜单2</li>
            </ul>
          </li>
          <li class="menu-item menu-open">订单
            <ul class="sub-menu">
              <li class="menu-item">子菜单1</li>
              <li class="menu-item">子菜单2</li>
            </ul>
          </li>
          <li class="menu-item">统计</li>
        </ul>

        <main>正文</main>
        <div class="footer-left"></div>
        <footer>
          白月黑羽版权所有
          <br>
          <!-- 自己试在style里加style="padding:1rem;",注意一点:白月黑羽版权所有 是content,不是盒子-->
          <small>2020-2022 @copy rights reserved</small>
        </footer>
    </body>
</html>

导航栏下拉菜单样式

<!DOCTYPE html>
<html lang="en">
    <head>
      <meta charset="utf-8">
      <title>药品销管</title>
        <style>
        body{
          height: 100vh;
          max-width: 1250px;
          /* 上下设成0;左右均分 */
          margin: 0 auto;
          display: grid;
          grid-template-rows:  auto 1fr auto;
          /* 右边占据所有剩余宽度 */
          grid-template-columns: minmax(15rem,20rem) 1fr;
        }    
        .nav-logo{
          border-left: 1px solid #e5eaef;
          color:rgb(8, 96, 8);
          display:flex;
          align-items: center;
          justify-content: center;
        }
        /* 导航栏 */
        nav{
          background-color: rgb(4, 115, 155);
          color: white;
          display: flex;
          flex-flow: row wrap;
          /* 保证不会挤到一起去,再小出现滚动条 */
          min-width: 30rem;
        }
        .sub-nav-bar{
          list-style-type: none;
          display:flex;
          flex-flow: row wrap;
          gap:2rem;
          align-items: center;
          justify-content: center;
        }
        .dropdown-menu{
            position:absolute;
            list-style-type: none;
            background-color: white;
            color: #2e669f ;
            /* 整体下移 */
            margin-top: 1rem;
            font-size: .85rem;
            padding-left: 0;
            width:10rem;
        }
        .dropdown-menu .menu-item{
          /* 上下居中 */
          margin: .6rem;
        }
        .dropdown-divider{
          height:0;
          /* 一条边 */
          border-top:1px solid #e8dcdc;
        }
        /* 侧边栏 */
        .side-menu{
          border-left: 1px solid #e5eaef;
          border-top: 1px solid #e5eaef;
          margin: 0;
          padding:1rem;
          list-style-type: none;
          /* 根字体的90% */
          font-size:.9rem;
          display:flex;
          /* 列排 */
          flex-direction: column;
          gap:1rem;
        }
        .sub-menu{
          list-style-type: none;
          display:flex;
          /* 列排 */
          flex-direction: column;
          gap: .5rem;

          font-size: .85rem;
          padding:0 1rem;
        }
        .side-menu .menu-item{
          padding-left: 1rem;
        }
        /* 交集选择器,是menu-item又是menu-open的 */
        .side-menu .menu-item.menu-open{
          border-left:1px solid gray;
        }
        main{
          background-color: #d0d0d1;
          padding:1rem;
        }
        .footer-left{
          border-left: 1px solid #e5eaef;
        }

        footer{
          background-color: #e5eaef;
          text-align: center;
          padding:1rem;
        }

        .sub-nav-bar .menu-item{
          /* 相对于该元素在文档流中的正常位置进行偏移定位 */
          position: relative;
        }
        /* 子绝父相 注意这个.sub-nav-bar .menu-item是相对定位;.dropdown-menu是绝对定位*/
        /* 绝对定位查找父级的方式:就近找定位的父级,如果逐层查找不到这样的父级,就以浏览器窗口为参照进行定位 */
        .sub-nav-bar-right .dropdown-menu{
          /* 最终选择的元素是元素2 ,并且要求这个元素2是元素1的后代元素 ; 右对齐*/
          right:0;
        }

        </style>
    </head>
    <body>
        <div class="nav-logo">管理员操作</div> 
        <nav>

            <ol class="sub-nav-bar">
              <li class="menu-item">
                <!-- div ——块级,新开一行,水平方向占满父级 ;span ——行内,一行显示 -->
                <span>产品</span>
                <ul class="dropdown-menu">
                    <li class="menu-item">子菜单1</li>
                    <div class="dropdown-divider"></div>
                    <li class="menu-item">子菜单2</li>
                </ul>
              </li>

              <li class="menu-item"><span>客户</span></li>
              <li class="menu-item"><span>渠道</span></li>
              <li class="menu-item"><span>订单</span></li>
              <li class="menu-item"><span>统计</span></li>
            </ol>
       
         
            <ol class="sub-nav-bar sub-nav-bar-right" style="margin-left: auto; margin-right: 1rem;">
              <li class="menu-item">
                <span>白月黑羽</span>
                <ul class="dropdown-menu">
                  <li class="menu-item">子菜单1</li>
                  <div class="dropdown-divider"></div>
                  <li class="menu-item">子菜单2</li>
                  <div class="dropdown-divider"></div>
                  <li class="menu-item">子菜单3</li>
                </ul>
              </li>
            </ol>
        
        </nav>

        <ul class="side-menu">
          <!-- 菜单头部 -->
          <li class="menu-header">操作菜单</li>
          <li class="menu-item">产品</li>
          <li class="menu-item">客户</li>
          <li class="menu-item menu-open">渠道
            <ul class="sub-menu">
              <li class="menu-item">子菜单1</li>
              <li class="menu-item">子菜单2</li>
            </ul>
          </li>
          <li class="menu-item menu-open">订单
            <ul class="sub-menu">
              <li class="menu-item">子菜单1</li>
              <li class="menu-item">子菜单2</li>
            </ul>
          </li>
          <li class="menu-item">统计</li>
        </ul>

        <main>正文</main>
        <div class="footer-left"></div>
        <footer>
          白月黑羽版权所有
          <br>
          <!-- 自己试在style里加style="padding:1rem;",注意一点:白月黑羽版权所有 是content,不是盒子-->
          <small>2020-2022 @copy rights reserved</small>
        </footer>
    </body>
</html>

菜单项悬停高亮显示

<!DOCTYPE html>
<html lang="en">
    <head>
      <meta charset="utf-8">
      <title>药品销管</title>
        <style>
        body{
          height: 100vh;
          max-width: 1250px;
          /* 上下设成0;左右均分 */
          margin: 0 auto;
          display: grid;
          grid-template-rows:  auto 1fr auto;
          /* 右边占据所有剩余宽度 */
          grid-template-columns: minmax(15rem,20rem) 1fr;
        }    

        .nav-logo{
          border-left: 1px solid #e5eaef;
          color:rgb(8, 96, 8);
          display:flex;
          align-items: center;
          justify-content: center;
        }

        /* 导航栏 */
        nav{
          background-color: rgb(4, 115, 155);
          color: white;
          display: flex;
          flex-flow: row wrap;
          /* 保证不会挤到一起去,再小出现滚动条 */
          min-width: 30rem;
        }

        .sub-nav-bar{
          list-style-type: none;
          display:flex;
          flex-flow: row wrap;
          gap:2rem;
          align-items: center;
          justify-content: center;
          margin: 0;
        }

        .dropdown-menu{
            position:absolute;
            list-style-type: none;
            background-color: white;
            color: #2e669f ;
            /* 整体下移 */
            margin-top: .8rem;
            font-size: .85rem;
            padding-left: 0;
            width:10rem;
        }

        /* 菜单项 */
        /* 后代选择器:选中父元素 后代中 满足条件的元素 ;子代选择器:选择父元素 子代中 满足条件的元素*/
        .sub-nav-bar > .menu-item{
          /* 相对于该元素在文档流中的正常位置进行偏移定位 */
          position: relative;
          /* 上下为0,左右为.8rem ;注意:这里我只想设一级的子菜单->用子代选择器*/
          padding: .8rem; 
        }


        /* hover伪类选择器语法: 选择器:hover {css};选中鼠标悬停在元素上的状态,设置样式 */
        .sub-nav-bar .menu-item:hover{
          color:green;
          background-color: white;
        }

        .dropdown-menu .menu-item:hover{
          background-color: #e8f5e9;
        }


        /* 所有菜单项,我希望光标变成手 */
        .menu-item{
            cursor: pointer;
        }
         
        .dropdown-menu .menu-item{
          /* 上下居中 margin: .6rem; 换成padding */
          /* 背景色设置范围:有效区域包括这个元素的 内容区、padding部分、border部分。也就是包含块除了margin部分 */
          padding: .6rem;
        }

 
        .dropdown-divider{
          height:0;
          /* 一条边 */
          border-top:1px solid #e8dcdc;
        }

        /* 侧边栏 */
        .side-menu{
          border-left: 1px solid #e5eaef;
          border-top: 1px solid #e5eaef;
          margin: 0;
          padding:1rem;
          list-style-type: none;
          /* 根字体的90% */
          font-size:.9rem;
          display:flex;
          /* 列排 */
          flex-direction: column;
          /* flex布局列间距 */
          /* gap:.2rem; */
        }

        .sub-menu{
          list-style-type: none;
          display:flex;
          /* 列排 */
          flex-direction: column;
          /* gap: .5rem; */
          font-size: .85rem;
          padding:0 1rem;
        }

        .side-menu .menu-header{
          color:#837b70;
        }

        .side-menu .menu-item{
          color: #5e81a5;
          /* padding-left: 1rem; */
          /* 上 右 下 左 */
          padding: .5rem 0 .5rem 1rem;
          margin: .2rem 0;
        }
        .side-menu .menu-item:hover{
          background-color: #e8f5e9;
        }
        .sub-menu .menu-item:hover{
          background-color: #bce5bf;
        }

        /* 交集选择器,是menu-item又是menu-open的 */
        .side-menu .menu-item.menu-open{
          color:#6b6464;
          border-left:1px solid green;
        }

        main{
          background-color: #d0d0d1;
          padding:1rem;
        }

        .footer-left{
          border-left: 1px solid #e5eaef;
        }

        footer{
          background-color: #e5eaef;
          text-align: center;
          padding:1rem;
        }

        /* 子绝父相 注意这个.sub-nav-bar .menu-item是相对定位;.dropdown-menu是绝对定位*/
        /* 绝对定位查找父级的方式:就近找定位的父级,如果逐层查找不到这样的父级,就以浏览器窗口为参照进行定位 */
        .sub-nav-bar-right .dropdown-menu{
          /* 最终选择的元素是元素2 ,并且要求这个元素2是元素1的后代元素 ; 右对齐*/
          right:0;
        }

        </style>
    </head>
    <body>
        <div class="nav-logo">管理员操作</div> 
        <nav>

            <ol class="sub-nav-bar">
              <li class="menu-item">
                <!-- div ——块级,新开一行,水平方向占满父级 ;span ——行内,一行显示 -->
                <span>产品</span>
                <ul class="dropdown-menu">
                    <li class="menu-item">子菜单1</li>
                    <div class="dropdown-divider"></div>
                    <li class="menu-item">子菜单2</li>
                </ul>
              </li>

              <li class="menu-item"><span>客户</span></li>
              <li class="menu-item"><span>渠道</span></li>
              <li class="menu-item"><span>订单</span></li>
              <li class="menu-item"><span>统计</span></li>
            </ol>
       
         
            <ol class="sub-nav-bar sub-nav-bar-right" style="margin-left: auto; margin-right: 1rem;">
              <li class="menu-item">
                <span>白月黑羽</span>
                <ul class="dropdown-menu">
                  <li class="menu-item">子菜单1</li>
                  <div class="dropdown-divider"></div>
                  <li class="menu-item">子菜单2</li>
                  <div class="dropdown-divider"></div>
                  <li class="menu-item">子菜单3</li>
                </ul>
              </li>
            </ol>
        
        </nav>

        <ul class="side-menu">
          <!-- 菜单头部 -->
          <li class="menu-header">操作菜单</li>
          <li class="menu-item">产品</li>
          <li class="menu-item">客户</li>
          <li class="menu-item menu-open">渠道
            <ul class="sub-menu">
              <li class="menu-item">子菜单1</li>
              <li class="menu-item">子菜单2</li>
            </ul>
          </li>
          <li class="menu-item menu-open">订单
            <ul class="sub-menu">
              <li class="menu-item">子菜单1</li>
              <li class="menu-item">子菜单2</li>
            </ul>
          </li>
          <li class="menu-item">统计</li>
        </ul>

        <main>正文</main>
        <div class="footer-left"></div>
        <footer>
          白月黑羽版权所有
          <br>
          <!-- 自己试在style里加style="padding:1rem;",注意一点:白月黑羽版权所有 是content,不是盒子-->
          <small>2020-2022 @copy rights reserved</small>
        </footer>
    </body>
</html>

点击隐藏显示子菜单

点击菜单项实现显示/隐藏

思路:

首先我怎么知道这个菜单被点击了—— 对多个对象注册点击事件;但问题是如果后面产生动态元素,那还要单独对它写注册事件

我们可以对整个页面document注册click事件,然后看消息源是否是导航栏或侧边栏里的菜单项产生的,是的话再对它进行后续的处理。

-------------------------------------------------------------------------------------------------------------------------

元素是否显示,看display属性值是否为none

<!DOCTYPE html>
<html lang="en">
    <head>
      <meta charset="utf-8">
      <title>药品销管</title>
        <style>

        .hidden{
          display:none !important;
        }

        /* 页面整体 */
        body{
          height: 100vh;
          max-width: 1250px;
          /* 上下设成0;左右均分 */
          margin: 0 auto;
          display: grid;
          /* 指定行的数量和高度 */
          grid-template-rows:  auto 1fr auto;
          /* 指定列的数量和宽度;右边占据所有剩余宽度 */
          grid-template-columns: minmax(15rem,20rem) 1fr;
        }    

        /* 一行一列:管理员操作 */
        .nav-logo{
          border-left: 1px solid #e5eaef;
          color:rgb(8, 96, 8);
          display:flex;
          /* flex布局,居中 */
          align-items: center;
          justify-content: center;
        }

        /* 整个导航栏 */
        nav{
          background-color: rgb(4, 115, 155);
          color: white;
          display: flex;
          flex-flow: row wrap;
          /* 保证不会挤到一起去,再小出现滚动条 */
          min-width: 30rem;
          /* 去掉点击后出现的"选中状态"*/
          user-select: none;
        }

        /* 导航栏包含所有菜单项的容器*/
        .sub-nav-bar{
          list-style-type: none;
          display:flex;
          flex-flow: row wrap;
          gap:2rem;
          align-items: center;
          justify-content: center;
          margin: 0;
        }

        /* 导航栏菜单项里的下拉菜单 */
        .dropdown-menu{
            position:absolute;
            list-style-type: none;
            background-color: white;
            color: #2e669f;
            /* 整体下移 */
            margin-top: .8rem;
            font-size: .85rem;
            padding-left: 0;
            width:10rem;
        }

        /* 导航栏里的所有单个菜单项 */
        /* 后代选择器:选中父元素"后代中"满足条件的元素 ;子代选择器:选择父元素"子代中"满足条件的元素*/
        .sub-nav-bar > .menu-item{
          /* 相对于该元素在文档流中的正常位置进行偏移定位 */
          position: relative;
          /* 上下为0,左右为.8rem ;但要注意:这里我只想设一级的子菜单产品那行,需要用子代选择器"->"*/
          padding: .8rem; 
        }

        /* 子代采用的是绝对定位,绝对定位相对于非静态定位(static)的父元素进行定位移动;
        绝对定位查找父级的方式:就近找定位的父级,如果逐层查找不到这样的父级,就以浏览器窗口为参照进行定位;
        希望子元素相对于父元素进行定位,又不希望父元素脱标 采用子绝父相(注意这个“.sub-nav-bar .menu-item”是相对定位;“.dropdown-menu”是绝对定位)*/
        .sub-nav-bar-right .dropdown-menu{
          /* 最终选择的元素是元素2 ,并且要求这个元素2是元素1的后代元素 ; 右对齐*/
          right:0;
        }

        /* 悬停高亮 */
        /* hover伪类选择器语法: 选择器:hover {css};选中鼠标悬停在元素上的状态,设置样式 */
        .sub-nav-bar .menu-item:hover{
          color:green;
          background-color: white;
        }

        .dropdown-menu .menu-item:hover{
          background-color: #e8f5e9;
        }

        /* 对于所有菜单项,希望光标变成手*/
        .menu-item{
            cursor: pointer;
        }
         
        /* 下拉菜单的每个菜单项 */
        .dropdown-menu .menu-item{
          /* 上下居中 margin: .6rem; 换成padding 因为背景色设置范围:有效区域包括这个元素的 内容区、padding部分、border部分。也就是包含块除了margin部分 */
          padding: .6rem;
        }

        /* 下拉菜单每个菜单项的分界线 */
        .dropdown-divider{
          height:0;
          /* 一条边 */
          border-top:1px solid #e8dcdc;
        }

        /* 侧边栏 */
        .side-menu{
          border-left: 1px solid #e5eaef;
          border-top: 1px solid #e5eaef;
          margin: 0;
          /* 文字不顶左角 */
          padding:1rem;
          list-style-type: none;
          /* 根字体的90% */
          font-size:.9rem;
          display:flex;
          /* 列排 */
          flex-direction: column;
          /*  gap:.2rem; flex布局列间距 */
          user-select: none;
        }

        /* 侧边栏的下拉菜单 */
        .sub-menu{
          list-style-type: none;
          display:flex;
          /* 列排 */
          flex-direction: column;
          /* gap: .5rem; */
          font-size: .85rem;
          padding:0 1rem;
        }

        /* 左侧菜单 菜单头 */
        .side-menu .menu-header{
          color:#837b70;
        }

        /* 左侧菜单 菜单项 */
        .side-menu .menu-item{
          color: #5e81a5;
          /* padding-left: 1rem; */
          /* 上 右 下 左 */
          padding: .5rem 0 .5rem 1rem;
          /* 上下.2rem 左右无 */
          margin: .2rem 0;
        }

        /* 悬停高亮 */
        .side-menu .menu-item:hover{
          background-color: #e8f5e9;
        }

        .sub-menu .menu-item:hover{
          background-color: #bce5bf;
        }

        /* 侧边栏展开的菜单项 */
        /* .menu-item.has-sub-menu交集选择器,是menu-item又是has-sub-menu的 */
        .side-menu .menu-item.has-sub-menu{
          color:#6b6464;
          border-left:1px solid green;
        }

        /* 界面主体元素 */
        main{
          background-color: #d0d0d1;
          /* 防止文字顶左角 */
          padding:1rem;
        }

        /* 第三行一列;页脚左侧容器 */
        .footer-left{
          border-left: 1px solid #e5eaef;
        }

        /* 页脚元素 */
        footer{
          background-color: #e5eaef;
          text-align: center;
          padding:1rem;
        }
        </style>


        <script>
          window.onload = function(){
            document.addEventListener('click',function(e){
              //思路:首先我们先判断直接触发事件的对象(e.target)是否为导航栏“带有下拉菜单”的菜单项,怎么判断呢?—— 看这个元素对象里的class属性是否包含hidden
              //对于这个触发对象有个问题:如果点的是li标签,可以判断class属性是否有hidden;但如果点的是span标签,也就是产品,他没有class属性,点了也没用不显示,如何解决这个问题呢?—— 我们可以采用closest()方法获取符合条件的最接近的上级元素(包括自身),那么这样无论点里点外都能追溯到<li class="menu-item">这个元素, 如果没有匹配的元素返回的就是null
             
              //导航栏菜单点击处理
              let NavMenuItem = e.target.closest('.sub-nav-bar > .menu-item')
              //点击的是导航栏菜单项
              if (NavMenuItem){
                //<li class="menu-item">里面有hidden把hidden去掉;没有加上
                //有的话选出来的是  <ul class="dropdown-menu hidden"> ; 同样的没找到符合条件的元素返回null
                let subMenu = NavMenuItem.querySelector('.dropdown-menu')
                //如果有下拉子菜单
                if(subMenu){
                  if (subMenu.classList.contains('hidden')){
                    subMenu.classList.remove("hidden");
                  }
                  else{
                    subMenu.classList.add("hidden");
                  }
                }
              }

              //侧边栏菜单点击处理
              let sideMenuItem = e.target.closest('.side-menu > .menu-item')
              //这里有个问题:点导航栏的下拉菜单我们可以接受点击子菜单然后缩起来;但对于侧边栏我们并不希望这样(子菜单往上找也会追溯到<li class="menu-item">)——  那么我们需要加一个判断条件:如果当前点击的这个元素祖先中有sub-menu就不执行下面内容
              //点击的是侧边栏菜单项,并且不是点击子菜单
              if (sideMenuItem){
                //有的话选出来的是  <ul class="dropdown-menu hidden"> ; 同样的没找到符合条件的元素返回null
                let subMenu = sideMenuItem.querySelector('.sub-menu')
                //如果有下拉子菜单
                if(subMenu && !e.target.closest('.sub-menu')){
                  if (subMenu.classList.contains('hidden')){
                    subMenu.classList.remove("hidden");
                  }
                  else{
                    subMenu.classList.add("hidden");
                  }
                }
              }

            })
          }
        </script>

    </head>

    <body>
        <div class="nav-logo">管理员操作</div> 
        <nav>

            <ol class="sub-nav-bar">
              <li class="menu-item">
                <!-- div ——块级,新开一行,水平方向占满父级 ;span ——行内,一行显示 -->
                <span>产品</span>
                <ul class="dropdown-menu hidden">
                    <li class="menu-item">子菜单1</li>
                    <div class="dropdown-divider"></div>
                    <li class="menu-item">子菜单2</li>
                </ul>
              </li>

              <li class="menu-item"><span>客户</span></li>
              <li class="menu-item"><span>渠道</span></li>
              <li class="menu-item"><span>订单</span></li>
              <li class="menu-item"><span>统计</span></li>
            </ol>
       
         
            <ol class="sub-nav-bar sub-nav-bar-right" style="margin-left: auto; margin-right: 1rem;">
              <li class="menu-item">
                <span>白月黑羽</span>
                <ul class="dropdown-menu hidden">
                  <li class="menu-item">子菜单1</li>
                  <div class="dropdown-divider"></div>
                  <li class="menu-item">子菜单2</li>
                  <div class="dropdown-divider"></div>
                  <li class="menu-item">子菜单3</li>
                </ul>
              </li>
            </ol>
        
        </nav>

        <ul class="side-menu">
          <!-- 菜单头部 -->
          <li class="menu-header">操作菜单</li>
          <li class="menu-item">产品</li>
          <li class="menu-item">客户</li>
          <li class="menu-item has-sub-menu">渠道
            <ul class="sub-menu hidden">
              <li class="menu-item">子菜单1</li>
              <li class="menu-item">子菜单2</li>
            </ul>
          </li>
          <li class="menu-item has-sub-menu">订单
            <ul class="sub-menu hidden">
              <li class="menu-item">子菜单1</li>
              <li class="menu-item">子菜单2</li>
            </ul>
          </li>
          <li class="menu-item">统计</li>
        </ul>

        <main>正文</main>
        <div class="footer-left"></div>
        <footer>
          白月黑羽版权所有
          <br>
          <!-- 自己试在style里加style="padding:1rem;",注意一点:白月黑羽版权所有 是content,不是盒子-->
          <small>2020-2022 @copy rights reserved</small>
        </footer>
    </body>

</html>

列出系统中的客户

<!DOCTYPE html>
<html lang="en">
    <head>
      <meta charset="utf-8">
      <title>药品销管</title>
        <style>

        .hidden{
          display:none !important;
        }

        /* 页面整体 */
        body{
          height: 100vh;
          max-width: 1250px;
          /* 上下设成0;左右均分 */
          margin: 0 auto;
          display: grid;
          /* 指定行的数量和高度 */
          grid-template-rows:  auto 1fr auto;
          /* 指定列的数量和宽度;右边占据所有剩余宽度 */
          grid-template-columns: minmax(15rem,20rem) 1fr;
        }    

        /* 一行一列:管理员操作 */
        .nav-logo{
          border-left: 1px solid #e5eaef;
          color:rgb(8, 96, 8);
          display:flex;
          /* flex布局,居中 */
          align-items: center;
          justify-content: center;
        }

        /* 整个导航栏 */
        nav{
          background-color: rgb(4, 115, 155);
          color: white;
          display: flex;
          flex-flow: row wrap;
          /* 保证不会挤到一起去,再小出现滚动条 */
          min-width: 30rem;
          /* 去掉点击后出现的"选中状态"*/
          user-select: none;
        }

        /* 导航栏包含所有菜单项的容器*/
        .sub-nav-bar{
          list-style-type: none;
          display:flex;
          flex-flow: row wrap;
          gap:2rem;
          align-items: center;
          justify-content: center;
          margin: 0;
        }

        /* 导航栏菜单项里的下拉菜单 */
        .dropdown-menu{
            position:absolute;
            list-style-type: none;
            background-color: white;
            color: #2e669f;
            /* 整体下移 */
            margin-top: .8rem;
            font-size: .85rem;
            padding-left: 0;
            width:10rem;
        }

        /* 导航栏里的所有单个菜单项 */
        /* 后代选择器:选中父元素"后代中"满足条件的元素 ;子代选择器:选择父元素"子代中"满足条件的元素*/
        .sub-nav-bar > .menu-item{
          /* 相对于该元素在文档流中的正常位置进行偏移定位 */
          position: relative;
          /* 上下为0,左右为.8rem ;但要注意:这里我只想设一级的子菜单产品那行,需要用子代选择器"->"*/
          padding: .8rem; 
        }

        /* 子代采用的是绝对定位,绝对定位相对于非静态定位(static)的父元素进行定位移动;
        绝对定位查找父级的方式:就近找定位的父级,如果逐层查找不到这样的父级,就以浏览器窗口为参照进行定位;
        希望子元素相对于父元素进行定位,又不希望父元素脱标 采用子绝父相(注意这个“.sub-nav-bar .menu-item”是相对定位;“.dropdown-menu”是绝对定位)*/
        .sub-nav-bar-right .dropdown-menu{
          /* 最终选择的元素是元素2 ,并且要求这个元素2是元素1的后代元素 ; 右对齐*/
          right:0;
        }

        /* 悬停高亮 */
        /* hover伪类选择器语法: 选择器:hover {css};选中鼠标悬停在元素上的状态,设置样式 */
        .sub-nav-bar .menu-item:hover{
          color:green;
          background-color: white;
        }

        .dropdown-menu .menu-item:hover{
          background-color: #e8f5e9;
        }

        /* 对于所有菜单项,希望光标变成手*/
        .menu-item{
            cursor: pointer;
        }
         
        /* 下拉菜单的每个菜单项 */
        .dropdown-menu .menu-item{
          /* 上下居中 margin: .6rem; 换成padding 因为背景色设置范围:有效区域包括这个元素的 内容区、padding部分、border部分。也就是包含块除了margin部分 */
          padding: .6rem;
        }

        /* 下拉菜单每个菜单项的分界线 */
        .dropdown-divider{
          height:0;
          /* 一条边 */
          border-top:1px solid #e8dcdc;
        }

        /* 侧边栏 */
        .side-menu{
          border-left: 1px solid #e5eaef;
          border-top: 1px solid #e5eaef;
          margin: 0;
          /* 文字不顶左角 */
          padding:1rem;
          list-style-type: none;
          /* 根字体的90% */
          font-size:.9rem;
          display:flex;
          /* 列排 */
          flex-direction: column;
          /*  gap:.2rem; flex布局列间距 */
          user-select: none;
        }

        /* 侧边栏的下拉菜单 */
        .sub-menu{
          list-style-type: none;
          display:flex;
          /* 列排 */
          flex-direction: column;
          /* gap: .5rem; */
          font-size: .85rem;
          padding:0 1rem;
        }

        /* 左侧菜单 菜单头 */
        .side-menu .menu-header{
          color:#837b70;
        }

        /* 左侧菜单 菜单项 */
        .side-menu .menu-item{
          color: #5e81a5;
          /* padding-left: 1rem; */
          /* 上 右 下 左 */
          padding: .5rem 0 .5rem 1rem;
          /* 上下.2rem 左右无 */
          margin: .2rem 0;
        }

        /* 悬停高亮 */
        .side-menu .menu-item:hover{
          background-color: #e8f5e9;
        }

        .sub-menu .menu-item:hover{
          background-color: #bce5bf;
        }

        /* 侧边栏展开的菜单项 */
        /* .menu-item.has-sub-menu交集选择器,是menu-item又是has-sub-menu的 */
        .side-menu .menu-item.has-sub-menu{
          color:#6b6464;
          border-left:1px solid green;
        }

        /* 界面主体元素 */
        main{
          background-color: #fafafa;
          /* 防止文字顶左角 */
          padding:1rem;
        }

        /* 第三行一列;页脚左侧容器 */
        .footer-left{
          border-left: 1px solid #e5eaef;
        }

        /* 页脚元素 */
        footer{
          background-color: #e6e6e6;
          text-align: center;
          padding:1rem;
        }

        /* 正文 */
        .result-list{
          display:flex;
          flex-direction: column;
          gap:1rem;

          /* 主轴对齐 */
          justify-content: center;
          /* 从轴对齐 */
          align-items: center;   
        }

        .result-list-item{
          border:1px solid rgb(170, 177, 170);
          padding: 0 1rem;
          width: 90%;
        }

        .field-name{
          width: 5rem;
          /* 由于它是个<span>标签,行内元素,宽高不生效;把它转成行内块元素“一行显示多个,宽高生效” */
          display: inline-block;
          color: darkgreen;
        }

        </style>

        <script src="https://cdn.jsdelivr.net/npm/jquery/dist/jquery.min.js"></script>

        <script>
          //注册初始事件处理
          function registerEventListeners(){
            document.addEventListener('click',function(e){
              //思路:首先我们先判断直接触发事件的对象(e.target)是否为导航栏“带有下拉菜单”的菜单项,怎么判断呢?—— 看这个元素对象里的class属性是否包含hidden
              //对于这个触发对象有个问题:如果点的是li标签,可以判断class属性是否有hidden;但如果点的是span标签,也就是产品,他没有class属性,点了也没用不显示,如何解决这个问题呢?—— 我们可以采用closest()方法获取符合条件的最接近的上级元素(包括自身),那么这样无论点里点外都能追溯到<li class="menu-item">这个元素, 如果没有匹配的元素返回的就是null
             
              //导航栏菜单点击处理
              let NavMenuItem = e.target.closest('.sub-nav-bar > .menu-item')
              //点击的是导航栏菜单项
              if (NavMenuItem){
                //<li class="menu-item">里面有hidden把hidden去掉;没有加上
                //有的话选出来的是  <ul class="dropdown-menu hidden"> ; 同样的没找到符合条件的元素返回null
                let subMenu = NavMenuItem.querySelector('.dropdown-menu')
                //如果有下拉子菜单
                if(subMenu){
                  if (subMenu.classList.contains('hidden')){
                    subMenu.classList.remove("hidden");
                  }
                  else{
                    subMenu.classList.add("hidden");
                  }
                }
              }

              //侧边栏菜单点击处理
              let sideMenuItem = e.target.closest('.side-menu > .menu-item')
              //这里有个问题:点导航栏的下拉菜单我们可以接受点击子菜单然后缩起来;但对于侧边栏我们并不希望这样(子菜单往上找也会追溯到<li class="menu-item">)——  那么我们需要加一个判断条件:如果当前点击的这个元素祖先中有sub-menu就不执行下面内容
              //点击的是侧边栏菜单项,并且不是点击子菜单
              if (sideMenuItem){
                //有的话选出来的是  <ul class="dropdown-menu hidden"> ; 同样的没找到符合条件的元素返回null
                let subMenu = sideMenuItem.querySelector('.sub-menu')
                //如果有下拉子菜单
                if(subMenu && !e.target.closest('.sub-menu')){
                  if (subMenu.classList.contains('hidden')){
                    subMenu.classList.remove("hidden");
                  }
                  else{
                    subMenu.classList.add("hidden");
                  }
                }
              }
            })
          }
          //看接口文档,列出所有客户 请求参数http请求消息url中需要携带的参数4个
          function getCustomerList(pagenum=1,pagesize=5,keywords=''){

            //在发出请求之前,先把结果清空(点击下一页)
            document.querySelector('.result-list').innerHTML=''
            
            //获取响应内容
            $.ajax({   
                type: 'GET', 
                // http协议中,url参数格式都是urlencode格式
                url: `/api/mgr/customers?action=list_customer&pagenum=${pagenum}&pagesize=${pagesize}&keywords=${keywords}`,    
                
                //jQuery解析响应消息体
                success: function(data, textStatus, xhr) { 
                    if(data.ret !== 0){
                        alert('操作失败: ' + data.msg)
                        return;
                    }

                    for(let item of data.retlist){
                      // 每一项 ,加<p>是为了换行,让它独占一行 ; 前面加一个说明,还要在一行显示,用<span>;还需要指定样式,加个class
                      let pEle = `<div class='result-list-item'>
                        <p><span class='field-name'>客户名</span><span>${item.name}</span></p>
                        <p><span class='field-name'>地址</span><span>${item.address}</span></p>
                        <p><span class='field-name'>电话</span><span>${item.phonenumber}</span></p></div>`
                      document.querySelector('.result-list').insertAdjacentHTML("beforeend",pEle)
                    }
                },
                //错误
                error:function (xhr, textStatus, errorThrown ){
                    console.error(`${xhr.status} \n${textStatus} \n${errorThrown }`)
                }
            })
          }

          window.onload = function(){
            registerEventListeners();
            getCustomerList();//获取客户列表
          }

        </script>

    </head>

    <body>
        <div class="nav-logo">管理员操作</div> 
        <nav>
            <ol class="sub-nav-bar">
              <li class="menu-item">
                <!-- div ——块级,新开一行,水平方向占满父级 ;span ——行内,一行显示 -->
                <span>产品</span>
                <ul class="dropdown-menu hidden">
                    <li class="menu-item">子菜单1</li>
                    <div class="dropdown-divider"></div>
                    <li class="menu-item">子菜单2</li>
                </ul>
              </li>

              <li class="menu-item"><span>客户</span></li>
              <li class="menu-item"><span>渠道</span></li>
              <li class="menu-item"><span>订单</span></li>
              <li class="menu-item"><span>统计</span></li>
            </ol>
       
         
            <ol class="sub-nav-bar sub-nav-bar-right" style="margin-left: auto; margin-right: 1rem;">
              <li class="menu-item">
                <span>白月黑羽</span>
                <ul class="dropdown-menu hidden">
                  <li class="menu-item">子菜单1</li>
                  <div class="dropdown-divider"></div>
                  <li class="menu-item">子菜单2</li>
                  <div class="dropdown-divider"></div>
                  <li class="menu-item">子菜单3</li>
                </ul>
              </li>
            </ol>
        
        </nav>

        <ul class="side-menu">
          <!-- 菜单头部 -->
          <li class="menu-header">操作菜单</li>
          <li class="menu-item">产品</li>
          <li class="menu-item">客户</li>
          <li class="menu-item has-sub-menu">渠道
            <ul class="sub-menu hidden">
              <li class="menu-item">子菜单1</li>
              <li class="menu-item">子菜单2</li>
            </ul>
          </li>
          <li class="menu-item has-sub-menu">订单
            <ul class="sub-menu hidden">
              <li class="menu-item">子菜单1</li>
              <li class="menu-item">子菜单2</li>
            </ul>
          </li>
          <li class="menu-item">统计</li>
        </ul>

        <main>
          <!-- 正文 -->
          <div class="result-list"></div>
        </main>
        <div class="footer-left"></div>
        <footer>
          白月黑羽版权所有
          <br>
          <!-- 自己试在style里加style="padding:1rem;",注意一点:白月黑羽版权所有 是content,不是盒子-->
          <small>2020-2022 @copy rights reserved</small>
        </footer>
    </body>

</html>

分隔代码:

hyms.html

<!DOCTYPE html>
<html lang="en">
    <head>
      <meta charset="utf-8">
      <title>药品销管</title>

        <!--  外联式  -->
        <link rel="stylesheet" href="endhyms.css">

        <script src="https://cdn.jsdelivr.net/npm/jquery/dist/jquery.min.js"></script>

        <script src="endhyms.js"></script>

    </head>

    <body>
        <div class="nav-logo">管理员操作</div> 
        <nav>
            <ol class="sub-nav-bar">
              <li class="menu-item">
                <!-- div ——块级,新开一行,水平方向占满父级 ;span ——行内,一行显示 -->
                <span>产品</span>
                <ul class="dropdown-menu hidden">
                    <li class="menu-item">子菜单1</li>
                    <div class="dropdown-divider"></div>
                    <li class="menu-item">子菜单2</li>
                </ul>
              </li>

              <li class="menu-item"><span>客户</span></li>
              <li class="menu-item"><span>渠道</span></li>
              <li class="menu-item"><span>订单</span></li>
              <li class="menu-item"><span>统计</span></li>
            </ol>
       
         
            <ol class="sub-nav-bar sub-nav-bar-right" style="margin-left: auto; margin-right: 1rem;">
              <li class="menu-item">
                <span>白月黑羽</span>
                <ul class="dropdown-menu hidden">
                  <li class="menu-item">子菜单1</li>
                  <div class="dropdown-divider"></div>
                  <li class="menu-item">子菜单2</li>
                  <div class="dropdown-divider"></div>
                  <li class="menu-item">子菜单3</li>
                </ul>
              </li>
            </ol>
        
        </nav>

        <ul class="side-menu">
          <!-- 菜单头部 -->
          <li class="menu-header">操作菜单</li>
          <li class="menu-item">产品</li>
          <li class="menu-item">客户</li>
          <li class="menu-item has-sub-menu">渠道
            <ul class="sub-menu hidden">
              <li class="menu-item">子菜单1</li>
              <li class="menu-item">子菜单2</li>
            </ul>
          </li>
          <li class="menu-item has-sub-menu">订单
            <ul class="sub-menu hidden">
              <li class="menu-item">子菜单1</li>
              <li class="menu-item">子菜单2</li>
            </ul>
          </li>
          <li class="menu-item">统计</li>
        </ul>

        <main>
          <!-- 正文 -->
          <div class="result-list"></div>
        </main>
        <div class="footer-left"></div>
        <footer>
          白月黑羽版权所有
          <br>
          <!-- 自己试在style里加style="padding:1rem;",注意一点:白月黑羽版权所有 是content,不是盒子-->
          <small>2020-2022 @copy rights reserved</small>
        </footer>
    </body>

</html>

hyms.css

.hidden{
    display:none !important;
  }

  /* 页面整体 */
  body{
    height: 100vh;
    max-width: 1250px;
    /* 上下设成0;左右均分 */
    margin: 0 auto;
    display: grid;
    /* 指定行的数量和高度 */
    grid-template-rows:  auto 1fr auto;
    /* 指定列的数量和宽度;右边占据所有剩余宽度 */
    grid-template-columns: minmax(15rem,20rem) 1fr;
  }    

  /* 一行一列:管理员操作 */
  .nav-logo{
    border-left: 1px solid #e5eaef;
    color:rgb(8, 96, 8);
    display:flex;
    /* flex布局,居中 */
    align-items: center;
    justify-content: center;
  }

  /* 整个导航栏 */
  nav{
    background-color: rgb(4, 115, 155);
    color: white;
    display: flex;
    flex-flow: row wrap;
    /* 保证不会挤到一起去,再小出现滚动条 */
    min-width: 30rem;
    /* 去掉点击后出现的"选中状态"*/
    user-select: none;
  }

  /* 导航栏包含所有菜单项的容器*/
  .sub-nav-bar{
    list-style-type: none;
    display:flex;
    flex-flow: row wrap;
    gap:2rem;
    align-items: center;
    justify-content: center;
    margin: 0;
  }

  /* 导航栏菜单项里的下拉菜单 */
  .dropdown-menu{
      position:absolute;
      list-style-type: none;
      background-color: white;
      color: #2e669f;
      /* 整体下移 */
      margin-top: .8rem;
      font-size: .85rem;
      padding-left: 0;
      width:10rem;
  }

  /* 导航栏里的所有单个菜单项 */
  /* 后代选择器:选中父元素"后代中"满足条件的元素 ;子代选择器:选择父元素"子代中"满足条件的元素*/
  .sub-nav-bar > .menu-item{
    /* 相对于该元素在文档流中的正常位置进行偏移定位 */
    position: relative;
    /* 上下为0,左右为.8rem ;但要注意:这里我只想设一级的子菜单产品那行,需要用子代选择器"->"*/
    padding: .8rem; 
  }

  /* 子代采用的是绝对定位,绝对定位相对于非静态定位(static)的父元素进行定位移动;
  绝对定位查找父级的方式:就近找定位的父级,如果逐层查找不到这样的父级,就以浏览器窗口为参照进行定位;
  希望子元素相对于父元素进行定位,又不希望父元素脱标 采用子绝父相(注意这个“.sub-nav-bar .menu-item”是相对定位;“.dropdown-menu”是绝对定位)*/
  .sub-nav-bar-right .dropdown-menu{
    /* 最终选择的元素是元素2 ,并且要求这个元素2是元素1的后代元素 ; 右对齐*/
    right:0;
  }

  /* 悬停高亮 */
  /* hover伪类选择器语法: 选择器:hover {css};选中鼠标悬停在元素上的状态,设置样式 */
  .sub-nav-bar .menu-item:hover{
    color:green;
    background-color: white;
  }

  .dropdown-menu .menu-item:hover{
    background-color: #e8f5e9;
  }

  /* 对于所有菜单项,希望光标变成手*/
  .menu-item{
      cursor: pointer;
  }
   
  /* 下拉菜单的每个菜单项 */
  .dropdown-menu .menu-item{
    /* 上下居中 margin: .6rem; 换成padding 因为背景色设置范围:有效区域包括这个元素的 内容区、padding部分、border部分。也就是包含块除了margin部分 */
    padding: .6rem;
  }

  /* 下拉菜单每个菜单项的分界线 */
  .dropdown-divider{
    height:0;
    /* 一条边 */
    border-top:1px solid #e8dcdc;
  }

  /* 侧边栏 */
  .side-menu{
    border-left: 1px solid #e5eaef;
    border-top: 1px solid #e5eaef;
    margin: 0;
    /* 文字不顶左角 */
    padding:1rem;
    list-style-type: none;
    /* 根字体的90% */
    font-size:.9rem;
    display:flex;
    /* 列排 */
    flex-direction: column;
    /*  gap:.2rem; flex布局列间距 */
    user-select: none;
  }

  /* 侧边栏的下拉菜单 */
  .sub-menu{
    list-style-type: none;
    display:flex;
    /* 列排 */
    flex-direction: column;
    /* gap: .5rem; */
    font-size: .85rem;
    padding:0 1rem;
  }

  /* 左侧菜单 菜单头 */
  .side-menu .menu-header{
    color:#837b70;
  }

  /* 左侧菜单 菜单项 */
  .side-menu .menu-item{
    color: #5e81a5;
    /* padding-left: 1rem; */
    /* 上 右 下 左 */
    padding: .5rem 0 .5rem 1rem;
    /* 上下.2rem 左右无 */
    margin: .2rem 0;
  }

  /* 悬停高亮 */
  .side-menu .menu-item:hover{
    background-color: #e8f5e9;
  }

  .sub-menu .menu-item:hover{
    background-color: #bce5bf;
  }

  /* 侧边栏展开的菜单项 */
  /* .menu-item.has-sub-menu交集选择器,是menu-item又是has-sub-menu的 */
  .side-menu .menu-item.has-sub-menu{
    color:#6b6464;
    border-left:1px solid green;
  }

  /* 界面主体元素 */
  main{
    background-color: #fafafa;
    /* 防止文字顶左角 */
    padding:1rem;
  }

  /* 第三行一列;页脚左侧容器 */
  .footer-left{
    border-left: 1px solid #e5eaef;
  }

  /* 页脚元素 */
  footer{
    background-color: #e6e6e6;
    text-align: center;
    padding:1rem;
  }

  /* 正文 */
  .result-list{
    display:flex;
    flex-direction: column;
    gap:1rem;

    /* 主轴对齐 */
    justify-content: center;
    /* 从轴对齐 */
    align-items: center;   
  }

  .result-list-item{
    border:1px solid rgb(170, 177, 170);
    padding: 0 1rem;
    width: 90%;
  }

  .field-name{
    width: 5rem;
    /* 由于它是个<span>标签,行内元素,宽高不生效;把它转成行内块元素“一行显示多个,宽高生效” */
    display: inline-block;
    color: darkgreen;
  }

hyms.js

//注册初始事件处理
function registerEventListeners(){
document.addEventListener('click',function(e){
    //思路:首先我们先判断直接触发事件的对象(e.target)是否为导航栏“带有下拉菜单”的菜单项,怎么判断呢?—— 看这个元素对象里的class属性是否包含hidden
    //对于这个触发对象有个问题:如果点的是li标签,可以判断class属性是否有hidden;但如果点的是span标签,也就是产品,他没有class属性,点了也没用不显示,如何解决这个问题呢?—— 我们可以采用closest()方法获取符合条件的最接近的上级元素(包括自身),那么这样无论点里点外都能追溯到<li class="menu-item">这个元素, 如果没有匹配的元素返回的就是null

    //导航栏菜单点击处理
    let NavMenuItem = e.target.closest('.sub-nav-bar > .menu-item')
    //点击的是导航栏菜单项
    if (NavMenuItem){
        //<li class="menu-item">里面有hidden把hidden去掉;没有加上
        //有的话选出来的是  <ul class="dropdown-menu hidden"> ; 同样的没找到符合条件的元素返回null
        let subMenu = NavMenuItem.querySelector('.dropdown-menu')
        //如果有下拉子菜单
        if(subMenu){
            if (subMenu.classList.contains('hidden')){
                subMenu.classList.remove("hidden");
            }
            else{
                subMenu.classList.add("hidden");
            }
        }
    }

//侧边栏菜单点击处理
let sideMenuItem = e.target.closest('.side-menu > .menu-item')
//这里有个问题:点导航栏的下拉菜单我们可以接受点击子菜单然后缩起来;但对于侧边栏我们并不希望这样(子菜单往上找也会追溯到<li class="menu-item">)——  那么我们需要加一个判断条件:如果当前点击的这个元素祖先中有sub-menu就不执行下面内容
//点击的是侧边栏菜单项,并且不是点击子菜单
if (sideMenuItem){
//有的话选出来的是  <ul class="dropdown-menu hidden"> ; 同样的没找到符合条件的元素返回null
    let subMenu = sideMenuItem.querySelector('.sub-menu')
    //如果有下拉子菜单
    if(subMenu && !e.target.closest('.sub-menu')){
        if (subMenu.classList.contains('hidden')){
            subMenu.classList.remove("hidden");
        }
        else{
            subMenu.classList.add("hidden");
        }
    }
}

})
}

//看接口文档,列出所有客户 请求参数http请求消息url中需要携带的参数4个
function getCustomerList(pagenum=1,pagesize=5,keywords=''){

//在发出请求之前,先把结果清空(点击下一页)
document.querySelector('.result-list').innerHTML=''

//获取响应内容
$.ajax({   
    type: 'GET', 
    // http协议中,url参数格式都是urlencode格式
    url: `/api/mgr/customers?action=list_customer&pagenum=${pagenum}&pagesize=${pagesize}&keywords=${keywords}`,    

    //jQuery解析响应消息体
    success: function(data, textStatus, xhr) { 
        if(data.ret !== 0){
            alert('操作失败: ' + data.msg)
            return;
        }

        for(let item of data.retlist){
        // 每一项 ,加<p>是为了换行,让它独占一行 ; 前面加一个说明,还要在一行显示,用<span>;还需要指定样式,加个class
        let pEle = `<div class='result-list-item'>
            <p><span class='field-name'>客户名</span><span>${item.name}</span></p>
            <p><span class='field-name'>地址</span><span>${item.address}</span></p>
            <p><span class='field-name'>电话</span><span>${item.phonenumber}</span></p></div>`
        document.querySelector('.result-list').insertAdjacentHTML("beforeend",pEle)
        }
    },

    //错误
    error:function (xhr, textStatus, errorThrown ){
        console.error(`${xhr.status} \n${textStatus} \n${errorThrown }`)
    }
})

}

window.onload = function(){
    registerEventListeners();
    getCustomerList();//获取客户列表
}

添加客户

hyms.html
<!DOCTYPE html>
<html lang="en">
    <head>
      <meta charset="utf-8">
      <title>药品销管</title>

        <!--  外联式  -->
        <link rel="stylesheet" href="endhyms.css">

        <script src="https://cdn.jsdelivr.net/npm/jquery/dist/jquery.min.js"></script>

        <script src="endhyms.js"></script>

    </head>

    <body>
        <div class="nav-logo">管理员操作</div> 
        <nav>
            <ol class="sub-nav-bar">
              <li class="menu-item">
                <!-- div ——块级,新开一行,水平方向占满父级 ;span ——行内,一行显示 -->
                <span>产品</span>
                <ul class="dropdown-menu hidden">
                    <li class="menu-item">子菜单1</li>
                    <div class="dropdown-divider"></div>
                    <li class="menu-item">子菜单2</li>
                </ul>
              </li>

              <li class="menu-item"><span>客户</span></li>
              <li class="menu-item"><span>渠道</span></li>
              <li class="menu-item"><span>订单</span></li>
              <li class="menu-item"><span>统计</span></li>
            </ol>
       
         
            <ol class="sub-nav-bar sub-nav-bar-right" style="margin-left: auto; margin-right: 1rem;">
              <li class="menu-item">
                <span>白月黑羽</span>
                <ul class="dropdown-menu hidden">
                  <li class="menu-item">子菜单1</li>
                  <div class="dropdown-divider"></div>
                  <li class="menu-item">子菜单2</li>
                  <div class="dropdown-divider"></div>
                  <li class="menu-item">子菜单3</li>
                </ul>
              </li>
            </ol>
        
        </nav>

        <ul class="side-menu">
          <!-- 菜单头部 -->
          <li class="menu-header">操作菜单</li>
          <li class="menu-item">产品</li>
          <li class="menu-item">客户</li>
          <li class="menu-item has-sub-menu">渠道
            <ul class="sub-menu hidden">
              <li class="menu-item">子菜单1</li>
              <li class="menu-item">子菜单2</li>
            </ul>
          </li>
          <li class="menu-item has-sub-menu">订单
            <ul class="sub-menu hidden">
              <li class="menu-item">子菜单1</li>
              <li class="menu-item">子菜单2</li>
            </ul>
          </li>
          <li class="menu-item">统计</li>
        </ul>

        <main>
          <!-- 正文 -->
          <div class="add-one-area">
            <button id='add-one-btn'>添加</button>
            
            <div class="add-one-form hidden">
                <p>
                    <span class='field-name'>客户名</span>
                    <input type="text" id="customer-name" class="input-l"></input>
                </p>

                <p>
                    <span class='field-name'>电话</span>
                    <input type="text" id="customer-phone" class="input-l"></input>
                </p>

                <p>
                    <span class='field-name'>地址</span>
                    <input type="text" id="customer-addr" class="input-xl"></input>
                </p>

                <div class="add-one-submit-btn-div">
                    <button id='add-one-submit-btn'>确定</button>
                </div>
                
            </div>

            

          </div>


          <div class="result-list"></div>
        </main>
        <div class="footer-left"></div>
        <footer>
          白月黑羽版权所有
          <br>
          <!-- 自己试在style里加style="padding:1rem;",注意一点:白月黑羽版权所有 是content,不是盒子-->
          <small>2020-2022 @copy rights reserved</small>
        </footer>
    </body>

</html>
hyms.css
.hidden{
    display:none !important;
  }

  /* 页面整体 */
  body{
    height: 100vh;
    max-width: 1250px;
    /* 上下设成0;左右均分 */
    margin: 0 auto;
    display: grid;
    /* 指定行的数量和高度 */
    grid-template-rows:  auto 1fr auto;
    /* 指定列的数量和宽度;右边占据所有剩余宽度 */
    grid-template-columns: minmax(15rem,20rem) 1fr;
  }    

  /* 一行一列:管理员操作 */
  .nav-logo{
    border-left: 1px solid #e5eaef;
    color:rgb(8, 96, 8);
    display:flex;
    /* flex布局,居中 */
    align-items: center;
    justify-content: center;
  }

  /* 整个导航栏 */
  nav{
    background-color: rgb(4, 115, 155);
    color: white;
    display: flex;
    flex-flow: row wrap;
    /* 保证不会挤到一起去,再小出现滚动条 */
    min-width: 30rem;
    /* 去掉点击后出现的"选中状态"*/
    user-select: none;
  }

  /* 导航栏包含所有菜单项的容器*/
  .sub-nav-bar{
    list-style-type: none;
    display:flex;
    flex-flow: row wrap;
    gap:2rem;
    align-items: center;
    justify-content: center;
    margin: 0;
  }

  /* 导航栏菜单项里的下拉菜单 */
  .dropdown-menu{
      position:absolute;
      list-style-type: none;
      background-color: white;
      color: #2e669f;
      /* 整体下移 */
      margin-top: .8rem;
      font-size: .85rem;
      padding-left: 0;
      width:10rem;
  }

  /* 导航栏里的所有单个菜单项 */
  /* 后代选择器:选中父元素"后代中"满足条件的元素 ;子代选择器:选择父元素"子代中"满足条件的元素*/
  .sub-nav-bar > .menu-item{
    /* 相对于该元素在文档流中的正常位置进行偏移定位 */
    position: relative;
    /* 上下为0,左右为.8rem ;但要注意:这里我只想设一级的子菜单产品那行,需要用子代选择器"->"*/
    padding: .8rem; 
  }

  /* 子代采用的是绝对定位,绝对定位相对于非静态定位(static)的父元素进行定位移动;
  绝对定位查找父级的方式:就近找定位的父级,如果逐层查找不到这样的父级,就以浏览器窗口为参照进行定位;
  希望子元素相对于父元素进行定位,又不希望父元素脱标 采用子绝父相(注意这个“.sub-nav-bar .menu-item”是相对定位;“.dropdown-menu”是绝对定位)*/
  .sub-nav-bar-right .dropdown-menu{
    /* 最终选择的元素是元素2 ,并且要求这个元素2是元素1的后代元素 ; 右对齐*/
    right:0;
  }

  /* 悬停高亮 */
  /* hover伪类选择器语法: 选择器:hover {css};选中鼠标悬停在元素上的状态,设置样式 */
  .sub-nav-bar .menu-item:hover{
    color:green;
    background-color: white;
  }

  .dropdown-menu .menu-item:hover{
    background-color: #e8f5e9;
  }

  /* 对于所有菜单项,希望光标变成手*/
  .menu-item{
      cursor: pointer;
  }
   
  /* 下拉菜单的每个菜单项 */
  .dropdown-menu .menu-item{
    /* 上下居中 margin: .6rem; 换成padding 因为背景色设置范围:有效区域包括这个元素的 内容区、padding部分、border部分。也就是包含块除了margin部分 */
    padding: .6rem;
  }

  /* 下拉菜单每个菜单项的分界线 */
  .dropdown-divider{
    height:0;
    /* 一条边 */
    border-top:1px solid #e8dcdc;
  }

  /* 侧边栏 */
  .side-menu{
    border-left: 1px solid #e5eaef;
    border-top: 1px solid #e5eaef;
    margin: 0;
    /* 文字不顶左角 */
    padding:1rem;
    list-style-type: none;
    /* 根字体的90% */
    font-size:.9rem;
    display:flex;
    /* 列排 */
    flex-direction: column;
    /*  gap:.2rem; flex布局列间距 */
    user-select: none;
  }

  /* 侧边栏的下拉菜单 */
  .sub-menu{
    list-style-type: none;
    display:flex;
    /* 列排 */
    flex-direction: column;
    /* gap: .5rem; */
    font-size: .85rem;
    padding:0 1rem;
  }

  /* 左侧菜单 菜单头 */
  .side-menu .menu-header{
    color:#837b70;
  }

  /* 左侧菜单 菜单项 */
  .side-menu .menu-item{
    color: #5e81a5;
    /* padding-left: 1rem; */
    /* 上 右 下 左 */
    padding: .5rem 0 .5rem 1rem;
    /* 上下.2rem 左右无 */
    margin: .2rem 0;
  }

  /* 悬停高亮 */
  .side-menu .menu-item:hover{
    background-color: #e8f5e9;
  }

  .sub-menu .menu-item:hover{
    background-color: #bce5bf;
  }

  /* 侧边栏展开的菜单项 */
  /* .menu-item.has-sub-menu交集选择器,是menu-item又是has-sub-menu的 */
  .side-menu .menu-item.has-sub-menu{
    color:#6b6464;
    border-left:1px solid green;
  }

  /* 界面主体元素 */
  main{
    background-color: #fafafa;
    /* 防止文字顶左角 */
    padding:1rem;
  }

  /* 第三行一列;页脚左侧容器 */
  .footer-left{
    border-left: 1px solid #e5eaef;
  }
  
  /* 添加客户 */
  .add-one-area{
    display:flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;

    /* 上 右 下 左 */
    margin: 0 0 1rem 0;
  }
  .input-l{
    width: 10rem;
  }
  .input-xl{
    width: 20rem;
  }
  input{
    height:1.3rem;
    border:1px solid grey;
  }

  .add-one-submit-btn-div{
    display:flex;
    justify-content: center;
    align-items: center;
  }

  /* 正文 */
  .result-list{
    display:flex;
    flex-direction: column;
    gap:1rem;

    /* 主轴对齐 */
    justify-content: center;
    /* 从轴对齐 */
    align-items: center;   
  }

  .result-list-item{
    border:1px solid rgb(170, 177, 170);
    padding: 0 1rem;
    width: 90%;
  }

  .field-name{
    width: 5rem;
    /* 由于它是个<span>标签,行内元素,宽高不生效;把它转成行内块元素“一行显示多个,宽高生效” */
    display: inline-block;
    color: darkgreen;
  }

  /* 页脚元素 */
  footer{
    background-color: #e6e6e6;
    text-align: center;
    padding:1rem;
  }
hyms.js
//注册全局点击事件
function registerGlobalEvents(){

    document.addEventListener('click',function(e){
        //思路:首先我们先判断直接触发事件的对象(e.target)是否为导航栏“带有下拉菜单”的菜单项,怎么判断呢?—— 看这个元素对象里的class属性是否包含hidden
        //对于这个触发对象有个问题:如果点的是li标签,可以判断class属性是否有hidden;但如果点的是span标签,也就是产品,他没有class属性,点了也没用不显示,如何解决这个问题呢?—— 我们可以采用closest()方法获取符合条件的最接近的上级元素(包括自身),那么这样无论点里点外都能追溯到<li class="menu-item">这个元素, 如果没有匹配的元素返回的就是null

        //导航栏菜单点击处理
        let NavMenuItem = e.target.closest('.sub-nav-bar > .menu-item')
        //点击的是导航栏菜单项
        if (NavMenuItem){
            //<li class="menu-item">里面有hidden把hidden去掉;没有加上
            //有的话选出来的是  <ul class="dropdown-menu hidden"> ; 同样的没找到符合条件的元素返回null
            let subMenu = NavMenuItem.querySelector('.dropdown-menu')
            //如果有下拉子菜单
            if(subMenu){
                if (subMenu.classList.contains('hidden')){
                    subMenu.classList.remove("hidden");
                }
                else{
                    subMenu.classList.add("hidden");
                }
            }
        }

        //侧边栏菜单点击处理
        let sideMenuItem = e.target.closest('.side-menu > .menu-item')
        //这里有个问题:点导航栏的下拉菜单我们可以接受点击子菜单然后缩起来;但对于侧边栏我们并不希望这样(子菜单往上找也会追溯到<li class="menu-item">)——  那么我们需要加一个判断条件:如果当前点击的这个元素祖先中有sub-menu就不执行下面内容
        //点击的是侧边栏菜单项,并且不是点击子菜单
        if (sideMenuItem){
        //有的话选出来的是  <ul class="dropdown-menu hidden"> ; 同样的没找到符合条件的元素返回null
            let subMenu = sideMenuItem.querySelector('.sub-menu')
            //如果有下拉子菜单
            if(subMenu && !e.target.closest('.sub-menu')){
                if (subMenu.classList.contains('hidden')){
                    subMenu.classList.remove("hidden");
                }
                else{
                    subMenu.classList.add("hidden");
                }
            }
        }

    })

}

//添加按钮点击处理
function registerClickAddOne(){
    let addOneBtn = document.querySelector('#add-one-btn')
    addOneBtn.addEventListener('click',function(){
        let addOneForm = document.querySelector('.add-one-form')

        if(addOneForm.classList.contains('hidden')){
            addOneForm.classList.remove('hidden')
            addOneBtn.innerText='隐藏'
        }
        else{
            addOneForm.classList.add('hidden')
            addOneBtn.innerText='添加'
        }

    })
}

//提交按钮点击处理
function registerClickAddOneSubmit(){
    //先获取
    let addOneSubmitBtn = document.querySelector('#add-one-submit-btn')
    //监听
    addOneSubmitBtn.addEventListener('click',function(){
        //取出数据;获取已有的网页界面上的内容
        let customer_name = document.querySelector('#customer-name').value
        let customer_phone = document.querySelector('#customer-phone').value
        let customer_addr = document.querySelector('#customer-addr').value

        //发送到后端
        $.ajax({
            url: '/api/mgr/customers',        
            type: 'POST', 
            //指明消息体为json格式
            contentType : 'application/json',

            //浏览器js的内置对象JSON的stringify方法,可将js对象转化为JSON格式的字符串(序列化)
            data: JSON.stringify({
                action:'add_customer',                      
                data:{
                    name:customer_name,
                    phonenumber:customer_phone,
                    address:customer_addr
                }
            }),

            // data: JSON.stringify({
            //     "action":"add_customer",        
            //     "data":{
            //         "name":customer_name,
            //         "phonenumber":customer_phone,
            //         "address":customer_addr
            //     }               
            // }),

            // success 接收到响应
            success: function(data, textStatus, xhr) { 
                if(data.ret === 0)
                    getCustomerList();//重新刷新列表
                else
                    alert('操作失败:'+data.msg)
            },
           
            error: function (xhr, textStatus, errorThrown ){
                console.error(`${xhr.status} \n${textStatus} \n${errorThrown }`)
            }
        })
    })
}

//看接口文档,列出所有客户 请求参数http请求消息url中需要携带的参数4个
function getCustomerList(pagenum=1,pagesize=5,keywords=''){

    //在发出请求之前,先把结果清空(点击下一页)
    document.querySelector('.result-list').innerHTML=''

    //获取响应内容
    $.ajax({   
        type: 'GET', 
        // http协议中,url参数格式都是urlencode格式
        url: `/api/mgr/customers?action=list_customer&pagenum=${pagenum}&pagesize=${pagesize}&keywords=${keywords}`,    

        //jQuery解析响应消息体
        success: function(data, textStatus, xhr) { 
            if(data.ret !== 0){
                alert('操作失败: ' + data.msg)
                return;
            }

            for(let item of data.retlist){
            // 每一项 ,加<p>是为了换行,让它独占一行 ; 前面加一个说明,还要在一行显示,用<span>;还需要指定样式,加个class
            let pEle = `<div class='result-list-item'>
                <p><span class='field-name'>客户名</span><span>${item.name}</span></p>
                <p><span class='field-name'>地址</span><span>${item.address}</span></p>
                <p><span class='field-name'>电话</span><span>${item.phonenumber}</span></p></div>`
            document.querySelector('.result-list').insertAdjacentHTML("beforeend",pEle)
            }
        },

        //错误
        error:function (xhr, textStatus, errorThrown ){
            console.error(`${xhr.status} \n${textStatus} \n${errorThrown }`)
        }
        
    })

}

window.onload = function(){
    registerGlobalEvents();//全局事件
    registerClickAddOne();
    registerClickAddOneSubmit();

    getCustomerList();//获取客户列表
}

分页

login.html
<!DOCTYPE html>
<html lang="en">
<head>
    <style>
        body{
            background-color: #e9ecef;

        }
        main{
            background-color:whitesmoke;
            width: 25rem;
            margin:auto;
            /* 水平方向,左右同时占据一半空间;实现水平居中 */
            margin-top:20vh;
            /* vh:相对整个浏览器网页内容的显示框viewport的高度 ;100vh 就是 100% 的 viewport高度;它会随着窗口高度的调整,字体大小跟着变化 */
            text-align: center;
            /* 指定文本内容的对齐方式 */
        }
    </style>

    <script src="https://cdn.jsdelivr.net/npm/jquery/dist/jquery.min.js"></script>

    <!-- 事件处理:1.DOM对象的addEventListener方法 2.DOM对象的事件属性指定事件处理函数;事件属性名以on开头后面跟事件名称 -->
    <!-- 注意:放head里面的话会导致网页内容还没渲染完就先被执行,DOM里面的内容还没创建都还没有body节点 => 指定一个页面加载事件,等页面加载完之后再执行箭头函数 -->
    <script>
        // 先选择登录按钮
        window.onload =() => {
        document.querySelector('#loginButton').onclick = () => {
            //1.获取用户名、密码
            //alert('执行登录')
            //value:input标签属性,对应的是输入框里面的文本
            let username = document.querySelector('#username').value
            let password = document.querySelector('#password').value

            //2.把他们放到HTTP消息里发出去(使用jQuery) , 看请求消息的接口文档
            //byhy 88888888
            $.post(
            '/api/mgr/signin',//请求网址
            {
                username:username,
                password:password,
            }
            )
            
            //3.当服务端返回ret=0时,跳转到真正的网址 /hyms.html
            //jQuery解析响应消息
            $.ajax({
                url: '/api/mgr/signin',        
                type: 'POST', 
                data: 'username=byhy&password=88888888',
                // 正确返回;回调函数被传入3个参数:data 从服务端返回的数据 ,textStatus 返回的状态文本描述,xhr XMLHttpRequest的扩展类型jqXHR的对象
                success: function(data, textStatus, xhr) { 
                    if(data.ret === 0){
                        //重定向网址
                        location.href = 'hyms.html'
                    }
                    else{
                        alert('登陆失败: ' + data.msg)
                    }
                },
                //错误
                error:function (xhr, textStatus, errorThrown ){
                    console.error(`${xhr.status} \n${textStatus} \n${errorThrown }`)
                }
            })
        }
    };
    </script>
</head>
<body>
    <main>
        <br>
        <div style="display: flex; justify-content: center;">
            <img src="/assets/images/logo.jpg" style="border-radius:50%;width:2.5rem;margin-right:1rem">
            <!-- main属于block类型元素 ;block元素特征:垂直方向,占据的空间由其内容大小决定 -->
            <!-- rem用来修饰 元素的 宽度、高度 ,同样也是相对于 根元素 html 的字体大小 -->
            <!-- 相对的是 根元素 html 的字体大小 -->
            <!-- margin:盒子模型,外边距,盒子与盒子间的距离 -->
            <span style="font-size: 1.8rem">黑羽医疗</span> 
        </div>
 
        <p>输入用户名、密码登录</p>
        <div>
         <input type="text" placeholder="用户名" id="username"> 
         <!-- 提供可描述输入字段预期值的提示信息 --> 
        </div>

        <br>
        <div>
        <!-- div 块级元素 ;特点独占一行 -->
         <input type="password"  placeholder="密码" id="password">   
        </div>

        <br>
        <div>
            <button id="loginButton">登录</button>
        </div>

        <br>
        <div>
            <a href="/register.html">没有账号?请先注册</a>
        </div>
        
        <br>
    </main>
</body>
</html>
hyms.html
<!DOCTYPE html>
<html lang="en">
    <head>
      <meta charset="utf-8">
      <title>药品销管</title>
 
        <!--  外联式  -->
        <link rel="stylesheet" href="hyms.css">
 
        <script src="https://cdn.jsdelivr.net/npm/jquery/dist/jquery.min.js"></script>
 
        <script src="hyms.js"></script>
 
    </head>
 
    <body>
        <!-- 导航logo -->
        <div class="nav-logo">管理员操作</div> 

        <!-- 导航栏 -->
        <nav>
            <ol class="sub-nav-bar">
              <li class="menu-item">
                <!-- div ——块级,新开一行,水平方向占满父级 ;span ——行内,一行显示 -->
                <span>产品</span>
                <ul class="dropdown-menu hidden">
                    <li class="menu-item">子菜单1</li>
                    <div class="dropdown-divider"></div>
                    <li class="menu-item">子菜单2</li>
                </ul>
              </li>
 
              <li class="menu-item"><span>客户</span></li>
              <li class="menu-item"><span>渠道</span></li>
              <li class="menu-item"><span>订单</span></li>
              <li class="menu-item"><span>统计</span></li>
            </ol>
       
         
            <ol class="sub-nav-bar sub-nav-bar-right" style="margin-left: auto; margin-right: 1rem;">
              <li class="menu-item">
                <span>白月黑羽</span>
                <ul class="dropdown-menu hidden">
                  <li class="menu-item">子菜单1</li>
                  <div class="dropdown-divider"></div>
                  <li class="menu-item">子菜单2</li>
                  <div class="dropdown-divider"></div>
                  <li class="menu-item">子菜单3</li>
                </ul>
              </li>
            </ol>
        </nav>
 
        <!-- 侧边菜单栏 -->
        <ul class="side-menu">
          <!-- 菜单头部 -->
          <li class="menu-header">操作菜单</li>
          <li class="menu-item">产品</li>
          <li class="menu-item">客户</li>
          <li class="menu-item has-sub-menu">渠道
            <ul class="sub-menu hidden">
              <li class="menu-item">子菜单1</li>
              <li class="menu-item">子菜单2</li>
            </ul>
          </li>
          <li class="menu-item has-sub-menu">订单
            <ul class="sub-menu hidden">
              <li class="menu-item">子菜单1</li>
              <li class="menu-item">子菜单2</li>
            </ul>
          </li>
          <li class="menu-item">统计</li>
        </ul>
 
        <!-- 主体 -->
        <main>
          <!-- addone 界面 -->
          <div class="add-one-area">
            <span class='btn' id='add-one-btn'>添加</span>
            <div class="add-one-form hidden">
                <p>
                    <span class='field-name'>客户名</span>
                    <input type="text" id="customer-name" class="input-l"></input>
                </p>
 
                <p>
                    <span class='field-name'>电话</span>
                    <input type="text" id="customer-phone" class="input-l"></input>
                </p>
 
                <p>
                    <span class='field-name'>地址</span>
                    <input type="text" id="customer-addr" class="input-xl"></input>
                </p>
 
                <div class="add-one-submit-btn-div">
                    <span class='btn' id='add-one-submit-btn'>确定</span>
                </div>
                
            </div>
 
          </div>
 
          <!-- 分页器 -->
          <div class="paginator">
            <span class="curpage" id="curpage-totalpage"></span>
            <span class="btn-no-border" id="prevPage">上一页</span>
            <span class="btn-no-border" id="nextPage">下一页</span>
            <input type="number" id="gotoPageInput" style="width:3rem">
            <span class="btn-no-border" id="gotoPage">跳转</span>
          </div>
 
          <!-- 列出条目区 -->
          <div class="result-list"></div>


        </main>

        <!-- 页脚左边 -->
        <div class="footer-left"></div>

        <!-- 页脚 -->
        <footer>
          白月黑羽版权所有
          <br>
          <!-- 自己试在style里加style="padding:1rem;",注意一点:白月黑羽版权所有 是content,不是盒子-->
          <small>2020-2022 @copy rights reserved</small>
        </footer>


    </body>
 
</html>
hyms.css
  /* 通用样式 */
  .hidden{
    display:none !important;
  }

  .input-l{
    width: 10rem;
  }

  .input-xl{
    width: 20rem;
  }

  input{
    height:1.3rem;
    border:1px solid grey;
  }

  .btn{
    background-color: rgb(4, 115, 155);
    color:white;
    font: size .8rem;
    text-align:center;
    /* 上下 左右 */
    padding: .2rem .4rem;
    /* 鼠标指针变小手 */
    cursor:pointer;
    width:3rem;
    /* 禁止用户选择文本内容 */
    user-select: none;
  }

  .btn-no-border{
    cursor:pointer;
    color:#296cff;
    font-size: .8rem;
    padding: .2rem .4rem;
    border:1px solid whitesmoke;
    user-select: none;
  }

  .btn-no-border:hover{
    border:1px solid rgb(4, 115, 155);
  }
  /* .disable在原来基础上又设一值 */
  .btn-no-border.disable{
    /* 恢复默认值:正常鼠标 */
    cursor:auto;
    color:grey;
  }

  .btn-no-border.disable:hover{
    color:grey;
    border:1px solid whitesmoke;
  }

  /* 消除input、textarea和select元素在被选中时的默认外边框样式,使其没有边框 */
  input:focus,textarea:focus{
    outline:none;
  }

  /* 功能区设置 */
  /* 页面整体 */
  body{
    height: 100vh;
    max-width: 1250px;
    /* 上下设成0;左右均分 */
    margin: 0 auto;
    display: grid;
    /* 指定行的数量和高度 */
    grid-template-rows:  auto 1fr auto;
    /* 指定列的数量和宽度;右边占据所有剩余宽度 */
    grid-template-columns: minmax(15rem,20rem) 1fr;
  }    
 
  /* 一行一列:管理员操作 */
  .nav-logo{
    border-left: 1px solid #e5eaef;
    color:rgb(8, 96, 8);
    display:flex;
    /* flex布局,居中 */
    align-items: center;
    justify-content: center;
  }
 
  /* 整个导航栏 */
  nav{
    background-color: rgb(4, 115, 155);
    color: white;
    display: flex;
    flex-flow: row wrap;
    /* 保证不会挤到一起去,再小出现滚动条 */
    min-width: 30rem;
    /* 去掉点击后出现的"选中状态"*/
    user-select: none;
  }
 
  /* 导航栏包含所有菜单项的容器*/
  .sub-nav-bar{
    list-style-type: none;
    display:flex;
    flex-flow: row wrap;
    gap:2rem;
    align-items: center;
    justify-content: center;
    margin: 0;
  }
 
  /* 导航栏菜单项里的下拉菜单 */
  .dropdown-menu{
      position:absolute;
      list-style-type: none;
      background-color: white;
      color: #2e669f;
      /* 整体下移 */
      margin-top: .8rem;
      font-size: .85rem;
      padding-left: 0;
      width:10rem;
  }
 
  /* 导航栏里的所有单个菜单项 */
  /* 后代选择器:选中父元素"后代中"满足条件的元素 ;子代选择器:选择父元素"子代中"满足条件的元素*/
  .sub-nav-bar > .menu-item{
    /* 相对于该元素在文档流中的正常位置进行偏移定位 */
    position: relative;
    /* 上下为0,左右为.8rem ;但要注意:这里我只想设一级的子菜单产品那行,需要用子代选择器"->"*/
    padding: .8rem; 
  }
 
  /* 子代采用的是绝对定位,绝对定位相对于非静态定位(static)的父元素进行定位移动;
  绝对定位查找父级的方式:就近找定位的父级,如果逐层查找不到这样的父级,就以浏览器窗口为参照进行定位;
  希望子元素相对于父元素进行定位,又不希望父元素脱标 采用子绝父相(注意这个“.sub-nav-bar .menu-item”是相对定位;“.dropdown-menu”是绝对定位)*/
  .sub-nav-bar-right .dropdown-menu{
    /* 最终选择的元素是元素2 ,并且要求这个元素2是元素1的后代元素 ; 右对齐*/
    right:0;
  }
 
  /* 悬停高亮 */
  /* hover伪类选择器语法: 选择器:hover {css};选中鼠标悬停在元素上的状态,设置样式 */
  .sub-nav-bar .menu-item:hover{
    color:green;
    background-color: white;
  }
 
  .dropdown-menu .menu-item:hover{
    background-color: #e8f5e9;
  }
 
  /* 对于所有菜单项,希望光标变成手*/
  .menu-item{
      cursor: pointer;
  }
   
  /* 下拉菜单的每个菜单项 */
  .dropdown-menu .menu-item{
    /* 上下居中 margin: .6rem; 换成padding 因为背景色设置范围:有效区域包括这个元素的 内容区、padding部分、border部分。也就是包含块除了margin部分 */
    padding: .6rem;
  }
 
  /* 下拉菜单每个菜单项的分界线 */
  .dropdown-divider{
    height:0;
    /* 一条边 */
    border-top:1px solid #e8dcdc;
  }
 
  /* 侧边栏 */
  .side-menu{
    border-left: 1px solid #e5eaef;
    border-top: 1px solid #e5eaef;
    margin: 0;
    /* 文字不顶左角 */
    padding:1rem;
    list-style-type: none;
    /* 根字体的90% */
    font-size:.9rem;
    display:flex;
    /* 列排 */
    flex-direction: column;
    /*  gap:.2rem; flex布局列间距 */
    user-select: none;
  }
 
  /* 侧边栏的下拉菜单 */
  .sub-menu{
    list-style-type: none;
    display:flex;
    /* 列排 */
    flex-direction: column;
    /* gap: .5rem; */
    font-size: .85rem;
    padding:0 1rem;
  }
 
  /* 左侧菜单 菜单头 */
  .side-menu .menu-header{
    color:#837b70;
  }
 
  /* 左侧菜单 菜单项 */
  .side-menu .menu-item{
    color: #5e81a5;
    /* padding-left: 1rem; */
    /* 上 右 下 左 */
    padding: .5rem 0 .5rem 1rem;
    /* 上下.2rem 左右无 */
    margin: .2rem 0;
  }
 
  /* 悬停高亮 */
  .side-menu .menu-item:hover{
    background-color: #e8f5e9;
  }
 
  .sub-menu .menu-item:hover{
    background-color: #bce5bf;
  }
 
  /* 侧边栏展开的菜单项 */
  /* .menu-item.has-sub-menu交集选择器,是menu-item又是has-sub-menu的 */
  .side-menu .menu-item.has-sub-menu{
    color:#6b6464;
    border-left:1px solid green;
  }
 
  /* 界面主体元素 */
  main{
    background-color: #fafafa;
    /* 防止文字顶左角 */
    padding:1rem;
  }
 
  /* 第三行一列;页脚左侧容器 */
  .footer-left{
    border-left: 1px solid #e5eaef;
  }
  
  /* 添加客户 */
  .add-one-area{
    display:flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
 
    /* 上 右 下 左 */
    margin: 0 0 1rem 0;
  }

  .add-one-submit-btn-div{
    display:flex;
    justify-content: center;
    align-items: center;
  }
 
  .paginator{
    display: flex;
    justify-content: center;
    align-items: center;

    gap:1rem;
    margin-bottom: .5rem;
  }

  /* 正文 */
  .result-list{
    display:flex;
    flex-direction: column;
    gap:1rem;
 
    /* 主轴对齐 */
    justify-content: center;
    /* 从轴对齐 */
    align-items: center;   
  }
 
  .result-list-item{
    border:1px solid rgb(170, 177, 170);
    padding: 0 1rem;
    width: 90%;
  }
 
  .field-name{
    /* 由于它是个<span>标签,行内元素,宽高不生效;把它转成行内块元素“一行显示多个,宽高生效” */
    display: inline-block;
    width: 5rem;
    color: darkgreen;
  }
 
  /* 页脚元素 */
  footer{
    background-color: #e6e6e6;
    text-align: center;
    padding:1rem;
  }
hyms.js
//全局数据对象
const GDATA = {
    curPageNum:1,//当前页码
    pagecount:0,//总共页数
}


//注册全局点击事件
function registerGlobalEvents(){
    document.addEventListener('click',function(e){
        //思路:首先我们先判断直接触发事件的对象(e.target)是否为导航栏“带有下拉菜单”的菜单项,怎么判断呢?—— 看这个元素对象里的class属性是否包含hidden
        //对于这个触发对象有个问题:如果点的是li标签,可以判断class属性是否有hidden;
        //但如果点的是span标签,也就是产品,他没有class属性,点了也没用不显示,如何解决这个问题呢?
        //我们可以采用closest()方法获取符合条件的最接近的上级元素(包括自身),那么这样无论点里点外都能追溯到<li class="menu-item">这个元素, 如果没有匹配的元素返回的就是null
 
        //导航栏菜单点击处理
        let NavMenuItem = e.target.closest('.sub-nav-bar > .menu-item')
        //点击的是导航栏菜单项
        if (NavMenuItem){
            //<li class="menu-item">里面有hidden把hidden去掉;没有加上
            //有的话选出来的是  <ul class="dropdown-menu hidden"> ; 同样的没找到符合条件的元素返回null
            let subMenu = NavMenuItem.querySelector('.dropdown-menu')
            //如果有下拉子菜单
            if(subMenu){
                if (subMenu.classList.contains('hidden')){
                    subMenu.classList.remove("hidden");
                }
                else{
                    subMenu.classList.add("hidden");
                }
            }
        }
 
        //侧边栏菜单点击处理
        //问题:点子菜单1,往上追溯,渠道收缩
        let sideMenuItem = e.target.closest('.side-menu > .menu-item')
        //这里有个问题:点导航栏的下拉菜单我们可以接受点击子菜单然后缩起来;但对于侧边栏我们并不希望这样(子菜单往上找也会追溯到<li class="menu-item">)
        //那么我们需要加一个判断条件:如果当前点击的这个元素祖先中有sub-menu就不执行下面内容
        //点击的是侧边栏菜单项,并且不是点击子菜单
        if (sideMenuItem){
        //有的话选出来的是  <ul class="dropdown-menu hidden"> ; 同样的没找到符合条件的元素返回null
            let subMenu = sideMenuItem.querySelector('.sub-menu')
            //如果有下拉子菜单
            //!e.target.closest('.sub-menu')祖先中没有sub-menu;点的不是子菜单
            if(subMenu && !e.target.closest('.sub-menu')){
                if (subMenu.classList.contains('hidden')){
                    subMenu.classList.remove("hidden");
                }
                else{
                    subMenu.classList.add("hidden");
                }
            }
        }
    })
}
 
//添加按钮点击处理
function registerClickAddOne(){
    let addOneBtn = document.querySelector('#add-one-btn')
    addOneBtn.addEventListener('click',function(){
        let addOneForm = document.querySelector('.add-one-form')
 
        if(addOneForm.classList.contains('hidden')){
            addOneForm.classList.remove('hidden')
            addOneBtn.innerText='隐藏'
        }
        else{
            addOneForm.classList.add('hidden')
            addOneBtn.innerText='添加'
        }
 
    })
}

//提交分页器按钮
function   registerClickPaginatorBtns(){
    let prevPageEle=document.querySelector('#prevPage')
    let nextPageEle=document.querySelector('#nextPage')

    prevPageEle.addEventListener('click',function(){
        if(GDATA.curPageNum === 1)//为1,不做任何处理
            return

        getCustomerList(GDATA.curPageNum-1)
    })

    nextPageEle.addEventListener('click',function(){
        if(GDATA.curPageNum === GDATA.pagecount)
            return

        getCustomerList(GDATA.curPageNum+1)
    })

 
document.querySelector('#gotoPage').addEventListener("click",function(e){
    let goToPageNum = parseInt(document.querySelector('#gotoPageInput').value.trim())//trim()移除字符串两端的空格
    getCustomerList(goToPageNum);
})

document.querySelector('#gotoPageInput').addEventListener("keydown",function(e){
    if(e.key === 'Enter'){
        let goToPageNum = parseInt(document.querySelector('#gotoPageInput').value.trim())
        getCustomerList(goToPageNum);
    }
})
}

//提交按钮点击处理
function registerClickAddOneSubmit(){
    //先获取
    let addOneSubmitBtn = document.querySelector('#add-one-submit-btn')
    //监听
    addOneSubmitBtn.addEventListener('click',function(){
        //取出数据;获取已有的网页界面上的内容
        let customer_name = document.querySelector('#customer-name').value
        let customer_phone = document.querySelector('#customer-phone').value
        let customer_addr = document.querySelector('#customer-addr').value
 
        //发送到后端
        $.ajax({
            url: '/api/mgr/customers',        
            type: 'POST', 
            //消息体的格式是json——指明消息体为json格式
            contentType : 'application/json',
 
            //浏览器js的内置对象JSON的stringify方法,可将js对象转化为JSON格式的字符串(序列化)

            data: JSON.stringify({
                "action":"add_customer",        
                "data":{
                    "name":customer_name,
                    "phonenumber":customer_phone,
                    "address":customer_addr
                }               
            }),
 
            // success 接收到响应
            success: function(data, textStatus, xhr) { 
                if(data.ret === 0)
                    getCustomerList();//重新刷新列表
                else
                    alert('操作失败:'+data.msg)
            },
           
            error: function (xhr, textStatus, errorThrown ){
                console.error(`${xhr.status} \n${textStatus} \n${errorThrown }`)
            }
        })
    })
}
 
//看接口文档,列出所有客户 请求参数http请求消息url中需要携带的参数4个
function getCustomerList(pagenum=1,pagesize=4,keywords=''){
 
    //在发出请求之前,先把结果清空(点击下一页)
    document.querySelector('.result-list').innerHTML=''
 
    //获取响应内容
    $.ajax({   
        type: 'GET', 
        // http协议中,url参数格式都是urlencode格式
        url: `/api/mgr/customers?action=list_customer&pagenum=${pagenum}&pagesize=${pagesize}&keywords=${keywords}`,    
 
        //jQuery解析响应消息体
        success: function(data, textStatus, xhr) { 
            if(data.ret !== 0){
                alert('操作失败: ' + data.msg)
                return;
            }

            //更新分页信息
            let pagecount = Math.ceil(data.total/pagesize)//上限整数
            document.getElementById('curpage-totalpage').innerText=`第${pagenum}页,共${pagecount}页`

            GDATA.curPageNum = pagenum;
            GDATA.pagecount = pagecount;

            let prevPageEle=document.querySelector('#prevPage')
            let nextPageEle=document.querySelector('#nextPage')

            if(pagenum===1)
                prevPageEle.classList.add('disable')
            else
                prevPageEle.classList.remove('disable')

            if(pagenum===pagecount)
                nextPageEle.classList.add('disable')
            else
                nextPageEle.classList.remove('disable')

            
            //更新结果列表
            for(let item of data.retlist){
            // 每一项 ,加<p>是为了换行,让它独占一行 ; 前面加一个说明,还要在一行显示,用<span>;还需要指定样式,加个class
                let pEle = `<div class='result-list-item'>
                    <p><span class='field-name'>客户名</span><span>${item.name}</span></p>
                    <p><span class='field-name'>地址</span><span>${item.address}</span></p>
                    <p><span class='field-name'>电话</span><span>${item.phonenumber}</span></p>
                    </div>`
                document.querySelector('.result-list').insertAdjacentHTML("beforeend",pEle)
            }
        },
 
        //错误
        error:function (xhr, textStatus, errorThrown ){
            console.error(`${xhr.status} \n${textStatus} \n${errorThrown }`)
        } 
    })
}

// 注册事件
window.onload = function(){
    registerGlobalEvents()//全局事件
    registerClickAddOne()//添加按钮点击处理
    registerClickAddOneSubmit()//提交按钮点击处理
    registerClickPaginatorBtns()//提交分页器按钮

    getCustomerList();//获取客户列表
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值