电商后台管理

目录

项目介绍

在这个项目用到的技术

二、开发准备工作

三、开发流程

四、二次封装axios

五、配置api

六、首页

七、页面鉴权

 八、主页面 

1、头部导航

2、左侧导航

3、主题内容

        用户管理>用户列表

        用户管理>角色列表

        权限管理 ,权限列表

        商品管理,商品分类

        还有商品列表,分类参数,订单列表,数据报表,这几个模块使用的都是请求接口渲染,和增删改查

九、项目难点:



项目介绍

这是一个电商类的后台管理系统,主要作用是用来进行用户的管理,商品订单的管理,和权限管理,是内部员工进行商品记录,和分类


在这个项目用到的技术

                vue2全家桶,element ui,axios,vue-table-with-tree-grid


一、项目的主要模块

有登录页面和主页

        主页有用户管理,权限管理,商品管理,订单管理

二、开发准备工作

创建项目并下载项目中所需要用的第三方组件

三、开发流程

  1. 看接口是否用到跨域,如果需要跨域需要到 跨域需要创建vue.config.js文件,在里面配置devServer,在devServer属性⾥⾯的proxy属性⾥⾯配置,⼀共配置三个属性,分别是代理名称 代理地址 开启跨域 重写路径,这个项目是不用跨域的
  2. 二次封装axios和配置api
  3. 配置路由
  4. 下载项目所需要的组件 比如element ui

四、二次封装axios

        在src下创建一个http文件夹,在这个文件夹下面创建request.js文件,在request文件import引入axios,引入element ui用来实现loading加载

  1. 引入axios,和需要的组件
    //封装axios
    import axios from "axios";
    // element ui 提示信息和loading加载
    import { Message, Loading } from 'element-ui';
    //引入路由
    import router from "../router"

  2. 封装loading开启和结束的函数
    // 封装loading开启和结束函数
    let loading;
    function startLoading(){
      loading = Loading.service({
        lock:true,
        text:'拼命加载中...',
        background:'rgba(0,0,0,0.7)'
      })
    }
    function endLoading(){
      loading.close()
    }

  3. 创建axios实例
    //创建axios实例
    const service = axios.create({
      //基地址
      baseURL:" 接口地址",
      //baseURL:env.dev.baseUrl,
      settimeout: 5000,
    });

  4. 请求拦截 :请求拦截使用interceptors.request .use()在发送请求之前添加请求头并且开启loading,请求失败关闭loading,
    //2:请求拦截
    service.interceptors.request
      .use((config) => {
        //在发送请求之前做些什么,比如验证token之类的
        if(localStorage.eleToken){
          config.headers.Authorization = localStorage.eleToken
        }
        startLoading();
        return config;
      },(error) => {
        //对错误请求做些什么
        // endLoading();
        loading.close();
        return Promise.reject(error)
      })

  5. 响应拦截:响应拦截使用interceptors.response.use(),响应成功返回数据并关闭loading,请求失败返回失败的原因,比如用户过期 需要删除存放的token,并且提示用户用户过期,然后返回到登录页面
    //3:响应拦截
    service.interceptors.response.use(
        //请求成功关闭loading 并返回数据
      (response) =>{
        endLoading();
        return response;
      },
      (error) => {
        //对错误请求做些什么
        const {status} = error.response
        //判断用户是否过期,如果过期了清楚token
        if(status == 401){
          Message.error('用户过期,请重新登录!')
          localStorage.removeItem("eleToken")
          router.push("/login")
        }
        //关闭loading 返回信息提示用户登录过期
        endLoading();
        console.log(error)
        Message.error(error.response.data.msg)
        return Promise.reject(error)
    })

  6. 抛出对象
//抛出axios对象实例
export default  service;

五、配置api

在http文件夹新建api.js文件,在文件引入封装好的axios

// 封装api
// 引入封装好的axios
import request from "./request"

// 向各个接口分发axios
export function getList (){
  return request({
      url:'', // 这个地址是去掉公共地址剩下的地址
      method:'',// 请求方式 支持多种方式  get post put delete 等等
  })
}

六、首页

