精华内容
下载资源
问答
  • 基于 微信小程序 + springboot + vue 技术构建 ,支持单店铺,多店铺入驻的商城平台。项目包含 微信小程序管理后台。基于java后台语言,已功能闭环,且达到商用标准的一套项目体系。
  • 聚惠星商城 DTS-SHOP,基于 微信小程序 + springboot + vue 技术构建 ,支持单店铺,多店铺入驻的商城平台。项目包含 微信小程序管理后台。基于java后台语言,已功能闭环,且达到商用标准的一套项目体系。 技术栈 ...
  • 4.打开小程序则需要你有appid项目简介电商整套系统 pc商家管理后台 小程序客户端小程序端介绍1.商品模块功能:秒杀,算法推荐和猜你喜欢,收藏,sku选择,购物车,评论 ,会员2.活动模块功能:优惠套餐,商家推荐,...
  • vue+vant+weapp搭建小程序,以及打包发布 vue环境搭建 安装node:进入node官网下载与系统匹配的安装包完成安装 安装vue:查看官网教程完成安装 构建 weapp 打开 微信开发者工具 新建项目 2.打开 新建项目 ...

    vue+vant+weapp搭建小程序,以及打包发布

    vue环境搭建

    1. 安装node:进入node官网下载与系统匹配的安装包完成安装

    2. 安装vue:查看官网教程完成安装

    构建 weapp

    1. 打开 微信开发者工具 新建项目

    在这里插入图片描述

    2.打开 新建项目 根目录 下的 cmd命令编辑器
    在这里插入图片描述

    3.初始化项目

    (输入命令之后一直点回车)
    npm init 
    

    在这里插入图片描述

    4.安装 vant-weapp UI框架

     npm i @vant/weapp
    

    在这里插入图片描述

    5.设置 新建项目 使用npm模块

    在这里插入图片描述

    6.在 微信开发者工具
    在这里插入图片描述
    7.构建 vue + vant + weapp 小程序项目 完成

    在这里插入图片描述

    打包发布

    当小程序开发完毕后,我们需要把程序发布上去。

    1. 点击上传按钮,按提示操作,填入版本及描述,完成上次
      在这里插入图片描述
      在这里插入图片描述在这里插入图片描述
    2. 登录小程序账号,查看版本管理,可以看到我们提交的版本。在这里插入图片描述

    参考文档

    1.https://blog.csdn.net/weixin_46540977/article/details/104812315

    个人博客

    展开全文
  • JavaWeb_Vue_Pro 是基于 SpringBoot2+Vue+element-ui+Shiro+MybatisPlus 研发的权限(RBAC)及内容管理系统,致力于做更简洁的后台管理框架,包含系统管理、代码生成、权限管理、站点、广告、布局、字段、配置等一系列...

    项目介绍

    JavaWeb_Vue_Pro 是基于 SpringBoot2+Vue+element-ui+Shiro+MybatisPlus 研发的权限(RBAC)及内容管理系统,致力于做更简洁的后台管理框架,包含系统管理、代码生成、权限管理、站点、广告、布局、字段、配置等一系列常用的模块,整套系统一键生成所有模块(包括前端UI),一键实现CRUD,简化了传统手动抒写重复性代码的工作。 同时,框架提供长大量常规组件,如上传单图、上传多图、上传文件、下拉选择、复选框按钮、单选按钮,城市选择、富文本编辑器、权限颗粒度控制等高频使用的组件,代码简介,使用方便,节省了大量重复性的劳动,降低了开发成本,提高了整体开发效率,整体开发效率提交80%以上,JavaWeb框架专注于为中小企业提供最佳的行业基础后台框架解决方案,执行效率、扩展性、稳定性值得信赖,操作体验流畅,使用非常优化,欢迎大家使用及进行二次开发。

    开发者信息

    后台演示(用户名:admin 密码:123456)

    技术支持

    效果展示

    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

    展开全文
  • ​ 学生互动课堂系统,包含微信小程序、PC界面后台管理。采用前后端分离开发模式。模块interactiveClassUI,使用uni app、vue开发互动课堂微信小程序。模块interactiveClassAdminUi,基于vue admin tempalate 二次...
  • 这是一个结合线下的指纹出勤管理小程序 普通用户:在线下通过指纹出入房间,然后在小程序能看到自己的日志记录,可以看到在每个教室的日志记录,时长,还有排行榜记录等等,在这之前要实名认证(一般用学号密码)。 ...
  • 基于微信小程序的乐器(可通用)培训机构系统 前言:改项目作为毕设完全可以使用,同时可以作为实体培训机构商用,不过目前有些东西还不太全,比如支付接口(这个的话需要可以进行具体对接)、课程的付费模式等,...

    基于微信小程序的乐器(可通用)培训机构系统

    前言:改项目作为毕设完全可以使用,同时可以作为实体培训机构商用,不过目前有些东西还不太全,比如支付接口(这个的话需要可以进行具体对接)、课程的付费模式等,但是其他的整体流程已经开发好了。小程序端、小程序服务端、小程序后台、数据端、前后端的交互等,都已经可以使用。这篇博客分享,主要是为了帮助想独立开发小程序的朋友,已经一些需要定制小程序的商家。

    一、项目介绍

    微信小程序端:

        1、小程序端包含首页、产品、我的三个主模块。
        2、首页模块实现机构的课程列表、课程详情及课程学习,产品模块实现产品搜索、产品分类和详情,个人模块实现我的足迹、个人信息和我的课程。

    小程序服务端:

        1、实现对小程序功能的接口及业务逻辑支撑。
        2、对接数据端处理。

    Web后台管理端:

        1、实现对不同角色的权限管理,管理员以及普通用户操作权限分离。
        2、Web端管理实现对会员的管理。
        3、实现对课程的管理(课程录入、课程分类、章节管理等)
        4、Web端管理员实现对商场的关键词设置。
        5、实现对商品的管理(商品上架、品牌管理、类目管理、库存管理等)
        6、实现推广管理、一键运营,轻松设置广告banner。


    二、相关技术

        1、小程序采用小程序原生语言开发。
        2、小程序管理后台系统采用目前流行的前后端分离模式,前端使用Vue+ElementUI搭建后台管理界面。
        3、小程序服务端已经管理后台均采用Springboot+Mybatis实现。
        4、权限处理使用了Shiro框架实现。
        5、使用了lombok、SelectOneByExamplePlugin/ExampleEnhancedPlugin等插件。
        6、对于系统一些商品、课程的上传存储,目前实现了对接对地存储、阿里云对象存储、腾讯云对象存储、七牛云对象存储四种方式。


    三、系统结构


    在这里插入图片描述


    四、界面展示

    小程序端:

    首页(课程展示):在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    产品模块(产品展示、购买):
    在这里插入图片描述
    在这里插入图片描述
    我的模块:
    在这里插入图片描述
    Web后台管理端:

    管理登录页面:
    在这里插入图片描述
    所有模块菜单:

    在这里插入图片描述
    用户管理:
    在这里插入图片描述
    课程管理:

    在这里插入图片描述
    在这里插入图片描述
    商场关键词设置:

    在这里插入图片描述
    商品管理:

    在这里插入图片描述
    推广管理:

    在这里插入图片描述


    四、部分关键代码

    本系统前后陆陆续续用了2个多月,也是在边学习新技术,边上手做东西,真的是实际开发成品才会遇到一个又一个技术难关、一个又一个自己知识的盲区,还好坚持下来了~~

    小程序端,说两个页面的布局吧,一个是主页面的,一个是购物车页面。

    主页面 index.wxml:

    <!--index.wxml-->
    <view class="container">
    <!-- 搜索 -->
    <view class="search">
        <navigator url="/pages/search/search?source=course" class="input">
          <image class="icon"></image>
          <text class="txt">课程搜索, 共{{courseCount}}门课程</text>
        </navigator>
      </view>
      <!-- 活动轮播 -->
      <swiper class="banner" indicator-dots="true" autoplay="true" interval="3000" duration="1000">
        <swiper-item wx:for="{{banner}}" wx:key="id">
          <navigator url="{{item.link}}">
            <image src="{{item.url}}" background-size="cover"></image>
          </navigator>
        </swiper-item>
      </swiper>
      <!--快捷入口 -->
      <view class="fast_column">
          <navigator bindtap="openPage" class="item" data-url="/pages/courseList/courseList?type=hot">
            <!-- <image src="{{item.iconUrl}}" background-size="cover"></image>
            <text>{{item.name}}</text> -->
            <image src="/static/images/shortCut/hot_course.png" background-size="cover"></image>
            <text>热门课程</text>
          </navigator>
          <navigator bindtap="openPage" class="item" data-url="/pages/musicianStyle/index">
          <!-- <image src="{{item.iconUrl}}" background-size="cover"></image>
          <text>{{item.name}}</text> -->
           <image src="/static/images/shortCut/musician_style.png" background-size="cover"></image>
           <text>乐手风采</text>
         </navigator>
         <navigator class="item">
          <!-- <image src="{{item.iconUrl}}" background-size="cover"></image>
          <text>{{item.name}}</text> -->
           <image src="/static/images/shortCut/about_me.png" background-size="cover"></image>
          <text>关于我们</text>
        </navigator>
      </view>
      <!-- 体系课程 -->
      <view class="a-section a-type">
        <view class="h">
          <navigator url="">
            <text class="text"> — 体系课程系列 — </text>
          </navigator>
        </view>
        <view class="b">
          <view class="item item-1" wx:for="{{sysCatList}}" wx:key="id">
            <navigator url="/pages/courseList/courseList?id={{item.id}}">
              <view class="wrap">
                <image class="img" src="{{item.iconUrl}}" mode="aspectFill"></image>
                <view class="mt">
                  <text class="name">{{item.name}}</text>
                </view>
              </view>
            </navigator>
          </view>
        </view>
        <view class="h">
          <navigator url="" >
            <text class="text"> — 特色课程系列 — </text>
          </navigator>
        </view>
        <view class="b">
          <view class="item item-1" wx:for="{{feaCatList}}" wx:key="id">
            <navigator url="/pages/courseList/courseList?id={{item.id}}">
              <view class="wrap">
                <image class="img" src="{{item.iconUrl}}" mode="aspectFill"></image>
                <view class="mt">
                  <text class="brand">{{item.name}}</text>
                </view>
              </view>
            </navigator>
          </view>
      </view>
      </view>
    </view>
    

    购物车页面:cart.wxml

    <view class="container">
      <view class="no-login" wx:if="{{!hasLogin}}">
        <view class="c">
          <image src="http://nos.netease.com/mailpub/hxm/yanxuan-wap/p/20150730/style/img/icon-normal/noCart-a8fe3f12e5.png" />
          <text>还没有登录</text>
          <button style="background-color:#A9A9A9" bindtap="goLogin">去登录</button>
        </view>
      </view>
      <view class='login' wx:else>
        <view class="service-policy">
          <view class="item">30天无忧退货</view>
          <view class="item">48小时快速退款</view>
          <view class="item">满88元免邮费</view>
        </view>
        <view class="no-cart" wx:if="{{cartGoods.length <= 0}}">
          <view class="c">
            <image src="http://nos.netease.com/mailpub/hxm/yanxuan-wap/p/20150730/style/img/icon-normal/noCart-a8fe3f12e5.png" />
            <text>去添加点什么吧</text>
          </view>
        </view>
        <view class="cart-view" wx:else>
          <view class="list">
            <view class="group-item">
              <view class="goods">
                <view class="item {{isEditCart ? 'edit' : ''}}" wx:for="{{cartGoods}}" wx:key="id">
                  <view class="checkbox {{item.checked ? 'checked' : ''}}" bindtap="checkedItem" data-item-index="{{index}}"></view>
                  <view class="cart-goods">
                    <image class="img" src="{{item.picUrl}}"></image>
                    <view class="info">
                      <view class="t">
                        <text class="name">{{item.goodsName}}</text>
                        <text class="num">x{{item.number}}</text>
                      </view>
                      <view class="attr">{{ isEditCart ? '已选择:' : ''}}{{item.goodsSpecificationValues||''}}</view>
                      <view class="b">
                        <text class="price">¥{{item.price}}</text>
                        <view class="selnum">
                          <view class="cut" bindtap="cutNumber" data-item-index="{{index}}">-</view>
                          <input value="{{item.number}}" class="number" disabled="true" type="number" />
                          <view class="add" bindtap="addNumber" data-item-index="{{index}}">+</view>
                        </view>
                      </view>
                    </view>
                  </view>
                </view>
              </view>
            </view>
    
          </view>
          <view class="cart-bottom">
            <view class="checkbox {{checkedAllStatus ? 'checked' : ''}}" bindtap="checkedAll">全选({{cartTotal.checkedGoodsCount}})</view>
            <view class="total">{{!isEditCart ? '¥'+cartTotal.checkedGoodsAmount : ''}}</view>
            <view class='action_btn_area'>
              <view class="{{!isEditCart ? 'edit' : 'sure'}}" bindtap="editCart">{{!isEditCart ? '编辑' : '完成'}}</view>
              <view class="delete" bindtap="deleteCart" wx:if="{{isEditCart}}">删除({{cartTotal.checkedGoodsCount}})</view>
              <view class="checkout" bindtap="checkoutOrder" wx:if="{{!isEditCart}}">下单</view>
              <!-- </view>  -->
            </view>
          </view>
        </view>
      </view>
    </view>
    

    小程序服务端:

    首页Api:MiniHomeApi.java

    package com.code2life.course.mini.api;
    
    import com.code2life.course.core.util.ResponseUtil;
    import com.code2life.course.db.domain.MallCourseCategory;
    import com.code2life.course.db.service.MallAdService;
    import com.code2life.course.db.service.MallCourseCategoryService;
    import com.code2life.course.db.service.MallCourseChapterService;
    import com.code2life.course.db.service.MallCourseService;
    import com.code2life.course.mini.service.HomeCacheManager;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.validation.annotation.Validated;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    import java.util.ArrayList;
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    import java.util.concurrent.Callable;
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    import java.util.concurrent.FutureTask;
    
    /**
     * @author: wen
     * @date: 2019/11/20 10:50
     * @description: 小程序首页服务
     */
    @RestController
    @RequestMapping("/mini/home")
    @Validated
    public class MiniHomeApi {
    
    	@Autowired
    	private MallCourseCategoryService categoryService;
    	@Autowired
    	private MallCourseService courseService;
    	@Autowired
    	private MallCourseChapterService chapterService;
    	@Autowired
    	private MallAdService adService;
    
    	@GetMapping("/index")
    	public Object index(){
    
    		ExecutorService executorService = Executors.newFixedThreadPool(5);
    
    		Callable<List> bannerListCallable = () -> adService.queryIndex();
    
    		//体系课程
    		Callable<List> systemListCallable = null;
    		List<MallCourseCategory> systemList = categoryService.findL1ByMark("system");
    		if(systemList!=null && !systemList.isEmpty()){
    			Integer id = systemList.get(0).getId();
    			systemListCallable = () -> categoryService.queryByPid(id);
    		}else {
    			systemListCallable = () -> new ArrayList();
    		}
    
    		//特色课程
    		Callable<List> featureListCallable;
    		List<MallCourseCategory> featureList = categoryService.findL1ByMark("feature");
    		if(featureList!=null && !featureList.isEmpty()){
    			Integer id = featureList.get(0).getId();
    			featureListCallable = () -> categoryService.queryByPid(id);
    		}else {
    			featureListCallable = () -> new ArrayList();
    		}
    
    		FutureTask<List> bannerTask = new FutureTask<>(bannerListCallable);
    		FutureTask<List> sysCatTask = new FutureTask<>(systemListCallable);
    		FutureTask<List> feaCatTask = new FutureTask<>(featureListCallable);
    
    		executorService.submit(bannerTask);
    		executorService.submit(sysCatTask);
    		executorService.submit(feaCatTask);
    
    		Map<String, Object> entity = new HashMap<>();
    		try {
    
    			entity.put("banner", bannerTask.get());
    			entity.put("sysCatList", sysCatTask.get());
    			entity.put("feaCatList", feaCatTask.get());
    			//缓存数据
    			HomeCacheManager.loadData(HomeCacheManager.INDEX, entity);
    		}
    		catch (Exception e) {
    			e.printStackTrace();
    		}finally {
    			executorService.shutdown();
    		}
    		return ResponseUtil.ok(entity);
    	}
    }
    

    购物车订单处理API:MiniCourseOrderApi.java

    package com.code2life.course.mini.api;
    
    import com.code2life.course.mini.annotation.LoginUser;
    import com.code2life.course.mini.service.MiniCourserOrderService;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.validation.annotation.Validated;
    import org.springframework.web.bind.annotation.PostMapping;
    import org.springframework.web.bind.annotation.RequestBody;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    /**
     * @author: wen
     * @date: 2019/11/29 17:55
     * @description:
     */
    
    @RestController
    @RequestMapping("/mini/course/order")
    @Validated
    public class MiniCourseOrderApi {
    
    	@Autowired
    	private MiniCourserOrderService orderService;
    
    	/**
    	 * 订单提交
    	 * @param userId
    	 * @param body
    	 * @return
    	 */
    	@PostMapping("submit")
    	public Object submit(@LoginUser Integer userId, @RequestBody String body) {
    		return orderService.submit(userId, body);
    	}
    
    	/**
    	 * 付款订单的预支付会话标识
    	 *
    	 * @param userId 用户ID
    	 * @param body   订单信息,{ orderId:xxx }
    	 * @return 支付订单ID
    	 */
    	@PostMapping("prepay")
    	public Object prepay(@LoginUser Integer userId, @RequestBody String body, HttpServletRequest request) {
    		return orderService.prepay(userId, body, request);
    	}
    
    	/**
    	 * 微信付款成功或失败回调接口
    	 * <p>
    	 *  TODO
    	 *  注意,这里pay-notify是示例地址,建议开发者应该设立一个隐蔽的回调地址
    	 *
    	 * @param request 请求内容
    	 * @param response 响应内容
    	 * @return 操作结果
    	 */
    	@PostMapping("pay-notify")
    	public Object payNotify(HttpServletRequest request, HttpServletResponse response) {
    		return orderService.payNotify(request, response);
    	}
    }
    

    Web后台管理端:

    后台管理系统在线课程相关API:MallCourseApi.java

    package com.code2life.course.admin.api;
    
    import com.code2life.course.admin.dto.CourseAllinone;
    import com.code2life.course.admin.service.AdminCourseService;
    import com.code2life.course.core.util.ResponseUtil;
    import com.code2life.course.core.validator.Order;
    import com.code2life.course.core.validator.Sort;
    import com.code2life.course.db.domain.MallCourse;
    import io.swagger.annotations.Api;
    import org.apache.commons.logging.Log;
    import org.apache.commons.logging.LogFactory;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.validation.annotation.Validated;
    import org.springframework.web.bind.annotation.*;
    
    
    /**
     * @author: wen
     * @date: 2019/11/14 23:26
     * @description:
     */
    @RestController
    @RequestMapping("/mall/course")
    @Validated
    @Api(value = "后台管理系统在线课程相关API")
    public class MallCourseApi {
    
    	private final Log logger = LogFactory.getLog(MallCourseApi.class);
    
    	@Autowired
    	private AdminCourseService courseService;
    
    	@GetMapping("/list")
    	public Object list(String courseSn, String name,
    					   @RequestParam(defaultValue = "1") Integer page,
    					   @RequestParam(defaultValue = "10") Integer limit,
    					   @Sort @RequestParam(defaultValue = "add_time") String sort,
    					   @Order @RequestParam(defaultValue = "desc") String order) {
    		return courseService.list(courseSn, name, page, limit, sort, order);
    	}
    
    	@PostMapping("/delete")
    	public Object delete(@RequestBody MallCourse course) {
    		courseService.delete(course);
    		return ResponseUtil.vueOk();
    	}
    
    	@PostMapping("/add")
    	public Object create(@RequestBody CourseAllinone allinone) {
    		return courseService.add(allinone);
    	}
    
    	@GetMapping("/getRelatedList")
    	public Object getListCat(){
    		return courseService.relatedList();
    	}
    
    	@GetMapping("/getCourseById")
    	public Object getChapterNeed(Integer id) {
    		return courseService.getChapterNeed(id);
    	}
    
    	@GetMapping("/courseOption")
    	public Object courseOption(){
    		return courseService.courseOption();
    	}
    
    }
    

    后台管理系统商品相关API:MallGoodsApi.java

    package com.code2life.course.admin.api;
    
    import com.code2life.course.admin.dto.GoodsAllinone;
    import com.code2life.course.admin.service.AdminGoodsService;
    import com.code2life.course.core.validator.Order;
    import com.code2life.course.core.validator.Sort;
    import com.code2life.course.db.domain.MallGoods;
    import io.swagger.annotations.Api;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.validation.annotation.Validated;
    import org.springframework.web.bind.annotation.*;
    import javax.validation.constraints.NotNull;
    
    /**
     * @author: wen
     * @date: 2019/11/23 19:53
     * @description:
     */
    @RestController
    @RequestMapping("/mall/goods")
    @Validated
    @Api(value = "后台管理系统商品相关API")
    public class MallGoodsApi {
    
    	@Autowired
    	private AdminGoodsService goodsService;
    
    	@GetMapping("/list")
    	public Object list(String goodsSn, String GoodsName,
    					   @RequestParam(defaultValue = "1") Integer page,
    					   @RequestParam(defaultValue = "10") Integer limit,
    					   @Sort @RequestParam(defaultValue = "add_time") String sort,
    					   @Order @RequestParam(defaultValue = "desc") String order) {
    		return goodsService.list(goodsSn, GoodsName, page, limit, sort, order);
    	}
    
    	@GetMapping("/catAndBrand")
    	public Object list2() {
    		return goodsService.list2();
    	}
    
    	@PostMapping("/add")
    	public Object add(@RequestBody GoodsAllinone goodsAllinone) {
    		return goodsService.add(goodsAllinone);
    	}
    
    	@PostMapping("/update")
    	public Object update(@RequestBody GoodsAllinone goodsAllinone) {
    		return goodsService.update(goodsAllinone);
    	}
    
    	@PostMapping("/delete")
    	public Object delete(@RequestBody MallGoods goods) {
    		return goodsService.delete(goods);
    	}
    
    	@GetMapping("/detail")
    	public Object detail(@NotNull Integer id) {
    		return goodsService.detail(id);
    
    	}
    
    }
    

    Shiro登录系统验证:SysAuthorizingRealm.java

    package com.code2life.course.admin.shiro;
    
    import com.code2life.course.admin.util.Permission;
    import com.code2life.course.admin.util.PermissionUtil;
    import com.code2life.course.admin.vo.PermissionVo;
    import com.code2life.course.core.util.bcrypt.BCryptPasswordEncoder;
    import com.code2life.course.db.domain.SysRole;
    import com.code2life.course.db.domain.SysUser;
    import com.code2life.course.db.service.SysRoleService;
    import com.code2life.course.db.service.SysUserService;
    import org.apache.shiro.authc.*;
    import org.apache.shiro.authz.AuthorizationException;
    import org.apache.shiro.authz.AuthorizationInfo;
    import org.apache.shiro.authz.SimpleAuthorizationInfo;
    import org.apache.shiro.realm.AuthorizingRealm;
    import org.apache.shiro.subject.PrincipalCollection;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.context.ApplicationContext;
    import org.springframework.util.Assert;
    import org.springframework.util.StringUtils;
    
    import java.util.ArrayList;
    import java.util.HashSet;
    import java.util.List;
    import java.util.Set;
    
    /**
     * @author: wen
     * @date: 2019/11/5 15:14
     * @description: Shiro登录系统验证
     */
    public class SysAuthorizingRealm extends AuthorizingRealm {
    
    	@Autowired
    	private SysUserService sysUserService;
    	@Autowired
    	private SysRoleService sysRoleService;
    
    	@Autowired
    	private ApplicationContext context;
    	private List<PermissionVo> allPermissions = null;
    	private Set<String> allPermissionsString = null;
    
    	private List<PermissionVo> getSystemPermissions() {
    		final String basicPackage = "com.code2life.course.admin";
    		if (allPermissions == null) {
    			List<Permission> permissions = PermissionUtil.listPermission(context, basicPackage);
    			allPermissions = PermissionUtil.listPermVo(permissions);
    			allPermissionsString = PermissionUtil.listPermissionString(permissions);
    		}
    		return allPermissions;
    	}
    
    
    	@Override
    	protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals){
    		System.out.println("------------用户授权开始------------");
    		if (principals == null) {
    			throw new AuthorizationException("PrincipalCollection method argument cannot be null.");
    		}
    		SysUser user = (SysUser) getAvailablePrincipal(principals);
    		//存放角色对象
    		List<SysRole> roles = new ArrayList<>();
    		//存放角色名称
    		Set<String> roleNames = new HashSet<String>();
    		//存放用户的权限信息
    		Set<String> permissions = new HashSet<String>();
    		roles = sysRoleService.findByUsercode(user.getUsercode());
    		for(SysRole role : roles){
    			roleNames.add(role.getName());
    			//判断是否有超级权限,有需要转换成所有权限
    			if(sysRoleService.checkSuperPermission(role.getId())){
    				getSystemPermissions();
    			}
    		}
    		//拥有超级权限
    		if(allPermissionsString!=null && !allPermissionsString.isEmpty()) {
    			permissions = allPermissionsString;
    		}else{
    			//查询拥有角色的权限
    			for(SysRole role : roles) {
    				Set<String> perms = sysRoleService.queryPermissionByRoleId(role.getId());
    				permissions.addAll(perms);
    			}
    		}
    		//通过用户账号获取用户的所有资源,并把资源存入info中
    		SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
    		info.addRoles(roleNames);
    		info.addStringPermissions(permissions);
    		System.out.println("------------用户授权结束------------");
    
    		return info;
    	}
    
    	@Override
    	protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
    		System.out.println("------------用户认证开始------------");
    		//将AuthenticationToken转换为UsernamePasswordToken,token中存储着用户输入的账号和密码
    		UsernamePasswordToken upToken = (UsernamePasswordToken)token;
    		//获取用户账号和密码
    		String usercode = upToken.getUsername();
    		String password = new String(upToken.getPassword());
    
    		if (StringUtils.isEmpty(usercode)) {
    			throw new AccountException("用户名不能为空");
    		}
    		if (StringUtils.isEmpty(password)) {
    			throw new AccountException("密码不能为空");
    		}
    		List<SysUser> list = sysUserService.findByUsercode(usercode);
    		if(list==null || list.isEmpty()){
    			//账号不存在
    			throw new UnknownAccountException("账号不存在");
    		}
    		Assert.state(list.size() < 2, "同一个用户名存在两个账户");
    		SysUser user = list.get(0);
    		BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
    		if (!encoder.matches(password, user.getPassword())) {
    			throw new UnknownAccountException("找不到用户(" + usercode + ")的帐号信息");
    		}
    
    		SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user, password, getName());
    		System.out.println("------------用户认证结束------------");
    		return info;
    	}
    }
    

    Web后台系统前端Vue部分:

    后台课程管理首页:index.vue

    <template>
      <div class="app-container">
        <!-- 查询和其他操作 -->
        <div class="filter-container">
          <el-input v-model="listQuery.courseSn" clearable class="filter-item" style="width: 200px;" placeholder="请输入编号"/>
          <el-input v-model="listQuery.name" clearable class="filter-item" style="width: 200px;" placeholder="支持名称模糊搜索"/>
          <el-button class="filter-item" type="primary" icon="el-icon-search" @click="handleFilter">搜索</el-button>
          <el-button class="filter-item" type="primary" icon="el-icon-edit" @click="handleCreate">添加</el-button>
        </div>
        <!-- 查询结果 -->
        <el-table v-loading="listLoading" :data="list" element-loading-text="正在查询中。。。" border fit highlight-current-row row-key="id">
        <el-table-column type="expand">
          <template slot-scope="props">
            <el-form label-position="left" class="table-expand">
              <el-form-item label="宣传画廊">
                <img v-for="pic in props.row.gallery" :key="pic" :src="pic" class="gallery">
              </el-form-item>
              <el-form-item label="商品介绍">
                <span>{{ props.row.brief }}</span>
              </el-form-item>
              <el-form-item label="关键字">
                <span>{{ props.row.keywords }}</span>
              </el-form-item>
              <el-form-item label="类目ID">
                <span>{{ props.row.categoryId }}</span>
              </el-form-item>
            </el-form>
          </template>
        </el-table-column>
    
        <el-table-column align="center" label="课程编号" prop="courseSn"/>
    
        <el-table-column align="center" min-width="100" label="名称" prop="name"/>
    
        <el-table-column align="center" property="iconUrl" label="图片">
          <template slot-scope="scope">
            <img :src="scope.row.iconUrl" width="40">
          </template>
        </el-table-column>
    
        <el-table-column align="center" label="详情" prop="detail">
          <template slot-scope="scope">
            <el-dialog :visible.sync="detailDialogVisible" title="课程详情">
              <div v-html="courseDetail"/>
            </el-dialog>
            <el-button type="primary" size="mini" @click="showDetail(scope.row.detail)">查看</el-button>
          </template>
        </el-table-column>
    
        <el-table-column align="center" label="课程价格" prop="cPrice"/>
    
        <el-table-column align="center" label="是否新品" prop="isNew">
          <template slot-scope="scope">
            <el-tag :type="scope.row.isNew ? 'success' : 'error' ">{{ scope.row.isNew ? '新品' : '非新品' }}</el-tag>
          </template>
        </el-table-column>
    
        <el-table-column align="center" label="是否热品" prop="isHot">
          <template slot-scope="scope">
            <el-tag :type="scope.row.isHot ? 'success' : 'error' ">{{ scope.row.isHot ? '热门' : '普通' }}</el-tag>
          </template>
        </el-table-column>
    
        <el-table-column align="center" label="操作" width="300" class-name="small-padding fixed-width">
          <template slot-scope="scope">
            <el-button type="primary" size="small" @click="handleChapter(scope.row)">章节录入</el-button>
            <el-button type="primary" size="mini" @click="handleUpdate(scope.row)">编辑</el-button>
            <el-button type="danger" size="mini" @click="handleDelete(scope.row)">删除</el-button>
          </template>
        </el-table-column>
        </el-table>
    
        <pagination v-show="total>0" :total="total" :page.sync="listQuery.page" :limit.sync="listQuery.limit" @pagination="getList" />
    
        <el-tooltip placement="top" content="返回顶部">
          <back-to-top :visibility-height="100" />
        </el-tooltip>
      </div>
    
    </template>
    <script>
    import { listCourse, deleteCourse } from '@/api/course'
    import BackToTop from '@/components/BackToTop'
    import Pagination from '@/components/Pagination' // Secondary package based on el-pagination
    export default {
      name: 'Course',
      components: { BackToTop, Pagination },
      data() {
        return {
          list: [],
          total: 0,
          listLoading: true,
          listQuery: {
            page: 1,
            limit: 10,
            courseSn: undefined,
            name: undefined,
            sort: 'add_time',
            order: 'desc'
          },
          courseDetail: '',
          detailDialogVisible: false
        }
      },
      created() {
        this.getList()
      },
      methods: {
        getList() {
          this.listLoading = true
          listCourse(this.listQuery).then(response => {
            this.list = response.data.list
            this.total = response.data.total
            this.listLoading = false
          }).catch(() => {
            this.list = []
            this.total = 0
            this.listLoading = false
          })
        },
        handleFilter() {
          this.listQuery.page = 1
          this.getList()
        },
        showDetail(detail) {
          this.courseDetail = detail
          this.detailDialogVisible = true
        },
        handleCreate() {
          this.$router.push({ path: '/course-management/createCourse' })
        },
        handleChapter(row) {
          const data = row
          this.$router.push({ name: 'ChapterAdd', params: { id: data.id }})
        },
        handleUpdate(row) {
          this.$notify.warning({
            title: '警告',
            message: '该功能暂未开放',
            duration: 2000
          })
          // this.$router.push({ path: '/goods/edit', query: { id: row.id }})
        },
        handleDelete(row) {
          deleteCourse(row).then(response => {
            this.$notify.success({
              title: '成功',
              message: '删除成功'
            })
            const index = this.list.indexOf(row)
            this.list.splice(index, 1)
          }).catch(response => {
            this.$notify.error({
              title: '失败',
              message: response.msg
            })
          })
        }
      }
    }
    </script>
    
    <style scoped>
      .table-expand {
        font-size: 0;
      }
      .table-expand label {
        width: 100px;
        color: #99a9bf;
      }
      .table-expand .el-form-item {
        margin-right: 0;
        margin-bottom: 0;
      }
      .gallery {
        width: 80px;
        margin-right: 10px;
      }
    </style>
    

    Vue菜单路由:index.js

    import Vue from 'vue'
    import Router from 'vue-router'
    
    Vue.use(Router)
    
    /* Layout */
    import Layout from '@/layout'
    
    /* Router Modules */
    import sysSettingRouter from './modules/sysSetting'
    import courserRouter from './modules/course'
    import goodsRouter from './modules/goods'
    import mallUserRouter from './modules/mallUser'
    import promotionRouter from './modules/promotion'
    import mallSettingRouter from './modules/mallSetting'
    /**
     * Note: sub-menu only appear when route children.length >= 1
     * Detail see: https://panjiachen.github.io/vue-element-admin-site/guide/essentials/router-and-nav.html
     *
     * hidden: true                   if set true, item will not show in the sidebar(default is false)
     * alwaysShow: true               if set true, will always show the root menu
     *                                if not set alwaysShow, when item has more than one children route,
     *                                it will becomes nested mode, otherwise not show the root menu
     * redirect: noredirect           if `redirect:noredirect` will no redirect in the breadcrumb
     * name:'router-name'             the name is used by <keep-alive> (must set!!!)
     * meta : {
        roles: ['admin','editor']    control the page roles (you can set multiple roles)
        title: 'title'               the name show in sidebar and breadcrumb (recommend set)
        icon: 'svg-name'             the icon show in the sidebar
        noCache: true                if set true, the page will no be cached(default is false)
        affix: true                  if set true, the tag will affix in the tags-view
        breadcrumb: false            if set false, the item will hidden in breadcrumb(default is true)
        activeMenu: '/example/list'  if set path, the sidebar will highlight the path you set
      }
     */
    
    /**
     * constantRoutes
     * a base page that does not have permission requirements
     * all roles can be accessed
     */
    export const constantRoutes = [
      {
        path: '/redirect',
        component: Layout,
        hidden: true,
        children: [
          {
            path: '/redirect/:path*',
            component: () => import('@/views/redirect/index')
          }
        ]
      },
      {
        path: '/login',
        component: () => import('@/views/login/index'),
        hidden: true
      },
      {
        path: '/auth-redirect',
        component: () => import('@/views/login/auth-redirect'),
        hidden: true
      },
      {
        path: '/404',
        component: () => import('@/views/error-page/404'),
        hidden: true
      },
      {
        path: '/401',
        component: () => import('@/views/error-page/401'),
        hidden: true
      },
      {
        path: '',
        component: Layout,
        redirect: 'dashboard',
        children: [
          {
            path: 'dashboard',
            component: () => import('@/views/dashboard/index'),
            name: 'Dashboard',
            meta: { title: 'dashboard', icon: 'dashboard', noCache: true, affix: true }
          }
        ]
      },
      // {
      //   path: '/documentation',
      //   component: Layout,
      //   children: [
      //     {
      //       path: 'index',
      //       component: () => import('@/views/documentation/index'),
      //       name: 'Documentation',
      //       meta: { title: 'documentation', icon: 'documentation', affix: true }
      //     }
      //   ]
      // },
      {
        path: '/guide',
        component: Layout,
        redirect: '/guide/index',
        children: [
          {
            path: 'index',
            component: () => import('@/views/guide/index'),
            name: 'Guide',
            meta: { title: 'guide', icon: 'guide', noCache: true }
          }
        ]
      }
    ]
    
    /**
     * asyncRoutes
     * the routes that need to be dynamically loaded based on user roles
     */
    export const asyncRoutes = [
      courserRouter,
      goodsRouter,
      promotionRouter,
      mallSettingRouter,
      mallUserRouter,
      sysSettingRouter,
      // {
      //   path: '/permission',
      //   component: Layout,
      //   redirect: '/permission/index',
      //   alwaysShow: true, // will always show the root menu
      //   meta: {
      //     title: 'permission',
      //     icon: 'lock',
      //     roles: ['admin', 'editor'] // you can set roles in root nav
      //   },
      //   children: [
      //     {
      //       path: 'page',
      //       component: () => import('@/views/permission/page'),
      //       name: 'PagePermission',
      //       meta: {
      //         title: 'pagePermission',
      //         roles: ['admin'] // or you can only set roles in sub nav
      //       }
      //     },
      //     {
      //       path: 'directive',
      //       component: () => import('@/views/permission/directive'),
      //       name: 'DirectivePermission',
      //       meta: {
      //         title: 'directivePermission'
      //         // if do not set roles, means: this page does not require permission
      //       }
      //     },
      //     {
      //       path: 'role',
      //       component: () => import('@/views/permission/role'),
      //       name: 'RolePermission',
      //       meta: {
      //         title: 'rolePermission',
      //         roles: ['admin']
      //       }
      //     }
      //   ]
      // },
      //
      // {
      //   path: '/icon',
      //   component: Layout,
      //   children: [
      //     {
      //       path: 'index',
      //       component: () => import('@/views/svg-icons/index'),
      //       name: 'Icons',
      //       meta: { title: 'icons', icon: 'icon', noCache: true }
      //     }
      //   ]
      // },
      //
      // /** when your routing map is too long, you can split it into small modules **/
      // componentsRouter,
      // chartsRouter,
      // nestedRouter,
      // tableRouter,
      //
      // {
      //   path: '/example',
      //   component: Layout,
      //   redirect: '/example/list',
      //   name: 'Example',
      //   meta: {
      //     title: 'example',
      //     icon: 'example'
      //   },
      //   children: [
      //     {
      //       path: 'create',
      //       component: () => import('@/views/example/create'),
      //       name: 'CreateArticle',
      //       meta: { title: 'createArticle', icon: 'edit' }
      //     },
      //     {
      //       path: 'edit/:id(\\d+)',
      //       component: () => import('@/views/example/edit'),
      //       name: 'EditArticle',
      //       meta: { title: 'editArticle', noCache: true, activeMenu: '/example/list' },
      //       hidden: true
      //     },
      //     {
      //       path: 'list',
      //       component: () => import('@/views/example/list'),
      //       name: 'ArticleList',
      //       meta: { title: 'articleList', icon: 'list' }
      //     }
      //   ]
      // },
      //
      // {
      //   path: '/tab',
      //   component: Layout,
      //   children: [
      //     {
      //       path: 'index',
      //       component: () => import('@/views/tab/index'),
      //       name: 'Tab',
      //       meta: { title: 'tab', icon: 'tab' }
      //     }
      //   ]
      // },
      //
      // {
      //   path: '/error',
      //   component: Layout,
      //   redirect: 'noredirect',
      //   name: 'ErrorPages',
      //   meta: {
      //     title: 'errorPages',
      //     icon: '404'
      //   },
      //   children: [
      //     {
      //       path: '401',
      //       component: () => import('@/views/error-page/401'),
      //       name: 'Page401',
      //       meta: { title: 'page401', noCache: true }
      //     },
      //     {
      //       path: '404',
      //       component: () => import('@/views/error-page/404'),
      //       name: 'Page404',
      //       meta: { title: 'page404', noCache: true }
      //     }
      //   ]
      // },
      //
      // {
      //   path: '/error-log',
      //   component: Layout,
      //   redirect: 'noredirect',
      //   children: [
      //     {
      //       path: 'log',
      //       component: () => import('@/views/error-log/index'),
      //       name: 'ErrorLog',
      //       meta: { title: 'errorLog', icon: 'bug' }
      //     }
      //   ]
      // },
      //
      // {
      //   path: '/excel',
      //   component: Layout,
      //   redirect: '/excel/export-excel',
      //   name: 'Excel',
      //   meta: {
      //     title: 'excel',
      //     icon: 'excel'
      //   },
      //   children: [
      //     {
      //       path: 'export-excel',
      //       component: () => import('@/views/excel/export-excel'),
      //       name: 'ExportExcel',
      //       meta: { title: 'exportExcel' }
      //     },
      //     {
      //       path: 'export-selected-excel',
      //       component: () => import('@/views/excel/select-excel'),
      //       name: 'SelectExcel',
      //       meta: { title: 'selectExcel' }
      //     },
      //     {
      //       path: 'export-merge-header',
      //       component: () => import('@/views/excel/merge-header'),
      //       name: 'MergeHeader',
      //       meta: { title: 'mergeHeader' }
      //     },
      //     {
      //       path: 'upload-excel',
      //       component: () => import('@/views/excel/upload-excel'),
      //       name: 'UploadExcel',
      //       meta: { title: 'uploadExcel' }
      //     }
      //   ]
      // },
      //
      // {
      //   path: '/zip',
      //   component: Layout,
      //   redirect: '/zip/download',
      //   alwaysShow: true,
      //   meta: { title: 'zip', icon: 'zip' },
      //   children: [
      //     {
      //       path: 'download',
      //       component: () => import('@/views/zip/index'),
      //       name: 'ExportZip',
      //       meta: { title: 'exportZip' }
      //     }
      //   ]
      // },
      //
      // {
      //   path: '/pdf',
      //   component: Layout,
      //   redirect: '/pdf/index',
      //   children: [
      //     {
      //       path: 'index',
      //       component: () => import('@/views/pdf/index'),
      //       name: 'PDF',
      //       meta: { title: 'pdf', icon: 'pdf' }
      //     }
      //   ]
      // },
      // {
      //   path: '/pdf/download',
      //   component: () => import('@/views/pdf/download'),
      //   hidden: true
      // },
      //
      // {
      //   path: '/theme',
      //   component: Layout,
      //   redirect: 'noredirect',
      //   children: [
      //     {
      //       path: 'index',
      //       component: () => import('@/views/theme/index'),
      //       name: 'Theme',
      //       meta: { title: 'theme', icon: 'theme' }
      //     }
      //   ]
      // },
      //
      // {
      //   path: '/clipboard',
      //   component: Layout,
      //   redirect: 'noredirect',
      //   children: [
      //     {
      //       path: 'index',
      //       component: () => import('@/views/clipboard/index'),
      //       name: 'ClipboardDemo',
      //       meta: { title: 'clipboardDemo', icon: 'clipboard' }
      //     }
      //   ]
      // },
      //
      // {
      //   path: '/i18n',
      //   component: Layout,
      //   children: [
      //     {
      //       path: 'index',
      //       component: () => import('@/views/i18n-demo/index'),
      //       name: 'I18n',
      //       meta: { title: 'i18n', icon: 'international' }
      //     }
      //   ]
      // },
      //
      // {
      //   path: 'external-link',
      //   component: Layout,
      //   children: [
      //     {
      //       path: 'https://github.com/PanJiaChen/vue-element-admin',
      //       meta: { title: 'externalLink', icon: 'link' }
      //     }
      //   ]
      // },
      { path: '*', redirect: '/404', hidden: true }
    ]
    
    const createRouter = () => new Router({
      // mode: 'history', // require service support
      scrollBehavior: () => ({ y: 0 }),
      routes: constantRoutes
    })
    
    const router = createRouter()
    
    // Detail see: https://github.com/vuejs/vue-router/issues/1234#issuecomment-357941465
    export function resetRouter() {
      const newRouter = createRouter()
      router.matcher = newRouter.matcher // reset router
    }
    
    export default router
    

    五、写在最后

    如果需要毕设使用、商用、个人学习使用,可加博主V:(Code2Life2)交流、获取源码。
    本博客属于个人原创,转载请注明出处;
    本系统还要很多不足的地方,由于时间有限,后续会继续更新功能;

    展开全文
  • mpvue将vue项目转换为小程序

    千次阅读 2019-02-28 16:44:04
    mpvue:是由 美团点评团队出品的小程序开 发的一款基于 vue的框架, 从整个 Vue的核心代码上经过二次开发而形成的一个框架,相当于是给Vue本身赋能,增加了开发微信小程序的能力。 使用 mpvue开发小程序,你将在...

    一、 mpvue简介

    mpvue:是由 美团点评团队出品的小程序开 发的一款基于 vue的框架, 从整个 Vue的核心代码上经过二次开发而形成的一个框架,相当于是给Vue本身赋能,增加了开发微信小程序的能力。

    使用 mpvue开发小程序,你将在小程序技术体系的基础上获取到这样一些能力:

    l 彻底的组件化开发能力:提高代码

    l 完整的 Vue.js 开发体验

    l 方便的 Vuex 数据管理方案:方便构建复杂应用

    l 快捷的 webpack 构建机制:自定义构建策略、开发阶段 hotReload

    l 支持使用 npm 外部依赖

    l 使用 Vue.js 命令行工具 vue-cli 快速初始化项目

    l H5 代码转换编译成小程序目标代码的能力

    它的目标是:在未来最理想的状态下,可以一套代码可以直接跑在多端: WEB、微信小程序、支付宝小程序、Native(借助weex)。不过由于各个端之间都存在一些比较明显的差异性,从产品的层面上讲,不建议这么做,这个框架的官方他们对它的期望的也只是开发和调试体验的一致

    原生微信小程序、 mpvue、WePY这三种开发小程序方式的比较

    二、mpvue开发流程

    1、小程序账号配置

    1)前往https://mp.weixin.qq.com/wxopen/waregister?action=step1根据指引填写信息和提交相应的资料,申请小程序帐号。在菜单 “设置”-“开发设置”获取小程序的 AppID 。

    2)在菜单 “设置”-“开发设置”中配置服务器域名,必须是https开头的域名

    2、安装开发工具

    前往 开发者工具下载页面 ,根据自己的操作系统下载对应的安装包进行安装,有关开发者工具更详细的介绍可以查看 《开发者工具介绍》 。

    打开小程序开发者工具,用微信扫码登录开发者工具,准备开发小程序。

    3、mpvue生成项目

    # 全局安装 vue-cli

    $ npm install --global vue-cli

    # 创建一个基于 mpvue-quickstart 模板的新项目

    $ vue init mpvue/mpvue-quickstart my-project

    # 安装依赖

    $ cd my-project

    $ npm install

    # 启动构建

    $ npm run dev

    Npm run dev运行成功后,本地目录下会生成一个dist文件,这个文件就是生成的小程序相关代码。

    在小程序中新建项目,填写上一步获取的 appid,便于后面可以在手机上预览,真机测试,小程序的文件目录就是本地项目目录的dist文件。

    三、mpvue开发中的规范

    1、生命周期函数

    除了 vue本身的生命周期外,mpvue还兼容了小程序的生命周期,

    app 部分:

    onLaunch,初始化

    onShow,当小程序启动,或从后台进入前台显示

    onHide,当小程序从前台进入后台

    page 部分:

    onLoad,监听页面加载

    onShow,监听页面显示

    onReady,监听页面初次渲染完成

    onHide,监听页面隐藏

    onUnload,监听页面卸载

    onPullDownRefresh,监听用户下拉动作

    onReachBottom,页面上拉触底事件的处理函数

    onShareAppMessage,用户点击右上角分享

    onPageScroll,页面滚动

    onTabItemTap, 当前是 tab 页时,点击 tab 时触发 (mpvue 0.0.16 支持)

    注意点 :

    created:这个钩子是有bug的,所有页面的created函数会在项目加载的时候被一起调用,而且进入页面的时候不会在被调用,所以这个函数基本就不能使用了,用小程序的onLoad钩子代替

    mounted:你如果从页面B返回页面A,页面A的mounted钩子不会被触发,因为页面没有被重新加载,如果有需要每次页面展示都要调用的逻辑,使用小程序的onShow代替

    2、mpvue转换的部分规则

    1. 微信小程序的页面的 query 参数是通过 onLoad 获取的,mpvue 对此进行了优化,直接通过 this.$root.$mp.query 获取相应的参数数据

    2. 小程序里所有的 BOM/DOM 都不能用,因此v-html 、 v-text 不能用。

    el:this.$refs...styles.width=offsetWIdth --> :style="{'width':offsetWidth}"
    

    获取节点信息,

    wx.createSelectorQuery().select(className).boundingClientRect().exec(res=>{
    在此处获取到节点的信息: left,top,width,height})
    
    1. 不支持部分复杂的 JavaScript 渲染表达式,我们会把 template 中的 {{}} 双花括号的部分,直接编码到 wxml 文件中,由于微信小程序的能力限制(数据绑定),所以无法支持复杂的 JavaScript 表达式。

    目前可以使用的有 + - * % ?: ! == === > < [] .,剩下的还待完善。

    {{ message.split('').reverse().join('') }}

    4) 不支持过滤器,渲染部分会转成 wxml ,wxml 不支持过滤器,所以这部分功能不支持。

    5) 不支持在 template 内使用 methods 中的函数。

    6) 不支持 官方文档: Class 与 Style 绑定 中的 classObject 和 styleObject 语法。

    <template>
    <!-- 支持 -->
    <div class="container" :class="computedClassStr"></div>
    <div class="container" :class="{active: isActive}"></div>
    <!-- 不支持 -->
    <div class="container" :class="computedClassObject"></div>
    </template>
    <script>
    export default {
    data () {
    return {
    isActive: true
    }
    },
    computed: {
    computedClassStr () {
    return this.isActive ? 'active' : ''
    },
    computedClassObject () {
    return { active: this.isActive }
    }
    }
    }
    </script>
    

    7) 不支持在组件上使用 Class 与 Style 绑定,将class与style绑定在组件最外层div上

    8) 列表渲染 需要注意一点, 嵌套列表渲染,必须指定不同的索引!

    <template>
    <ul v-for="(card, index) in list">
    <li v-for="(item, itemIndex) in card">
    {{item.value}}
    </li>
    </ul>
    </template>
    
    1. 小程序不支持路由,因此,路由跳转使用小程序的页面导航 api代替
    this.$router.push-->wx.navigateTo() //进入子页面
    this.$router.replace-->wx.reLaunch()//打开新页面
    

    10) 获取当前页面地址

    this.$route.fullPath–>getCurrentPages()[0].route

    11) 接口返回参数结构调整,小程序的 request请求接口返回的数据会在外层添加一个data

    res:{
    res:{ data:{
    code:'000000', --> code:'000000',
    data:{...} data:{...}
    }   }
    }
    

    12) 不支持本地图片用作背景图,可以使用网络图片、或者 base64,或者使用img、image标签

    13) 上拉加载 /下拉刷新,选用小程序的全局api,scroll-view中无法使用

    14) 不支持 css媒体查询,css样式避免标签选择器,不易于维护

    15) mpvue-wxParse富文本解析

    1)安装npm i mpvue-wxparse

    2)组件内

    <template>
    <wxParse :content="article" />
    </template>
    <script>
    import wxParse from 'mpvue-wxparse'
    components: {wxParse},
    </script>
    <style>
    @import url("~mpvue-wxparse/src/wxParse.css");
    </style>
    

    最后

    为了帮助大家让学习变得轻松、高效,给大家免费分享一大批资料,帮助大家在成为全栈工程师,乃至架构师的路上披荆斩棘。在这里给大家推荐一个前端全栈学习交流圈:866109386.欢迎大家进群交流讨论,学习交流,共同进步。

    当真正开始学习的时候难免不知道从哪入手,导致效率低下影响继续学习的信心。

    但最重要的是不知道哪些技术需要重点掌握,学习时频繁踩坑,最终浪费大量时间,所以有有效资源还是很有必要的。

    最后祝福所有遇到瓶疾且不知道怎么办的前端程序员们,祝福大家在往后的工作与面试中一切顺利。

    展开全文
  • 微信小程序版本 主要功能 管理端: 统计分析,会员管理,广告管理,分类管理,商品管理,订单管理等 用户端: 商品展示,商品下单,购物车,个人中心,我的收藏,我的订单等 springboot+bootstrap+html功能截图如下 ...
  • 小程序希望替换搜索中已有H5站点资源,需要先进行H5站点关联。 1. 2. 3. 4. { path: "/bd_mapp_domaincer_21829225.txt", name: "baidubd", component: () => import ("../public/bd_mapp_domaincer_...
  • 【最近更新】mpvue入门系列教程:如何在mpvue中正确的引用小程序的原生自定义组件使用mpvue开发小程序教程(六)使用mpvue开发小程序教程(五)使用mpvue开发小程序教程(四)使用mpvue开发小程序教程(三)使用...
  • 转载地址:(JAVA后端)微信小程序-毕设级项目搭建-微信小程序商城(内含源码,微信小程序+java逻辑后台+vue管理系统) 转载请注明出处 作者:Happy王子乐 个人网站(整理了部分学习资源,以及个人项目):...
  • 转载地址:(JAVA后端)微信小程序-毕设级项目搭建-微信阅读小程序(内含源码,微信小程序+java逻辑后台+vue管理系统)~不求完美,实现就好 转载请注明出处 作者:Happy王子乐 个人网站(整理了部分学习资源,以及...
  • 外卖小程序最新开发,springboot+vue+mybatis技术 餐饮小程序-点餐,商家轻松管理,更高效,更便捷的经营方式,餐饮微信领航者,助您轻松实现线上线下融合! 主要功能: 多店商家版、 预定菜品、跑腿、商家、用户注册
  • vue axios css js element 2、项目结构 config中可以修改后端请求地址及端口 api封装了后端接口 components中包含了各种业务页面 router中是页面路由的配置 static中包含了多种静态文件 3、页面截图 登录首页,...
  • vue+mpvue+vant-weapp搭建小程序开发环境,以及打包发布小程序 背景 最近因为工作的原因,需要用到小程序。由于本人使用vue较多,so,花了半天时间调研”以vue方式开发小程序的环境搭建“才有了这篇文章。废话不多说...
  • npmvue构建微信小程序

    千次阅读 2018-08-26 23:03:28
    无奈现实中手上项目太多,一个接着一个,而且也没有开发小程序的需求,所以就一拖再拖。 直到上周,终于有一个小程序的项目。如果现在学小程序,时间上肯定来不及了(就给了一周的时间)。正好前段时间看到美团开源...
  • 前端以VueCLI框架 + nodejs打包; 3.PHPExcel数据导出,导出表格更加美观,可视; 4.EasyWeChat部署微信开发,微信接入更加快捷,简单; 5.后台应用ECharts实现完善的数据统计和分析; 6.内部预留事件钩子,方面用户...
  • 聚惠星商城 DTS-SHOP,基于 微信小程序 + springboot + vue 技术构建 ,支持单店铺,多店铺入驻的商城平台。项目包含 微信小程序管理后台。基于java后台语言,已功能闭环,且达到商用标准的一套项目体系。 技术栈 ...
  • 【最近更新】mpvue入门系列教程:如何在mpvue中正确的引用小程序的原生自定义组件使用mpvue开发小程序教程(六)使用mpvue开发小程序教程(五)使用mpvue开发小程序教程(四)使用mpvue开发小程序教程(三)使用...
  • 大家好,我是佑@佐:https://blog.csdn.net/Smell_rookie,是一名页面仔工程师,我会不定时在CSDN更新我的博客,有兴趣的可以点个关注来逛逛我的主页。 前言:项目中凡是涉及到用户登录注册的都需要一个登录态来...
  • 微信小程序的icon库 微信小程序的icon库 1.引入微信的WeUI 组件库 在全局的app.json中输入以下代码: ,"useExtendedLib": { "weui": true } 2.引入到页面中 在某个页面的json文件中加入 "usingComponents":{ ...
  • 这是一个结合线下的指纹出勤管理小程序 普通用户:在线下通过指纹出入房间,然后在小程序能看到自己的日志记录,可以看到在每个教室的日志记录,时长,还有排行榜记录等等,在这之前要实名认证(一般用学号密码)。 ...
  • Vue+SpringBoot开发的图书管理小系统(前后端分离包含数据库脚本文件).zip
  • 需求:需要把vue项目打包生成桌面应用,点击桌面图标进入程序,不需要在浏览器输入地址。而且在没有网络的情况下也能正常使用。 效果图 图片: 首先你需要一个完整的vue项目,执行打包命令npm run build。然后你的...
  • 该项目是一个小程序的服务端,使用了thinkjs开发小程序和后台管理系统的服务端接口 其中后台服务接口使用jwt验证,小程序服务端通过小程序授权获取appId 后台管理平台: https://gitee.com/520...
  • 用户端手机h5 小程序端,功能齐全带开发文档 功能: 后台管理: 统计分析:查看用户,物品,订单数量;统计近7日借阅趋势 用户管理:显示注册用户信息 广告管理:轮播图增删改查 物品管理:物品显示以及审核,物品...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 21,530
精华内容 8,612
关键字:

vue小程序包管理

vue 订阅