精华内容
下载资源
问答
  • vue后台管理系统难点
    千次阅读
    2022-02-14 14:02:30

    vue后台管理知识点、难点总结

    1.upload时,png格式的不能上传????(不对)

        // 上传相关
        //图片上传成功
        handleAvatarSuccess(res, file) {
          console.log(res, file, 222222);
          this.tmForm.logoUrl = res.data;
        },
        //图片上传之前
        beforeAvatarUpload(file) {
          // const isJPG = file.type === "image/jpeg";
          const isJPG = file.type === 'image/jpg' || file.type === 'image/png'|| file.type === 'image/PNG'|| file.type === 'image/JPG';
          const isLt2M = file.size / 1024 / 1024 < 2;
    
          if (!isJPG) {
            // this.$message.error("上传头像图片只能是 JPG 格式!");
            this.$message.error("上传头像图片只能是 JPG和PNG 格式!");
    
          }
          if (!isLt2M) {
            this.$message.error("上传头像图片大小不能超过 2MB!");
          }
          return isJPG && isLt2M;
        },
    

    2 js中的项目应用什么时候用async和await

    获取分页数据的时候;获取列表,点击删除数据确定按钮、点击添加和修改的确定按钮的时候;

    3 添加或者编辑的时候报错:Error in v-on handler (Promise/async): “Error: 失败”(解决,其他页的数据正常显示)

    4 注册全局组件和方法

    //引入相关接口API
    import API from '@/api';
    import CategorySelete from '@/components/CategorySelect'
    
    //(组件实例的原型的原型指向的是Vue.prototype)放在原型上,任意组件都可使用API相关的接口
    Vue.prototype.$API=API;
    //注册全局组件
    Vue.component(CategorySelete.name,CategorySelete)
    

    5 深拷贝:

    1. // this.attrInfo=JSON.parse(JSON.stringify(row))
    2. this.attrInfo=cloneDeep(row)
      第二种引入elementui中封装的方法:cloneDeep
    //按需引入lodash当中的深拷贝
    import cloneDeep from 'lodash/cloneDeep'
    export default {
      name:'',
      data(){}
      .........
      methods:{
        fn(row){
        ...
        this.attrInfo=cloneDeep(row)
        }
      }
    }
    
    
    

    6 v-if和v-else之间不能有任何节点,或者失效

    7 vue中 data的数据都是响应式的,添加到data中的也是

    数组的检测可以通过替换或变更(push也是变更)实现

    8查看模式转为编辑模式时(span–>input)用$nextTick()

     //单击span
        toEdit(row,index){
          //点击span时,切换为input,对于浏览器而言,重排重绘需要耗时间,不可能立即取到input键
          //这是用  $nextTick()==>当节点渲染完毕了,会执行一次
          this.$nextTick(()=>{
            this.$refs[index].focus();
          })
          row.flag=true
        },
    

    9 elementui版本问题

    在用Popconfirm 气泡确认框时,绑定confirm事件时没有效果,原因是最新的elementui版本号(2.15.x)和模板版本号(2.13.x)不一致,项目低,于是事件绑定改为@onConfirm="deleteAttrValue"即可

     <el-popconfirm :title="`这是一段内容确定${row.valueName}删除吗?`" @onConfirm="deleteAttrValue">
    	  <el-button
    	     type="danger"
    	     size="mini"
    	     icon="el-icon-delete"
    	     slot="reference"
    	        ></el-button>
    	 </el-popconfirm>
    
    deleteAttrValue() {
          alert(333);
        },
    

    10 为什么删除属性值列表不用发送请求(没解决)

    在这里插入图片描述

    11 数组中filter

    1.会返回一个新的数组
    2.过滤的作用,从起始遍历,筛选需要的数据,需要返回的布尔值妖魔真要么假

    12 element ui中分页pagination的汉化

    main.js中添加:

    //element分页组件汉化
    import zhLocale from 'element-ui/lib/locale/lang/zh-CN'  //引入中文版
    Vue.use(ElementUI,{zhLocale})
    
    

    13 父组件想要调用子组件的方法(父组件想要获取子组件的属性和方法),可用$ref $childen

    每次点击父组件中的按钮(如父组件列表中有修改按钮),点击修改按钮后,展示子组件的页面的同时,同时四个请求),怎么解决?

    总结::项目功能需求是,每一次显示SpuForm子组件时,都会发四个请求。

    mounted是组件挂载完毕后,只执行一次。
    不能在子组件中的mounted中写,因为v-show只是控制SpuForm子组件显示与隐藏,这个子组件并没有卸载,导致mounted只执行一次

    <el-table-column prop="prop" label="操作" width="width">
         <template slot-scope="{row,$index}">
              <hint-button type="warning" icon="el-icon-edit" size="mini" title="修改spu" @click="updateSpu(row)"></hint-button>
         </template>
              </el-table-column>
    
    //父组件中封装好的子组件
     <SpuForm v-show="scene==1" @changeScene="changeScene"></SpuForm>
    

    解决思路:每次点击修改按钮时,让子组件发四个请求
    可以给子组件加一个ref

     <SpuForm v-show="scene==1" @changeScene="changeScene" ref="spu"></SpuForm>
    

    在点击修改时的函数中可以得到子组件的方法

     updateSpu(row){
            this.scene=1
            console.log(this.$refs.spu,999999);//可以获取到子组件spuForm子组件的,那么子组件的数据和方法也可以拿到
        },
    

    接着,在子组件中定义一个初始化方法。那么在父组件中就可以通过$refs接收到方法

     updateSpu(row){
            this.scene=1
            this.$refs.spu.initSpuData()
        },
    

    14 用foreach修改服务器传过来的数据

    //获取SPU图标的接口
          let result3 = await this.$API.spu.reqSpuImageList(this.spuId);
          console.log(result3, 113);
          if (result3.code == 200) {
            //由于照片墙显示图片的数据需要数组,数组里面的元素需要有name和url,so进行修改
             let listArr= result3.data;
             listArr.forEach(item => {
               item.name=item.imgName
               item.url=item.imgUrl
             });
            this.spuImageList = listArr;
          }
    

    15 vue中的computed

    computed必须有返回值return
    every返回布尔值
    filter返回的值为布尔值为真的值
    在这里插入图片描述

    computed: {
        unSelectSaleAttr(){
          let result=this.saleAttrList.filter(item=>{
            return this.spu.spuSaleAttrList.every((item2)=>{//不知道为啥是every,用some也可
              return  item2.sale`在这里插入代码片`AttrName!==item.name
            })
          })
          return result
        }
      },
    

    16 el-select多选框可以穿多个数据,拼接一下即可

    <el-form-item label="销售属性">
            <el-select :placeholder="`还有${unSelectSaleAttr.length}未选择`" v-model="attrId">
              <el-option :label="item.name" :value="`${item.id}:${item.name}`" v-for="(item,index) in unSelectSaleAttr" :key="item.id"></el-option>
            </el-select>
            <el-button type="primary" icon="el-icon-plus" :disabled="!attrId">添加销售属性</el-button>
          </el-form-item>
    

    17 项目中添加的数据push到收集数据的spu中,判断输入的是否为空

        //添加新的销售属性
        addSaleAttr() {
          //把收集到的销售属性进行分割
          const [baseSaleAttrId, saleAttrName] = this.attrIdAndAttrName.split(":");
          let newSaleAttr = { baseSaleAttrId, saleAttrName, spuSaleAttrValueList: [] };
          this.spu.spuSaleAttrList.push(newSaleAttr);
          this.attrIdAndAttrName = "";
        },
        //添加属性值
        addSaleAttrValue(row) {
          console.log(row, 555);
          // row.inputVisible=true 不是响应式的数据
          this.$set(row, "inputVisible", true);
          this.$set(row, "inputValue", "");
        },
        //el-input失焦事件
        handleInputConfirm(row) {
          console.log(row,8888);
          // this.$set(row, "inputVisible", false);  已经是响应式的了
          const {baseSaleAttrId,inputValue}=row
            if(inputValue.trim()==''){
              this.$message('属性值不能为空')
              return
          }
          let newSaleAttrValue={baseSaleAttrId,saleAttrValueName:inputValue}
          row.spuSaleAttrValueList.push(newSaleAttrValue)
    
          row.inputVisible=false
          
        },
    

    18 some every filter 返回的都是布尔值,需要return

          //不能为空
          if (inputValue.trim() == "") {
            this.$message("属性值不能为空");
            return;
          }
          //不能重复
          // every和some都可,some更合理一些
          let result = row.spuSaleAttrValueList.every((item) => {
            return item.saleAttrValueName != inputValue;
          });
          //或者不写{},也不用return
          // let result = row.spuSaleAttrValueList.every((item) => 
          //    item.saleAttrValueName != inputValue
          // );
          if (!result) {
            this.$message("属性值不能重复,请重新输入");
            return; //不执行
          }
    

    19 elementui模板请求数据

    import request from '@/utils/request'
    
    //获取SPU列表数据的接口  /admin/product/{page}/{limit}  get
    export const reqSpuList=(page,limit,category3Id)=>request({url:`/admin/product/${page}/${limit}`,method:'get',params:{category3Id}})
    
    
    //获取SPU信息  /admin/product/getSpuById/{spuId}  get
    export const reqSpu=(spuId)=>request({url:`/admin/product/getSpuById/${spuId}`,method:'get'})
    
    //获取品牌的信息  /admin/product/baseTrademark/getTrademarkList  get
    export const reqTradeMarkList=()=>request({url:'/admin/product/baseTrademark/getTrademarkList',method:'get'})
    
    
    //获取SPU图标的接口  /admin/product/spuImageList/{spuId}  get
    export const reqSpuImageList=(spuId)=>request({url:`/admin/product/spuImageList/${spuId}`,method:'get'})
    
    
    //获取平台全部销售属性(3个)  /admin/product/baseSaleAttrList  get  颜色,版本,尺码
    export const reqBaseSaleAttrList=()=>request({url:'/admin/product/baseSaleAttrList',method:'get'})
    
    //保存spu数据  修改或者添加 ,携带的参数大致相同,唯一的区别是携带的参数是否带id /admin/product/saveSpuInfo 
    export const reqAddOrUpdateSpu=(supInfo)=>{
        //有参数,修改
        if(supInfo.id){
            return request({url:`/admin/product/updateSpuInfo`,method:'post',data:supInfo})
        }else{
            //无参数,添加
            return request({url:`/admin/product/saveSpuInfo`,method:'post',data:supInfo})
        }
    }
    

    20 在main.js中引入接口和组件等总结

    //引入相关接口API
    import API from '@/api';
    //(组件实例的原型的原型指向的是Vue.prototype)放在原型上,任意组件都可使用API相关的接口
    Vue.prototype.$API=API;
    
    //注册全局组件
    import CategorySelete from '@/components/CategorySelect'
    Vue.component(CategorySelete.name,CategorySelete)
    
    //element分页组件汉化
    import zhLocale from 'element-ui/lib/locale/lang/zh-CN'  //引入中文版
    Vue.use(ElementUI,{zhLocale})
    
    //引入HintButton组件
    import HintButton from '@/components/HintButton'
    Vue.component(HintButton.name,HintButton)
    

    21 map 映射,可以把已有的数组数据通过return一个新数组

    map()方法定义在JavaScript的Array中,它返回一个新的数组,数组中的元素为原始数组调用函数处理后的值。
    注意:

    map()不会对空数组进行检测
    map()不会改变原始数组

    22 取消按钮,清除数据的方法

        cancel(){
         //点击取消按钮,清除数据
         // Object.assign:es6中新增的方法,可以合并对象
         //组件实例this._data可以操作data当中的响应式数据
         //his.$options可以获取配置对象,配置对象的data函数执行,返回的响应式数据为空的
         Object.assign(this._data,this.$options.data())
         console.log(this._data,this.$options.data(),'this.$options');
        },
    

    23 删除某一页数据列表时,当也数据删除完毕之后,自动返回都上一页

      <el-table :data="records" style="width: 100%" border>
              <el-table-column
                align="center"
                type="index"
                prop="prop"
                label="序号"
                width="80"
              >
              </el-table-column>
      </el-table>
        //删除spu
        async deleteSpu(row) {
          let result = await this.$API.spu.reqDeleteSpu(row.id);
          console.log(result, "888888");
          if (result.code == 200) {
            this.$message({ type: "success", message: "删除成功" });
            this.getSpuList(this.records.length>1?this.page:this.page-1);
          }
        },
    

    24 form表单中海油form

    在这里插入图片描述

     <el-form-item label="平台属性">
            <el-form :inline="true" ref="form" label-width="80px">
              <el-form-item label="屏幕尺寸">
                <el-select  placeholder="请选择" value="value">
                  <el-option label="label" value="value"></el-option>
                  <el-option label="label" value="value"></el-option>
                </el-select>
              </el-form-item>
              <el-form-item label="无线通信">
                <el-select  placeholder="请选择" value="value">
                  <el-option label="label" value="value"></el-option>
                  <el-option label="label" value="value"></el-option>
                </el-select>
              </el-form-item>
            </el-form>
          </el-form-item>
    

    25 获取的数据中不含有某个参数,这个参数需要收集,以后传给服务器

    收集的过程中进行添加,不能放在收集的图片列表中,因为table列表时复选框,选中后才有

          //获取图片
          let result = await this.$API.sku.reqSpuImageList(spu.id);
          if (result.code == 200) {
            //整理参数,result中午isDefault,循环添加
            let list = result.data;
            list.forEach(item => {
              item.isDefault=0  //0代表设置默认   1代表默认
            });
            this.spuImageList=list
          }
    

    26 可以在获取的数据中通过一下形式收集参数

    v-model="attr.attrIdAndValueId"是定义的

     <el-form-item label="平台属性">
            <el-form :inline="true" ref="form" label-width="80px">
              <el-form-item
                :label="attr.attrName"
                v-for="(attr, index) in attrInfoList"
                :key="attr.id"
              >
                <el-select placeholder="请选择" v-model="attr.attrIdAndValueId">
                  <el-option
                    :label="attrVal.valueName"
                    :value="`${attrVal.id}:${attrVal.id}`"
                    v-for="(attrVal, index) in attr.attrValueList"
                    :key="attrVal.id"
                  ></el-option>
                </el-select>
              </el-form-item>
            </el-form>
          </el-form-item>
    

    27 如何把获取到的部分数据添加到收集(上传服务器所需要的参数)的数据里面 foreach和reduce都可以

          save() {
          //整理收集数据
          //平台属性
    
          //第一种方法
          // const {skuInfo,attrInfoList}=this
          // let arr = [];
          // attrInfoList.forEach((item) => {
          // 当前用户是否进行了选择
          //   if (item.attrIdAndValueId) {
          //     const [attrId, valueId] = item.attrIdAndValueId.split(":");
          //     let obj = {valueId,attrId };
          //     arr.push(obj);
          //   }
          // });
          // skuInfo.skuAttrValueList=arr
    
          //第二种方法
          const {attrInfoList,skuInfo}=this
          skuInfo.skuAttrValueList=attrInfoList.reduce((prev, item) => {
            //prev初始值[]
            if (item.attrIdAndValueId) {
              const [attrId, valueId] = item.attrIdAndValueId.split(":");
              prev.push({attrId, valueId})
            }
            return prev
          }, []);
        },
    

    28 获取列表数据,分页加载

        // 获取到的spu数据
        async getSpuList(pager = 1) {
          this.page = pager;
          const { page, limit, category3Id } = this;
    
          let result = await this.$API.spu.reqSpuList(page, limit, category3Id);
          if (result.code == 200) {
            this.records = result.data.records;
            this.total = result.data.total;
          }
        },
    

    29 深度选择器

    在这里插入图片描述

    30 在boot cdn找依赖包

    31 安装echarts

    npm install --save echarts
    

    32 map()

                if (res.result) {
                  res.result.map((item) => {
                    const dataObj = {
                      name: "",
                      value: [],
                    };
                    dataObj.name = item.tag;
                    dataObj.value[0] = item.decisionVal;
                    dataObj.value[1] = item.loadVal;
                    dataObj.value[2] = item.situationVal;
                    dataObj.value[3] = item.factorVal;
                    dataObj.value[4] = item.communicationVal;
                    dataObj.value[5] = item.processVal;
                    dataObj.value[6] = item.skillVal;
                    dataObj.value[7] = item.applyVal;
                    that.radarData.push(dataObj);
                  });
                }
    
    更多相关内容
  • 最近在开发管理系统时遇到了任何管理系统都会有的需求—权限控制,之前也遇到过这种需求,但是架构不完善导致的各种问题使得后期维护非常麻烦,这一次的方案解决了之前的种种问题,现做一次记录,当然这个架构后期...
  • vue后台管理知识点、难点总结02 1 elementui分页组件封装(drm) 2 查询和重置(drm) 3 弹出框 message,message,confirm,$notify 4 校验 5 点击删除(尚食品) 6 scoped使用 7 复制快捷键:shift+alt+向下3箭头 8 ...

    1 elementui分页组件封装(drm)

    封装:

    <template>
      <el-row style="margin-top: 30px">
        <el-col :span="14" :offset="10">
          <div class="block">
              <!-- :page-sizes="[10, 20, 30, 40]" -->
            <el-pagination
              background
              :current-page="currentPage"
              :page-sizes="pageSizes"
              :page-size="pageSize"
              layout="total, sizes, prev, pager, next, jumper"
              :total="total"
              @size-change="handleSizeChange"
              @current-change="handleCurrentChange"
            />
          </div>
        </el-col>
      </el-row>
    </template>
    <script>
    export default {
      // props: ['total', 'pageSize', 'currentPage'],
      props: {
        currentPage: { 
          type: [String, Number],
          default: 1,
        },
        total: {
          type: [String, Number],
          default: 0,
        },
        pageSizes: {
          type: Array,
          default: () => [10, 15, 30, 50],
        },
        pageSize: {
          type: [String, Number],
          default: 10,
        },
        // prev表示上一页,next为下一页,pager表示页码列表,jumper表示跳页元素,total表示总条目数,size用于设置每页显示的页码数量
        // total, sizes, prev, pager, next, jumper
        // layout: {
        //   type: String,
        //   default: "total, sizes, prev, pager, next, jumper",
        // },
      },
      data() {
        return {};
      },
      methods: {
        handleSizeChange(val) {
          console.log(`每页 ${val}`);
          this.$emit("sizeChange", val);
        },
        handleCurrentChange(val) {
          console.log(`当前页: ${val}`);
          this.$emit("pagination", val);
        },
      },
    };
    </script>
    
    

    引用:

     <pagination
          :total="total"
          :page-size.sync="params.pageSize"
          :current-page.sync="params.pageNo"
          :page-sizes="[5, 10, 15, 20]"
          @sizeChange="handleSizeChange"
          @pagination="getBaseData"
     />
    
    //data数据
    params: {
            pageNo: 1,
            pageSize: 10,
          },
      total: 0,
     // js  每页多少条
     handleSizeChange(newSize){
        this.params.pageSize=newSize
        this.getBaseData()
      },
    

    2 查询和重置(drm)

     <el-form-item>
          <el-button type="primary" @click="searchFn">查询</el-button>
          <el-button type="defaul" @click="resetFn">重置</el-button>
     </el-form-item>
    // 查询
        searchFn(val) {
          val ? (this.params.pageNo = 1) : null;
          listUser(this.params).then((res) => {
            console.log(res, 123456789);
            this.tableData = res.result.list;
            this.total = res.result.total;
            this.params.pageSize = res.result.size;
            this.params.pageNo = res.result.current;
          });
        },
        // 查询重置
        resetFn() {
          this.params = {};
          this.getBaseData();
        },
    

    3 弹出框 m e s s a g e , message, message,confirm,$notify

    提交–$notify

      //点击提交-修改密码
        submitEditPws() {
          //  if(this.pswForm.lgPasswd==this.pswForm.checklgPasswd &&this.pswForm.lgPasswd!=''&&this.pswForm.checklgPasswd!=''){}
          this.$refs.pswForm.validate((valid) => {
            if (valid) {
              this.pswForm.userId = this.pswUserId;
              updatePasswd(this.pswForm)
                .then((data) => {
                  this.$notify({
                    title: data.success ? "成功" : "失败",
                    message: data.message,
                    type: data.success ? "success" : "error",
                    duration: 2000,
                  });
                  // location.reload()
                  this.getBaseData();
                })
                .catch((err) => {
                  console.log("提交失败", err);
                });
            } else {
              console.log("error submit!!");
              return false;
            }
          });
        },
    

    删除 confirm和message

        // 点击编辑和删除
        getEdit(row, remove) {
          console.log(row, "编辑-获取的信息");
          this.form = Object.assign({}, row);
          this.form.orgObj = {
            orgCode: row.orgCode,
            orgId: row.orgId,
            orgName: row.orgName,
          };
          // this.form = Object.assign({},this.form, row);
          if (remove) {
            this.open(row.userId);
          } else {
            this.dialogStatus = "update";
            this.creatDialogVisible = true;
            this.disabledShow = false;
          }
        },
    // 删除弹窗提醒
        open(id) {
          this.$confirm("此操作将永久删除该文件, 是否继续?", "提示", {
            confirmButtonText: "确定",
            cancelButtonText: "取消",
            type: "warning",
          })
            .then(() => {
              this.removeData(id);
            })
            .catch(() => {
              this.$message({
                type: "info",
                message: "已取消删除",
              });
            });
        },
        // 删除数据
        removeData(uid) {
          const uidData = {};
          uidData.uid8 = uid;
          deleteUser(uidData).then((data) => {
            this.$notify({
              title: data.success ? "成功" : "失败",
              message: data.message,
              type: data.success ? "success" : "error",
              duration: 2000,
            });
            // location.reload()
            this.getBaseData();
          });
        },
    

    4 校验

        // 保存-创建数据
        createData() {
          this.$refs.form.validate((valid) => {
            if (valid) {
              this.form.orgCode = this.form.orgObj.orgCode;
              this.form.orgName = this.form.orgObj.orgName;
              this.form.orgId = this.form.orgObj.orgId;
              createUser(this.form)
                .then((data) => {
                  console.log(data, "创建的数据结果");
                  this.creatDialogVisible = false;
                  this.$notify({
                    title: data.success ? "成功" : "失败",
                    message: data.message,
                    type: data.success ? "success" : "error",
                    duration: 2000,
                  });
                  // location.reload()
                  this.getBaseData();
                })
                .catch((err) => {
                  console.log("提交失败", err);
                });
            } else {
              console.log("error submit!!");
              return false;
            }
          });
        },
    

    5 点击删除(尚食品)

        //点击删除
        deleteTradeMark(row) {
          this.$confirm(`是否删除${row.tmName}?品牌名称`, "提示", {
            confirmButtonText: "确定",
            cancelButtonText: "取消",
            type: "warning",
          })
          // 点击删除的确定按钮
            .then(async () => {
              let result = await this.$API.trademark.reqDeleteTradeMark(row.id);
              console.log(result, 777);
              if (result.code == 200) {
                this.$message({
                  type: "success",
                  message: "删除成功!",
                });
                this.getPageList(this.list.length > 1 ? this.page : this.page - 1);
              }
            })
            // // 点击删除的取消按钮
            .catch(() => {
              this.$message({
                type: "info",
                message: "已取消删除",
              });
            });
        },
    

    6 scoped使用

    组件内,如果style有scoped,需要使用深度选择器,没有的话不用加

    7 复制快捷键:shift+alt+向下3箭头

    8 tabs 清除浮动

    <div slot="header" class="clearfix">
        <span>卡片名称</span>
        <el-button style="float: right; padding: 3px 0" type="text">操作按钮</el-button>
    </div>
    
    .clearfix:before,
      .clearfix:after {
        display: table;
        content: "";
      }
      .clearfix:after {
        clear: both
      }
    

    9 computed属性应用

    切换不同页面的标题,可用到computed

      computed: {
        //计算属性-标题
        title() {
          return this.activeName == "sale" ? "销售额" : "访问量";
        },
      },
    

    在这里插入图片描述

      <h3>门店{{title}}排行</h3>
    
      computed:{
        //计算属性-标题
        title(){
          return this.activeName=='sale'?'销售':'访问量'
        }
      },
    

    10 watch应用

    首先,tabs切换,可用组件的方法handleClick(tab, event) {}实现title的切换,如下图
    在这里插入图片描述

    在这里插入图片描述
    用watch的话,如下

      //监听属性
      watch:{
        title(){
          //重新修改图表的配置数据
          this.mycharts.setOption({
            title:{
              text:this.title+'趋势',
            },
          })
        },
      },
    

    在这里插入图片描述

    11 日期插件 day.js和moment都可

    项目中安装

    npm install --save dayjs
    

    项目中引入

    import * as dayjs from "dayjs";
    

    在这里插入图片描述
    点击今日,本周,本月,本年的函数(参考dayjs官网)

        setDay() {
          const day = dayjs().format("YYYY-MM-DD");
          this.date = [day, day];
        },
        setWeek() {
          const start = dayjs().day(1).format("YYYY-MM-DD");
          const end = dayjs().day(7).format("YYYY-MM-DD");
          this.date = [start, end];
        },
        setMonth() {
          const start = dayjs().startOf("month").format("YYYY-MM-DD");
          const end = dayjs().endOf("month").format("YYYY-MM-DD");
          this.date = [start, end];
        },
        setYear() {
          const start = dayjs().startOf("year").format("YYYY-MM-DD");
          const end = dayjs().endOf("year").format("YYYY-MM-DD");
          this.date = [start, end];
        },
    

    12 echarts报错:echarts.js?1be7:2286 Can’t get DOM width or height,不显示图标

     <div class="charts" ref="charts"></div>
    
    
    //初始化echarts实例
        let lineCharts = echarts.init(this.$refs.charts);
        //配置数据
        lineCharts.setOption({})
    
    
    .charts {
      width: 100%;
      height: 100%;
    }
    

    原因是我把高度用百分数%表示,改为px就出现了。

    如果容器的height/width属性设置为百分比的形式,那么echarts就会warning,且不能正常的生成图表。所以div容器的高度宽度必须指定为px。

    如果非要用100%,怎么实现?

    <div class="charts" ref="charts" style="height:100%;width:100%;"></div>
    

    有警告,但是图片显示了。

    展开全文
  • vue后台管理知识点、难点总结04(权限管理)

    vue后台管理知识点、难点总结04--权限管理

    1 权限管理:

    用户管理,角色管理,菜单管理,角色授权,

    用户管理:

    角色管理:

    角色授权:

    菜单管理:

    设置路由:router->index
      //权限管理
      {
        name: 'Acl',
        path: '/acl',
        component: Layout,
        redirect: '/acl/user/list',
        meta: {
          title: '权限管理',
          icon: 'el-icon-lock'
        },
        children: [
          {
            name: 'User',
            path: 'user/list',
            component: () => import('@/views/acl/user/list'),
            meta: {
              title: '用户管理',
            },
          },
          {
            name: 'Role',
            path: 'role/list',
            component: () => import('@/views/acl/role/list'),
            meta: {
              title: '角色管理',
            },
          },
          {
            name: 'RoleAuth',
            path: 'role/auth/:id',
            component: () => import('@/views/acl/role/roleAuth'),
            meta: {
              activeMenu: '/acl/role/list',
              title: '角色授权',
            },
            hidden: true,
          },
          {
            name: 'Permission',
            path: 'permission/list',
            component: () => import('@/views/acl/permission/list'),
            meta: {
              title: '菜单管理',
            },
          },
        ]
      },
    

    写相应的请求路由:api->acl,再倒入到api->index中

    import * as trademark from './product/tradeMark' 
    import * as attr from './product/attr' 
    import * as spu from './product/spu' 
    import * as sku from './product/sku' 
    
    
    //引入权限相关的接口文件
    import * as user from './acl/user' //分开export
    import role  from './acl/role'  //export default {}
    import permission from './acl/permission'
    
    //对外暴露
    export default{
        trademark,
        attr,
        spu,
        sku,
        user,
        role,
        permission,
    }
    

    在相应的组件内写静态页面和js
    注意:发请求一般是在mounted中,也可以在created内

    注意: 登录@click事件

    <el-button :loading="loading" type="primary" style="width:100%;margin-bottom:30px;" @click.native.prevent="handleLogin">登录</el-button>
    
    

    2 菜单权限分析

    在这里插入图片描述

    3 按钮权限分析

    在这里插入图片描述

    <template>
      <div>
          <el-button type="primary" v-show="$store.state.user.buttons.indexOf('btn.Add1')!=-1">添加按钮1</el-button>
          <el-button type="primary" v-show="$store.state.user.buttons.indexOf('btn.Add2')!=-1">添加按钮2</el-button>
      </div>
    </template>
    
    展开全文
  • 【精品课】Vue.js实现电商后台管理系统(企业项目实战).zip,【精品课】Vue.js实现电商后台管理系统(企业项目实战)-20201203224615305.zip
  • Vue后台管理项目总结

    2022-08-31 22:25:51
    vue2后台管理界面项目总结

    前期准备:创建vue脚手架,配置文件,下载第三方ui库、axios、each等

    技术栈:Vue、elementui、axios、each

    项目组合:项目主要由: 登录模块,用户管理模块、权限管理、角色列表、商品管理、订单列表、可视化图标 each 数据统计、等几个模块。

            在项目启动前,先配置封装一下baseurl基地址接口路径,设置一下timeout超时时间,在通过axios 中的拦截器进行在网络请求和响应之后的一些操作,我们通过新建一个until文件夹,在里面新建一个request.js文件,在里面导入第三方axios,在配置基地址后通过 axios.interceptors 来设置拦截器,在请求拦截器中通过config.headers的 Authorization 配置一下请求头才能进入首页的token值,然后再响应拦截器中设置一下token值过期的处理,让用户去login页面去重新登录、再对一下常规的过期状态码进行处理和提示。

    登录模块

     通过创建一个login.vue组件,在里面引入element的form表单,通过这个点击登录事件,拿到这个表单中的用户名和密码,在通过引入封装的api接口进行发起网络请求,通过后台返回的状态码进行判断是否登录成功,成功的话就会返回一个token,将这个token存储到本地或者是vuex状态管理工具里面,在封装的网络请求中进行拿取这个token值放到请求头中,因为接下来的操作都需要依赖于这个token值,这样就可以不用在每次请求的时候都要写,显得冗余。

    菜单权限

            菜单是通过登录的用户,后段返回的数据,进行使用rouer.routes动态路径的方式进行实现,是根据登录的用户不同,超级管理员会给他们一些权限,登录的时候会拿到这个这个菜单列表,在通过ui库中的menus导航来进行循环输入。

     

    登录鉴权

            登录鉴权是通过路由守卫来实现的,我使用的时候路由的前置守卫(beforeEach)来进行判断状态管理工具中或者本地中是否有token值,没有的话,就强制让他去登录界面。

    用户管理模块

     用户模块的表格结构通过引入ui库中的<el-table>在data中进行配置tableData属性为一个数组,在onMounted钩子函数中请求用户列表的数据,在根据打印的data的数据进行赋值给tableData表格中的状态和操作表格的按钮需要使用<template>本行数据来设置,添加事件就是点击按钮后出现一个添加用户的模态框,在里面加入用户的姓名,邮箱之类的数据,点击确定发起网络请求,后端返回状态码判断是否添加成功 重新调用获取表格的数据。


     我觉得用户列表模块中相对于用户这个模块比较复杂的还是分配角色模块,它里面也就是一个下 select 拉框,v-mode绑定一个空的数据,在option中循环用户列表中拿到的数据,在属性value中进行赋值,然后再通过点击确定的事件判断他的value值,发送分配角色请求,给这个值带过去,后段返回分配成功字段。

    权限管理-角色列表

       角色列表中最大的难点莫过于分配权限和角色下面渲染了,这个分配权限主要还是在点击这个事件之后弹出一个模态框,里面引入一下ui库中的<el-tree>这个tree树型控件,在tree控件中绑定data数据,然后需要在tree树型控件中加入show-checkbox这个属性,因为这个树型控件默认是为false的,他的意思就是节点是否可以被选择,不加这个属性的话,使用的时候也无法被选中,在加入default-expanded-keys属性,译为选中的节点默认为展开的。因为发送树型控件的数据接口一般都是一个body体,就是个树型的数据,可以通过递归来判断里面的children是否还存在,直至判断到最后一层的id中的数据没有children的时候停止递归,在看树型控件是为全开还是半开,在vue2中可以直接使用this来拿到这个最后一层的id值,而在vue3中就不存在this指向了,就可以引入proxy,它里面可以访问到整个对象和原型,使用proxy.$refs.tree.数据数据.map来判断id是否相等,最后给它强转为字符串,在发送网络请求。改变用户的权限。

     商品管理-(商品列表)

     商品列表里面最麻烦的也是添加商品了,他不像其他组件那样直接模态框输入,传入就能加了,它是跳转了一个页面,需要在里面填入商品信息、级联菜单、商品属性、动态参数、上传商品图片、还有商品介绍的富文本。

      商品介绍的富文本我们可以直接下载组件

    这个步骤条是引入ui库中的 steps 通过设置里面的title属性页面中就可以显示基本信息、添加商品的这些文字,步骤条中通过添加 active 属性,绑定的是左侧tabs切换的下标,通过点击左侧的tabs给全局的activeIndex传过去当前的下标,给activeIndex绑定到步骤条的active属性上就可以实现点击tabs,已完成的功能。在基本信息中有个级联菜单,在级联菜单的事件中判断级联选中的是第几级,选中为第三级的时候才会拿到他的 id ,给这个id拿到商品参数和商品属性中,渲染

    上传图片

            上传图片是通过和 element ui 库结合的upload进行上传商品图片的的,通过upload中的 action 属性 属性中放置上传的图片地址,通过 on-success 属性 上传成功后的钩子函数,调用这个函数,使图片转换成二进制,传给后台,后端会拿到这个二进制文件再进行转换,成功的话会返回给前端一个data数据,一个是临时图片路径,一个是真实图片路径,临时图片会让前端自己查看,真实路径后端会存到数据库中,返回上传成功,提示用户.
     

     

    商品分类

    商品分类这里使用的是树形表格,添加分类设置弹出框,内有分类名称和父级名称,提交和取消按钮,下部的分页和之前一样,使用的ui组件,掉接口传pagenum和pagesize请求数据,每次只请求一页的数据,防止过于卡顿

     数据统计

     数据统计是通过第三方的 each第三方插件,下载,全局导入,根据each的实例,赋值代码,放到data数据中,比如说使用柱状图,通过融入 option 数据,在请求接口的时候,更改option里面data相对应的数据。

    总结:以上就是项目中所有模块的功能需求。本项目,是一个后台管理系统。采用前后端分离开发,主要用于给内部运营人员管理商 品用的。主要有登录模块、用户管理模块、权限管理模块、商品管理模块、数据统计等模块。

    展开全文
  • 一、阶段总结
  • 在这个项目中你有遇到什么技术难点,你是怎么解决的? 其实这个问题旨在了解你在遇到问题的时候的解决方法,毕竟现在前端技术领域广,各种框架和组件库层出不穷,而业务需求上有时纷繁复杂,观察一个程序员在面对...
  • 在广告机项目中,角色的权限管理是卡了挺久的一个难点。首先我们确定的权限控制分为两大部分,其中根据粒的大小分的更细: 接口访问的权限控制 页面的权限控制 菜单中的页面是否能被访问 页面中的按钮(增、删、...
  • 打包项目优化: 生成打包报告 ...方法1:通过vue-cli-service build --report命令生成 方法2:通过可视化vue-cli界面查看: 包括各模块体积大小,各资源加载所需时间。 2第三方库使用C...
  • 项目场景:VUE电商后台管理系统剩余模块的bug ` 在学习黑马前端的VUE电商后台管理系统时,老师所讲的内容已经基本完成了,但是项目剩下的一些功能还没有实现,在实现过程中出现了一些bug,不知道有没有小伙伴完成了...
  • 黑马vue电商后台管理系统总结

    千次阅读 2022-03-10 13:33:08
    vue电商后台管理系统-阶段总结 上个月把这个项目做完简单整理了一下文档,和大家交流分享一下 一、项目技术栈 前端 前端采用 vue cli 脚手架搭建框架,使用 element UI 美化项目结构 环境依赖(开发依赖,运行...
  • 在广告机项目中,角色的权限管理是卡了挺久的一个难点。首先我们确定的权限控制分为两大部分,其中根据粒的大小分的更细: 接口访问的权限控制 页面的权限控制 菜单中的页面是否能被访问 页面中的按钮(增、删、...
  • 1. 有个报错是在watch里判断如果一个值为true,就调用一个方法 ,方法定义过了,但是仍然报错此方法不是function,后来检查发现,包含关系错误 2. 打包的时候报错ELIFECYCLE,显示循环引用,删掉package-lock.json ...
  • 三、使用vue完成后台管理系统的(功能级)权限: 此处,还是以“后端处理权限的思路”,前端仅作功能权限的展示为例,进行描述。 使用vue-router的addRoutes来动态改变路由配置。 1、步骤 1)、默认路由配置里只有...
  • 后台管理项目 前后端分离,模块化开发后台系统。。。
  • VUE中如何实现后台管理系统的权限控制 在项目当中,角色的权限管理是卡了挺久的一个难点。首先我们确定的权限控制分为两大部分,其中根据粒的大小分的更细:1、接口访问的权限控制;2、页面的权限控制:①菜单中...
  • 后台,人力资源管理系统中,我们经常会遇到分配权限的技术,关于怎么分配权限就是一个难点,在这里,RBAC模型可以很好的解决这个问题 RBAC是什么? RBAC模型概述 RBAC模型(Role-Based Access Control:基于角色的...
  • vue-shop 1.Login.vue 1.1 通过token来控制登录成功后的行为 token的原理 将token保存在本地浏览器的sessionstorge中 在通过this.$router.push编程式导航实现跳转 this.$message.success("登录成功!"); //...
  • 基于vue搭建的后台管理系统

    万次阅读 多人点赞 2018-07-16 15:21:28
    小编推荐:Fundebug专注于JavaScript、微信小程序、微信小游戏,Node.js和Java实时BUG监控。...此项目是 vue2.0 + element-ui + node+mongodb 构建的后台管理系统,所有的数据都是从服务器实时获取...
  • token请求接口 说明:除了登录接口以外,其他接口都需要token才能够成功获取数据(此项目中) 因为这个首页接口是需要登录后才能访问的,所以需要将token作为请求头中的一个属性来传递给服务器,这样,服务器才知道...
  • 黑马程序员课程Vue实战项目_Element-ui——电商后台管理系统-权限管理制作
  • 整个管理系统使用的是element的标签页,使用keep-alive进行缓存,使用component来显示组件。所有的标签页都以组件的形式显示 component是一个占位符,:is属性可以用来指定要展示的组件名称 加v-if是因为我在写的...
  • vue后台管理知识点、难点总结03(vuex)
  • Vue后台管理项目踩坑

    2020-03-21 21:38:08
    最近跟着黑马前端视频在做vue后台管理项目。 下面这张图是利用element-ui渲染出来的级联选择器,但是它高度溢出了。 由于element-ui新的版本有一些bug,所以我们需要在全局样式中自定义高度。如下: .el-cascader-...
  • Vue电商后台管理系统项目第5篇-角色列表的增删改查&&角色授权
  • 在项目中,角色的权限管理是卡了挺久的一个难点。首先我们确定的权限控制分为两大部分,其中根据粒的大小分的更细: 接口访问的权限控制 页面的权限控制 菜单中的页面是否能被访问 页面中的...
  • vue外卖后台管理系统

    千次阅读 2021-01-15 19:55:27
    element-ui实现下拉菜单路由跳转总结 结构: <el-menu> // 一级菜单 (el-menu-item) <el-menu-item index="/dashboard"> ...template slot="title">...i class="iconfont icon-shouye"&...后台首页</

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,583
精华内容 633
关键字:

vue后台管理系统难点