首页样式

 实现方式:

  1. 登录样式
    <template>
      <div class="login_container">
        <!-- 父元素 -->
        <div class="login_box">
          <!-- 头像框 -->
          <div class="avatar_box">
            <img src="../assets/logo.png" alt="" />
          </div>
          <!-- 登录 -->
          <div class="">
            <el-form
              :model="loginForm"
              :rules="loginFormRules"
              ref="loginFormRef"
              class="login_form"
            >
              <!-- 用户名 -->
              <el-form-item prop="username">
                <el-input
                  prefix-icon="el-icon-user-solid"
                  type="text"
                  v-model="loginForm.username"
                  placeholder="请输入用户名"
                ></el-input>
              </el-form-item>
              <!-- 密码 -->
              <el-form-item prop="password">
                <el-input
                  prefix-icon="el-icon-s-goods"
                  type="password"
                  v-model="loginForm.password"
                  placeholder="请输入密码"
                ></el-input>
              </el-form-item>
              <el-form-item class="btns">
                <el-button type="primary" @click="loginFormBtn('loginFormRef')" >登录</el-button>
                <el-button @click="resetForm">重置</el-button>
              </el-form-item>
            </el-form>
          </div>
        </div>
      </div>
    </template>
    <style lang="less" scoped>
    .login_container {
      background: #2b4b6b;
      height: 100%;
    }
    .login_box {
      width: 450px;
      height: 360px;
      background: #fff;
      position: absolute;
      left: 50%;
      top: 50%;
      transform: translate(-50%, -50%);
      .avatar_box {
        height: 130px;
        width: 130px;
        border: 1px solid #ccc;
        border-radius: 50%;
        position: absolute;
        padding: 10px;
        left: 50%;
        transform: translate(-50%, -50%);
        box-shadow: 0px 0px 10px #ddd;
        background: #fff;
        img {
          width: 100%;
          height: 100%;
          border-radius: 50%;
          background: #eee;
        }
      }
      .login_form {
        width: 100%;
        position: absolute;
        bottom: 60px;
        padding: 0 40px;
        .btns {
          display: flex;
          justify-content: center;
        }
      }
    }
    </style>

  2. input框的校验
      data() {
        return {
          loginForm: {
            username: "admin",
            password: "123456",
          },
          // 校验
          loginFormRules: {
            username: [
              { required: true, message: "请输入用户名", trigger: "blur" },
              { min: 4, max: 10, message: "用户名在4到10个字符之间" ,trigger: "blur" },
            ],
            password: [
              { required: true, message: "请输入密码", trigger: "blur" },
              { min: 6, max: 10, message: "密码在6到10个字符之间",trigger: "blur" },
            ],
          },
        };
      },

  3.  

    在api.js文件夹配置登录的接口 并在引入api

     点击登录进项发起请求接口    

    在点击登录按钮时触发按钮的点击事件,向后台发送登录请求,请求成功后把token解析并存放到本地,如果页面多处需要用到token的信息,需要存放到vuex,并跳转到主页

    解析token可以使用插件 用npm install jwt-decode 在需要解析的页面引入

        import { xxx } from '../http/api'
    
        loginFormBtn() {
          this.$refs.loginFormRef.validate((valid) => {
            if(!valid) return
            if (valid) {
              loginForm(this.loginForm).then((res) => {
                // 判断状态码是否等于200
                if (res.data.meta.status == 200) {
                  // 获取本地中的token值
                  localStorage.setItem("eleToken", res.data.data.token);
                  let decode = jwt_decode(localStorage.eleToken)
                  this.$store.dispatch('decode', decode)
                  // 弹出提示信息
                  this.$message.success(res.data.meta.msg);
                  // 将页面跳转至首页
                  this.$router.push("/home");
                } else {
                  // 否则提示错误信息
                  this.$message.error(res.data.meta.msg);
                  return;
                }
              });
            } else {
              console.log("error submit!!");
              return false;
            }
          });
        },

    七、页面鉴权

                        为了避免用户没有登录就跳转到主页面,需要在router文件夹下面的index.js设置路由守卫

// 全局路由守卫前置钩子
router.beforeEach((to,form,next)=>{
  // 判断token是否存在
  const isLogin = localStorage.eleToken ? true : false
  // 判断是否为登录页面
  if(to.path == '/Login'){
    next()
  }else{
    // 如果token值存在就让放行  否则就强制回到登录页面
    isLogin ? next() : next('/Login')
  }
})

 八、主页面 

        主页面主要分为三个模块 ,头部导航 左侧导航,主题内容,

1、头部导航

就是显示logo,用户信息,退出登录,退出登录就是清除本地和vuex存放的token,并跳转到登录页面

2、左侧导航

        是用element ui 的组件来实现的

        左侧菜单的数据是后台给我们发送的,所以要在页面创建后就获取到数据信息,在methods定义一个事件,在created里面调用(created是创建后执行的函数),把获取到的数据放到data里面,然后再左侧导航的组件用v-for循环遍历,然后再router下的文件夹下的index.js配置对应的路由

<!-- 侧边栏 -->
      <el-aside width="200px">
        <el-menu
          :collapse="isCollapse"
          unique-opened
          text-color="#fff"
          background-color="#333744"
          active-text-color="#409FFF"
          :default-active="activePath"
          :collapse-transition="false"
          router
        >
          <el-submenu :index="item.id + ''" v-for="item in menuList" :key="item.id">
            <template slot="title">
              <i :class="iconObj[item.id]"></i>
              <span>{
   
   { item.authName }}</span>
            </template>
            <el-menu-item
              @click="saveNavState('/' + subItem.path)"
              :index="'/' + subItem.path"
              v-for="subItem in item.children"
              :key="subItem.id"
            >
              <template slot="title">
                <i :class="iconObj[subItem.id]"></i>
                <span>{
   
   { subItem.authName }}</span>
              </template>
            </el-menu-item>
          </el-submenu>
        </el-menu>
      </el-aside>
    //data的变量 
    menuList: [],

    async getMyMenus() {
      const { data: res } = await getMenus();
      if (res.meta.status != 200) return;
      this.menuList = res.data;
    },

3、主题内容

用户管理>用户列表

  1.   查找
          <!-- 搜索 添加 -->
          <el-row :gutter="20">
            <el-col :span="6">
              <el-input
                placeholder="请输入内容"
                v-model="queryInfo.query"
                clearable
                @clear="getUserList"
              >
                <el-button
                  slot="append"
                  icon="el-icon-search"
                  @click="getUserList"
                ></el-button>
              </el-input>
            </el-col>
            <el-col :span="4">
              <el-button type="primary" @click="addDialogVisible.show = true"
                >添加用户</el-button
              >
            </el-col>
          </el-row>
        //搜索和添加使用的是同一个接口
        async getUserList() {
          const { data: res } = await getUsers(this.queryInfo);
          if (res.meta.status !== 200) return this.$message.error("获取用户列表失败!");
          this.userlist = res.data.users;
          this.total = res.data.total;
        },

  2. 删除  需要把这一行的id发送给后台
        // 删除用户
        async removeUserById(id) {
          const confirmResult = await this.$confirm(
            "此操作将永久删除该用户, 是否继续?",
            "提示",
            {
              confirmButtonText: "确定",
              cancelButtonText: "取消",
              type: "warning",
            }
          ).catch((err) => err);
          // 点击确定 返回值为:confirm
          // 点击取消 返回值为: cancel
          if (confirmResult !== "confirm") {
            return this.$message.info("已取消删除");
          }
          const { data: res } = await deleteUsers(id);
          if (res.meta.status !== 200) return this.$message.error("删除用户失败!");
          this.$message.success("删除用户成功!");
          this.getUserList();
        },

  3. 添加  点击添加的时候会打开模态框 
        <!-- 添加用户的对话框 -->
        <el-dialog
          title="添加用户"
          center
          :visible.sync="addDialogVisible.show"
          width="50%"
          @close="addDialogClosed"
        >
          <!-- 内容主体 -->
          <el-form
            :model="addUserForm"
            ref="addUserFormRef"
            :rules="addUserFormRules"
            label-width="100px"
          >
            <el-form-item label="用户名" prop="username">
              <el-input v-model="addUserForm.username"></el-input>
            </el-form-item>
            <el-form-item label="密码" prop="password">
              <el-input v-model="addUserForm.password"></el-input>
            </el-form-item>
            <el-form-item label="邮箱" prop="email">
              <el-input v-model="addUserForm.email"></el-input>
            </el-form-item>
            <el-form-item label="手机" prop="mobile">
              <el-input v-model="addUserForm.mobile"></el-input>
            </el-form-item>
          </el-form>
          <span slot="footer" class="dialog-footer">
            <el-button @click="addDialogVisible.show = false">取 消</el-button>
            <el-button type="primary" @click="addUser">确 定</el-button>
          </span>
        </el-dialog>
        // 添加用户
        addUser() {
          // 提交请求前,表单预验证
          this.$refs.addUserFormRef.validate(async (valid) => {
            // console.log(valid)
            // 表单预校验失败
            if (!valid) return;
            const { data: res } = await addUsers(this.addUserForm);
            console.log(this.addUserForm);
            if (res.meta.status != 201) {
              this.$message.error("添加用户失败!");
              return;
            }
            this.$message.success("添加用户成功!");
            // 隐藏添加用户对话框
            this.addDialogVisible.show = false;
            // this.getUserList();
            this.$parent.getUserList();
          });
        },

  4. 编辑  点击编辑打开模态框
        // 编辑
        async editorCate(row) {
          this.dialogEditor = false;
          this.dialogVisible = true;
          this.dialog = {
            show: true,
            title: "编辑用户",
            option: "edit",
          };
          this.addCateForm.cat_pid = row.cat_id;
          this.addCateForm.cat_name = row.cat_name;
        },
    
    
        //点击确定
        addCate() {
          this.$refs.cateForm.validate(async (valid) => {
            if (valid) {
                const { data: res } = await editorCate(this.addCateForm);
                if (res.meta.status !== 200) {
                  return this.$message.error("编辑失败!");
                }
                this.$message.success("编辑成功!");
              
              this.dialogVisible = false;
              this.addCateForm = {
                cat_name: "", //分类名
                cat_pid: 0, //父级id
                cat_level: 0, //分类等级
              };
              this.selectedKeys = {};
            } else {
              console.log("error submit!!");
              return false;
            }
          });
        },

用户管理>角色列表

        除了增删改查还有树形菜单

 

实现方式

点击下拉显示  用到了element ui

 样式实现

        <el-table-column type="expand">
          <template slot-scope="scope">
            <!-- <pre>{
   
   { scope.row }}</pre> -->
            <el-row
              :class="[i1 === 0 ? '' : 'bdtop', 'vcenter']"
              v-for="(item1, i1) in scope.row.children"
              :key="item1.id"
            >
              <!-- 一级 -->
              <el-col :span="5">
                <el-tag closable @close="removeRightById(scope.row, item1.id)">{
   
   {
                  item1.authName
                }}</el-tag>
              </el-col>
              <!-- 二级和三级 -->
              <el-col :span="19">
                <el-row
                  :class="[i2 === 0 ? '' : 'bdtop', 'vcenter']"
                  v-for="(item2, i2) in item1.children"
                  :key="item2.id"
                >
                  <el-col :span="6">
                    <el-tag
                      closable
                      @close="removeRightById(scope.row, item2.id)"
                      type="success"
                      >{
   
   { item2.authName }}</el-tag
                    >
                  </el-col>
                  <el-col :span="18">
                    <el-tag
                      v-for="item3 in item2.children"
                      :key="item3.id"
                      type="warning"
                      closable
                      @close="removeRightById(scope.row, item3.id)"
                      >{
   
   { item3.authName }}</el-tag
                    >
                  </el-col>
                </el-row>
              </el-col>
            </el-row>
          </template>
        </el-table-column>

获取数据信息

    //调取角色数据
    async getAllRoles() {
      let { data: res } = await getRolesList();
      this.rolesList = res.data;
    },

点击分配权限,打开模态框,回显用的是递归的方法实现的

 分配权限的模态框样式

    <!-- 分配权限 -->
    <el-dialog
      title="分配权限"
      :visible.sync="dialogVisible"
      width="50%"
      @close="clearDefaultKeys"
    >
      <!-- defaultKeys 默认勾选数组 -->
      <el-tree
        :data="rightsTree"
        show-checkbox
        default-expand-all
        node-key="id"
        :props="treesProps"
        :default-checked-keys="defaultKeys"
        ref="treeData"
      ></el-tree>
      <span slot="footer" class="dialog-footer">
        <el-button @click="dialogVisible = false">取 消</el-button>
        <el-button type="primary" @click="addRights">确 定</el-button>
      </span>
    </el-dialog>
    // 打开模态框
    async showDialog(role) {
      this.roleID = role.id;
      this.dialogVisible = true;
      let { data: res } = await getRightsTree();
      if (res.meta.status !== 200) {
        return this.$message.error("获取用户权限列表失败");
      }
      this.rightsTree = res.data;
        // defaultKeys 默认勾选数组
      this.getleafKeys(role, this.defaultKeys);
      console.log(res, "treeData");
    },
    //递归遍历三级节点 如果没有chiledren就是三级节点 那么渲染数组
    getleafKeys(node, arr) {
      if (!node.children) {
        return arr.push(node.id);
      }
      node.children.forEach((item) => {
        this.getleafKeys(item, arr);
      });
    },

权限管理 ,权限列表

这个页面主要的效果就是展示

效果图

    <el-card>
      <el-table :data="rightsList" border stripe>
        <el-table-column type="index"></el-table-column>
        <el-table-column prop="authName" label="权限名称"></el-table-column>
        <el-table-column prop="path" label="路径"></el-table-column>
        <el-table-column prop="level" label="权限等级">
          <template slot-scope="scope">
            <el-tag v-if="scope.row.level == 0">一级</el-tag>
            <el-tag type="success" v-else-if="scope.row.level == 1">二级</el-tag>
            <el-tag type="warning" v-else>三级</el-tag>
          </template>
        </el-table-column>
      </el-table>
    </el-card>

商品管理,商品分类

简单的增删改查,主要的是树形结构  

这个功能用到了一个插件 下载需要cmd打开黑窗口 输入vue ui 跳转到网页下载 vue-table-with-tree-grid  下载完之后在main.js引入

      <!-- 表格 -->
      <tree-table
        :expand-type="false"
        :selection-type="false"
        show-index
        index-text="#"
        border
        :data="cateList"
        :columns="columns"
      >
      </tree-table>
      cateList: [],
      columns: [
        {
          label: "分类名称",
          prop: "cat_name",
        },
        {
          label: "是否有效",
          type: "template",
          template: "isok",
        },
        {
          label: "排序",
          type: "template",
          template: "order",
        },
        {
          label: "操作",
          type: "template",
          template: "opt",
        },
      ],
      
    async getAllCategories() {
      let { data: res } = await getCategoriesList(this.queryInfo);
      if (res.meta.status !== 200) {
        return this.$message.error("获取数据失败");
      }
      this.$message.success("获取分类成功");
      this.cateList = res.data.result;

      console.log(res, "分类数据");
    },

添加分类

模态框,用到了级联选择器

效果图

实现方法:

渲染级联选择权

    <!-- 添加分类弹框 -->
    <el-dialog title="dialog.title" :visible.sync="dialogVisible" width="50%">
      <el-form
        ref="cateForm"
        :model="addCateForm"
        :rules="addCateFormRules"
        label-width="100px"
      >
        <el-form-item label="分类名称:" prop="cat_name">
          <el-input
            v-model="addCateForm.cat_name"
            placeholder="请输入分类名字"
          ></el-input>
        </el-form-item>
        <!-- 
          options:数据源
          props:靶子对象{
            value:选中的属性
            label:显示的名称
            children:嵌套的结构
            ...
          }
          v-model:选中数组
          @changed:选择项发生变化时候 触发的函数
         -->
        <el-form-item label="父级分类:" v-if="dialogEditor">
          <el-cascader
            v-model="selectedKeys"
            :options="parentCateList"
            :props="cascaderProps"
            @change="parentCateListChanged"
            change-on-select
          ></el-cascader>
        </el-form-item>
      </el-form>
      <span slot="footer" class="dialog-footer">
        <el-button @click="dialogVisible = false">取 消</el-button>
        <el-button type="primary" @click="addCate">确 定</el-button>
      </span>
    </el-dialog>
      //添加分类表单
      addCateForm: {
        cat_name: "", //分类名
        cat_pid: 0, //父级id
        cat_level: 0, //分类等级
      },
          
          
 async showDialog() {
      this.dialog = {
        title: "添加用户",
        option: "add",
      };
      this.dialogEditor = true;
      let { data: res } = await getCategoriesList({ type: 2 });
      if (res.meta.status !== 200) {
        return this.$message.error("获取父级分类数据失败");
      }
      this.$message.success("获取父级分类数据成功!");
      this.parentCateList = res.data;
      this.dialogVisible = true;
    },

绑定级联选

   		//父级分类
      parentCateList: [],
        //选中的数组
      selectedKeys: [],
       //级联靶子对象
      cascaderProps: {
        value: "cat_id",
        label: "cat_name",
        children: "children",
        expandTrigger: "hover",
      },


	//选择项发生变化时候触发
    parentCateListChanged() {
      console.log(this.selectedKeys,"级联选择器变化了!!!")
      if (this.selectedKeys.length > 0) {
        this.addCateForm.cat_pid = this.selectedKeys[this.selectedKeys.length - 1];
        //为当前分类的等级赋值
        this.addCateForm.cat_level = this.selectedKeys.length;
        return;
      } else {
        this.addCateForm.cat_pid = 0;
        this.addCateForm.cat_level = 0;
      }
    },
        
        //点击确定
    addCate() {
      this.$refs.cateForm.validate(async (valid) => {
        if (valid) {
          if (this.dialog.option == "edit") {
            const { data: res } = await editorCate(this.addCateForm);
            if (res.meta.status !== 200) {
              return this.$message.error("编辑失败!");
            }
            this.$message.success("编辑成功!");
          } else if (this.dialog.option == "add") {
            const { data: res } = await addCateList(this.addCateForm);
            if (res.meta.status !== 201) {
              return this.$message.error("添加失败!");
            }
            this.$message.success("添加成功!");
          }
          this.getAllCategories();
          this.dialogVisible = false;
          this.addCateForm = {
            cat_name: "", //分类名
            cat_pid: 0, //父级id
            cat_level: 0, //分类等级
          };
          this.selectedKeys = {};
        } else {
          console.log("error submit!!");
          return false;
        }
      });
    },

还有商品列表,分类参数,订单列表,数据报表,这几个模块使用的都是请求接口渲染,和增删改查

九、项目难点:

  1. 难点:角色列表的分配权限回显,

    实现思路:当点击分配权限的时候打开模态框的时候进行渲染数据,和选中的对象

    实现方法:点击打开模态框的时候传递选中的对象,在点击打开模态框的定义方法中执行递归函数,进行判断遍历,如果有chiledren就循环遍历函数自身,如果没有chiledren就是三级节点 那么渲染数组,

  2. 难点:商品分类的用户添加,级联选择器

    实现思路:当点击添加用户分类的时候,渲染级联选择器,当我们选择级联选择器的时候,需要绑定选中的id

    实现方法:调用接口获取信息,绑定 options:数据源,设置靶子对象,用v-model绑定选中数组,设置选择项发生变化时候 触发的函数,当选择器发生改变的时候,进行if判断,如果选中的数组长度大于0,让该数值的id减1,意思就是添加的数据父级的id,放到新数组里,再把分类的层级和添加的分类名称存放到新的数组,

  3. 难点:按钮权限

    实现思路: 在某个菜单的界⾯中, 我们需要根据按钮权限数据, 展示出可进⾏操作的按钮,⽐如删除, 修改, 增 加等按钮

    实现方法: 如果要实现按钮的权限控制,我们需要使⽤vue的⾃定义指令去实现 , ⾸先需要创建⼀个按钮权限控制的指令,我们定义这个指令的名称为: v-a, 在这个指令的内部获取到vuex⾥⾯存储的按钮权限数据 , 在通过binding.value获取到⾃定义制定属性值的数据 , 判断从vuex⾥⾯获取到的按钮权限数据是否包含了⾃定义指令包含的权限 , 如果不包含,我们在设置el.style.display = “none”,并且使⽤el.parentNode.removeChild(el)删除当前按钮元素

    Vue.directive('a', {
     beforeMount: function (el, binding) {
             //获取vuex或者本地存放的按钮数据
         let actionList = storage.getItem('actionList');
             //控制指令的按钮数据
         let value = binding.value;
             //includes()方法用来判断一个数组是否包含一个指定的值,如果是返回 true,否则false。
         let hasPermission = actionList.includes(value)
         //判断是否存在如有有就显示按钮,如果不存在就隐藏
         if (!hasPermission) {
         	el.style = 'display:none';
        	 setTimeout(() => {
     				el.parentNode.removeChild(el);
     			}, 0)
     		}
     	}
    })

猜你喜欢

转载自blog.csdn.net/dyx001007/article/details/127640030