wyling007 před 3 roky
rodič
revize
4b5bcd98a8
100 změnil soubory, kde provedl 11996 přidání a 0 odebrání
  1. 21 0
      src/App.vue
  2. 8 0
      src/api/index.js
  3. 41 0
      src/api/mock/data/carVideo - 副本.js
  4. 43 0
      src/api/mock/data/carVideo.js
  5. 50 0
      src/api/mock/data/fulu.js
  6. 14 0
      src/api/mock/index.js
  7. 23 0
      src/api/modules/amap.js
  8. 102 0
      src/api/modules/applist.js
  9. 132 0
      src/api/modules/carVideo.js
  10. 171 0
      src/api/modules/cinema.js
  11. 125 0
      src/api/modules/fulu.js
  12. 104 0
      src/api/modules/home.js
  13. 136 0
      src/api/modules/order.js
  14. 28 0
      src/api/modules/phoneBill.js
  15. 63 0
      src/api/modules/user.js
  16. 81 0
      src/api/request.js
  17. 177 0
      src/common/css/animation.css
  18. 219 0
      src/components/loadSke/loadSke.vue
  19. 177 0
      src/components/loading/loading.vue
  20. 38 0
      src/components/m-banner/m-banner.vue
  21. 65 0
      src/components/m-home-bottomad/m-home-bottomad.vue
  22. 75 0
      src/components/m-home-coupon/m-home-coupon.vue
  23. 68 0
      src/components/m-home-menu/m-home-menu.vue
  24. 194 0
      src/components/m-home-pdd/m-home-pdd.vue
  25. 539 0
      src/components/m-icon/demo.css
  26. 1267 0
      src/components/m-icon/demo_index.html
  27. 201 0
      src/components/m-icon/iconfont.css
  28. 0 0
      src/components/m-icon/iconfont.js
  29. 338 0
      src/components/m-icon/iconfont.json
  30. binární
      src/components/m-icon/iconfont.ttf
  31. 34 0
      src/components/m-icon/m-icon.vue
  32. 37 0
      src/components/m-return/m-return.vue
  33. 102 0
      src/components/m-video-box/m-video-box.vue
  34. 89 0
      src/components/m-video-leftright/m-video-leftright.vue
  35. 100 0
      src/components/m-video-topbottom-short/m-video-topbottom-short.vue
  36. 98 0
      src/components/m-video-topbottom/m-video-topbottom.vue
  37. 32 0
      src/components/topbar/topbar.vue
  38. 7 0
      src/config/errorCode.js
  39. 24 0
      src/main.js
  40. 25 0
      src/manifest.json
  41. 253 0
      src/pages.json
  42. 67 0
      src/pages/carVideo/components/branchOne.vue
  43. 51 0
      src/pages/carVideo/components/branchTwo.vue
  44. 112 0
      src/pages/carVideo/components/shortVideo.vue
  45. 163 0
      src/pages/carVideo/components/videoListBox.vue
  46. 64 0
      src/pages/carVideo/index.vue
  47. 24 0
      src/pages/carVideo/more.vue
  48. 100 0
      src/pages/carVideo/play.vue
  49. 115 0
      src/pages/carVideo/shortVideoPaly.vue
  50. 70 0
      src/pages/cinema/cinemalist.vue
  51. 36 0
      src/pages/cinema/citylist.vue
  52. 68 0
      src/pages/cinema/components/cinema-Item.vue
  53. 405 0
      src/pages/cinema/index.vue
  54. 348 0
      src/pages/cinema/orderdes.vue
  55. 508 0
      src/pages/cinema/placeorder.vue
  56. 335 0
      src/pages/cinema/schedulelist.vue
  57. 379 0
      src/pages/cinema/selectseat.vue
  58. 196 0
      src/pages/fulu/index.vue
  59. 307 0
      src/pages/fulu/orderdes.vue
  60. 277 0
      src/pages/fulu/placeorder.vue
  61. 101 0
      src/pages/home/index.vue
  62. 439 0
      src/pages/index/components/applist.vue
  63. 52 0
      src/pages/index/components/login.vue
  64. 112 0
      src/pages/index/index.vue
  65. 241 0
      src/pages/phoneBill/index.vue
  66. 300 0
      src/pages/phoneBill/orderdes.vue
  67. 242 0
      src/pages/user/browserecord.vue
  68. 242 0
      src/pages/user/collectionList.vue
  69. 177 0
      src/pages/user/index.vue
  70. 152 0
      src/pages/user/order.vue
  71. 114 0
      src/pages/user/set.vue
  72. 20 0
      src/pages/webview/webview.vue
  73. binární
      src/static/imgs/home-avtive.png
  74. binární
      src/static/imgs/home.png
  75. binární
      src/static/imgs/shmr.png
  76. binární
      src/static/imgs/theFilm-avtive.png
  77. binární
      src/static/imgs/theFilm.png
  78. binární
      src/static/imgs/user-avtive.png
  79. binární
      src/static/imgs/user.png
  80. binární
      src/static/imgs/video-avtive.png
  81. binární
      src/static/imgs/video.png
  82. binární
      src/static/logo.png
  83. 10 0
      src/store/getters.js
  84. 18 0
      src/store/index.js
  85. 30 0
      src/store/modules/cinema.js
  86. 81 0
      src/store/modules/user.js
  87. 76 0
      src/uni.scss
  88. 145 0
      src/utils/index.js
  89. 68 0
      src/utils/modules/route.js
  90. 43 0
      src/utils/modules/wx.js
  91. 1 0
      src/wxcomponents/vant/action-sheet/index.d.ts
  92. 62 0
      src/wxcomponents/vant/action-sheet/index.js
  93. 8 0
      src/wxcomponents/vant/action-sheet/index.json
  94. 69 0
      src/wxcomponents/vant/action-sheet/index.wxml
  95. 0 0
      src/wxcomponents/vant/action-sheet/index.wxss
  96. 1 0
      src/wxcomponents/vant/area/index.d.ts
  97. 232 0
      src/wxcomponents/vant/area/index.js
  98. 6 0
      src/wxcomponents/vant/area/index.json
  99. 20 0
      src/wxcomponents/vant/area/index.wxml
  100. 8 0
      src/wxcomponents/vant/area/index.wxs

+ 21 - 0
src/App.vue

@@ -0,0 +1,21 @@
+<script>
+</script>
+
+<style>
+	@import "/wxcomponents/vant/common/index.wxss";
+	@import "@/common/css/animation.css";
+
+	/*每个页面公共css */
+	* {
+		margin: 0;
+		padding: 0;
+	}
+
+	html {
+		background-color: #F1F1F1;
+	}
+
+	.night {
+		filter: invert(1) hue-rotate(180deg);
+	}
+</style>

+ 8 - 0
src/api/index.js

@@ -0,0 +1,8 @@
+//批量引入modules文件夹下的js
+const api = {}
+const modules = require.context('./modules', false, /\.js$/)
+modules.keys().forEach(key=>{
+	api[key.slice(2,-3)]=modules(key).default
+})
+
+export default api

+ 41 - 0
src/api/mock/data/carVideo - 副本.js

@@ -0,0 +1,41 @@
+import Mock from 'mockjs'
+
+let Random = Mock.Random
+const data = Mock.mock({
+	code: 200,
+	msg: '请求成功',
+	'data|5-10': [{
+		chapterName: '@ctitle(5, 10)',
+		'list|5-10': [{
+			videoUrl: 'http://1305573081.vod2.myqcloud.com/10abdb63vodcq1305573081/c5d1c7a53701925920473528049/dfEdqef12AMA.mp4',
+			cover: Random.image('200x100', '#50B347', '#FFF', '@ctitle(5, 12)'),
+			title: '@ctitle(5, 12)',
+			remarks: '@ctitle(5, 12)',
+			duration: '@datetime("HH:mm:ss")',
+		}]
+	}]
+})
+
+const search = Mock.mock({
+	code: 200,
+	msg: '请求成功',
+	'list|5-10': [{
+		videoUrl: 'http://1305573081.vod2.myqcloud.com/10abdb63vodcq1305573081/c5d1c7a53701925920473528049/dfEdqef12AMA.mp4',
+		cover: Random.image('200x100', '#50B347', '#FFF', '@ctitle(5, 12)'),
+		title: '@ctitle(5, 12)',
+		remarks: '@ctitle(5, 12)',
+		duration: '@datetime("HH:mm:ss")',
+		type: '类型',
+	}]
+})
+
+const fulu = {
+	getCarVideoList() {
+		return [200, data]
+	},
+	getSearch() {
+		return [200, search]
+	}
+}
+
+export default fulu

+ 43 - 0
src/api/mock/data/carVideo.js

@@ -0,0 +1,43 @@
+import Mock from 'mockjs'
+
+let Random = Mock.Random
+const data = Mock.mock({
+	code: 200,
+	msg: '请求成功',
+	'data|5-10': [{
+		chapterName: '@ctitle(5, 10)',
+		'list|5-10': [{
+			videoUrl: 'http://1305573081.vod2.myqcloud.com/10abdb63vodcq1305573081/c5d1c7a53701925920473528049/dfEdqef12AMA.mp4',
+			cover: Random.image('200x100', '#50B347', '#FFF', '@ctitle(5, 12)'),
+			title: '@ctitle(5, 12)',
+			remarks: '@ctitle(5, 12)',
+			duration: '@datetime("HH:mm:ss")',
+		}]
+	}]
+})
+
+const search = Mock.mock({
+	code: 200,
+	msg: '请求成功',
+	data: {
+		chapterName: '@ctitle(5, 10)',
+		'list|5-10': [{
+			videoUrl: 'http://1305573081.vod2.myqcloud.com/10abdb63vodcq1305573081/c5d1c7a53701925920473528049/dfEdqef12AMA.mp4',
+			cover: Random.image('200x100', '#50B347', '#FFF', '@ctitle(5, 12)'),
+			title: '@ctitle(5, 12)',
+			remarks: '@ctitle(5, 12)',
+			duration: '@datetime("HH:mm:ss")',
+		}]
+	}
+})
+
+const fulu = {
+	getCarVideoList() {
+		return [200, data]
+	},
+	getSearch() {
+		return [200, search]
+	}
+}
+
+export default fulu

+ 50 - 0
src/api/mock/data/fulu.js

@@ -0,0 +1,50 @@
+import Mock from 'mockjs'
+
+const data = Mock.mock({
+	code: 200,
+	msg: '请求成功',
+	'data|1-1': [{
+			type_name: '视频会员',
+			'list|1-1': [{
+					icon: 'https://t1-1305573081.cos.ap-shanghai.myqcloud.com/wxapp/static/imgs/%E7%88%B1%E5%A5%87%E8%89%BA.png',
+					name: '爱奇艺',
+					introduction: "立即充值享折扣",
+					remark: ['请确保充值账号无误,充值成功后不支持退换'],
+					product_ids: [11549658, 16681765, 17736621, 18229248, 10971544, 15757712]
+				},
+				{
+					icon: 'https://t1-1305573081.cos.ap-shanghai.myqcloud.com/wxapp/static/imgs/%E8%85%BE%E8%AE%AF%E8%A7%86%E9%A2%91.png',
+					name: '腾讯视频',
+					introduction: "立即充值享折扣",
+					remark: ['请确保充值账号无误,充值成功后不支持退换', '仅支持QQ号充值'],
+					product_ids: [18387970, 11032040, 16894978, 14983719]
+				},
+				{
+					icon: 'https://t1-1305573081.cos.ap-shanghai.myqcloud.com/wxapp/static/imgs/%E5%93%94%E5%93%A9%E5%93%94%E5%93%A9.png',
+					name: '哔哩哔哩',
+					introduction: "立即充值享折扣",
+					remark: ['请确保充值账号无误,充值成功后不支持退换'],
+					product_ids: [10645834]
+				}
+			]
+		},
+		{
+			type_name: '虚拟卡币',
+			'list|1-1': [{
+				icon: 'https://t1-1305573081.cos.ap-shanghai.myqcloud.com/wxapp/static/imgs/%E7%88%B1%E5%A5%87%E8%89%BA.png',
+				name: '斗鱼直播',
+				introduction: "立即充值享折扣",
+				remark: ['请确保充值账号无误,充值成功后不支持退换'],
+				product_ids: [12664416]
+			}]
+		}
+	]
+})
+
+const fulu = {
+	getTypeList() {
+		return [200, data]
+	}
+}
+
+export default fulu

+ 14 - 0
src/api/mock/index.js

@@ -0,0 +1,14 @@
+import MockAdapter from 'axios-mock-adapter'
+import fulu from './data/fulu.js'
+import carVideo from './data/carVideo.js'
+
+export default {
+	init(request) {
+		let mock = new MockAdapter(request, {
+			onNoMatch: 'passthrough'
+		});
+		// mock.onGet('student/applet/fulu/list').reply(fulu.getTypeList);
+		mock.onGet('carVideo').reply(carVideo.getCarVideoList);
+		mock.onGet('carVideo/search').reply(carVideo.getSearch);
+	}
+}

+ 23 - 0
src/api/modules/amap.js

@@ -0,0 +1,23 @@
+import request from '../request'
+
+const amap={
+	/**
+	 * 逆地理编码
+	 * @param {
+		 location: string '经纬度坐标:经度在前,纬度在后,经纬度间以“,”分割'
+		 ...其他参数去高德官网看
+	 } params
+	 */
+	regeo(params) {
+		return request({
+			url: 'https://restapi.amap.com/v3/geocode/regeo',
+			method: 'get',
+			params: {
+				key: '6476cd358ddea091d7da6d59e92b0659',
+				...params
+			}
+		})
+	}
+}
+
+export default amap

+ 102 - 0
src/api/modules/applist.js

@@ -0,0 +1,102 @@
+import request from '../request'
+
+//发现模块
+const appList = {
+	/**
+	 * 按品类查询商家列表
+	 * @param {Object} id
+	 * @param {Object} params
+	 */
+	getTypeAppList(id,params) {
+		return request({
+			url: `/student/applet/customer/getCustomerListByProductId/${id}`,
+			method: 'get',
+			params
+		})
+	},
+	/**
+	 * 查询用户收藏列表
+	 * @param {Object} params
+	 */
+	collectionList(params) {
+		return request({
+			url: '/student/applet/collection/collectionList',
+			method: 'get',
+			params
+		})
+	},
+	/**
+	 * 查询用户浏览记录
+	 * @param {Object} params
+	 */
+	getBrowseRecordInfoList(params) {
+		return request({
+			url: '/student/applet/record/info/getBrowseRecordInfoList',
+			method: 'get',
+			params
+		})
+	},
+	/**
+	 * 查询品类列表
+	 * @param {Object} params
+	 */
+	typeList(params) {
+		return request({
+			url: '/student/applet/product/info/list',
+			method: 'get',
+			params
+		})
+	},
+	/**
+	 * 收藏商家
+	 * @param {Object} id
+	 */
+	addFavorites(id) {
+		return request({
+			url: `/student/applet/collection/collectionBusiness/${id}`,
+			method: 'put'
+		})
+	},
+	/**
+	 * 删除收藏
+	 * @param {Object} ids
+	 */
+	delFavorites(ids) {
+		return request({
+			url: `/student/applet/collection/cancelCollection/${ids}`,
+			method: 'delete'
+		})
+	},
+	/**
+	 * 新增记录
+	 * @param {Object} id
+	 */
+	BrowseRecordAdd(id) {
+		return request({
+			url: `/student/applet/record/info/insertBrowseRecord/${id}`,
+			method: 'put'
+		})
+	},
+	/**
+	 * 删除记录
+	 * @param {Object} ids
+	 */
+	BrowseRecordDel(ids) {
+		return request({
+			url: `/student/applet/record/info/${ids}`,
+			method: 'delete'
+		})
+	},
+	/**
+	 * 查询轮播图列表
+	 */
+	getCarouselChartList() {
+		return request({
+			url: `/student/applet/homePage/getHomePageDataList`,
+			method: 'get'
+		})
+	}
+}
+
+
+export default appList

+ 132 - 0
src/api/modules/carVideo.js

@@ -0,0 +1,132 @@
+import request from '../request'
+import dayjs from 'dayjs'
+import Mock from 'mockjs'
+
+const cleanData = (item) => {
+	return {
+		pid: item.teachingVideoTypeId,
+		videoUrl: item.fileUrl,
+		cover: item.coverFileUrl,
+		title: item.title,
+		remarks: item.videoDescribe,
+		duration: dayjs(item.videoDuration * 1000).subtract(8, 'hour').format('HH:mm:ss'),
+	}
+}
+
+//学车视频api
+class CarVideo {
+	/**
+	 * 获取短视频列表
+	 */
+	async getShortVideoList(params) {
+		const res = await request({
+			url: '/open-api/teachingDsp/dsp/list',
+			method: 'get',
+			params
+		})
+
+		const list = res.rows.map((item) => {
+			return {
+				videoUrl: item.fileUrl,
+				cover: item.coverFileUrl,
+				title: item.title,
+				remarks: item.videoDescribe,
+				duration: dayjs(item.videoDuration * 1000).subtract(8, 'hour').format('HH:mm:ss'),
+			}
+		})
+
+		const data = {
+			code: 200,
+			msg: '请求成功',
+			data: {
+				chapterName: '短视频',
+				list: list,
+				total: res.total
+			}
+		}
+
+		return data
+	}
+	/**
+	 * 获取学车视频列表
+	 */
+	async getCarVideoList(id) {
+		let res = await request({
+			url: `open-api/teachingVideo/info/getTeachingVideoByTypeId`,
+			params: {
+				videoTypeId: id
+			}
+		})
+
+		res.data = res.data.map(item => {
+			return {
+				pid: item.teachingVideoTypeId,
+				videoUrl: item.fileUrl,
+				cover: item.coverFileUrl,
+				title: item.title,
+				remarks: item.videoDescribe,
+				duration: dayjs(item.videoDuration * 1000).subtract(8, 'hour').format(
+					'HH:mm:ss'),
+			}
+		})
+
+		return res
+	}
+	/**
+	 * 获取视频列表树形结构
+	 */
+	async getTreeList() {
+		let res = await request({
+			url: `open-api/teachingVideo/info/treeList`
+		})
+
+
+		const mapFn = (obj) => {
+			let newObj = {}
+			newObj.chapterName = obj.typeName
+			newObj.children = obj.children.map(mapFn)
+			newObj.list = obj.videos.map(cleanData)
+			return newObj
+		}
+
+
+		res.data = res.data.map(mapFn)
+
+		return res
+	}
+	/**
+	 * 查询视频列表
+	 */
+	async getSearchList(keyword) {
+
+		const res = await request({
+			url: `open-api/teachingVideo/info/search`,
+			params: {
+				keyword
+			}
+		})
+		
+		const list = res.data.map((item) => {
+			return {
+				pid: item.teachingVideoTypeId,
+				videoUrl: item.fileUrl,
+				cover: item.coverFileUrl,
+				title: item.title,
+				remarks: item.videoDescribe,
+				duration: dayjs(item.videoDuration * 1000).subtract(8, 'hour').format('HH:mm:ss'),
+			}
+		})
+		
+		const data = {
+			chapterName: keyword,
+			list: list
+		}
+		
+		res.data = data
+
+		return res
+	}
+}
+
+
+export default new CarVideo

+ 171 - 0
src/api/modules/cinema.js

@@ -0,0 +1,171 @@
+import request from '../request'
+import qs from 'qs'
+
+let fileCommonApiUrl='/student/film/order/fileCommonApi'
+
+//电影模块API
+const cinema = {
+	/**
+	 * 获取电影后台折扣参数
+	 * @param {Object} data
+	 */
+	getFilmDiscount(data) {
+		return request({
+			url: `/system/config/configKey/film_discount`,
+		})
+	},
+	/**
+	 * 获取即将上映电影列表
+	 * @param {Object} data
+	 */
+	getSoonList(data) {
+		return request({
+			url: fileCommonApiUrl,
+			method: 'post',
+			data: {
+				url: 'movieapi/movie-info/get-soon-list',
+				paramData: qs.stringify(data)
+			}
+		})
+	},
+	/**
+	 * 包含某电影的日期
+	 * @param {Object} data
+	 */
+	getShowDate(data) {
+		return request({
+			url: fileCommonApiUrl,
+			method: 'post',
+			data: {
+				url: 'movieapi/movie-info/get-show-date',
+				paramData: qs.stringify(data)
+			}
+		})
+	},
+	/**
+	 * 获取正在热映电影列表
+	 * @param {Object} data
+	 */
+	getHotList(data) {
+		return request({
+			url: fileCommonApiUrl,
+			method: 'post',
+			data: {
+				url: 'movieapi/movie-info/get-hot-list',
+				paramData: qs.stringify(data)
+			}
+		})
+	},
+	/**
+	 * 获取城市列表
+	 * @param {Object} data
+	 */
+	getCityList(data) {
+		return request({
+			url: fileCommonApiUrl,
+			method: 'post',
+			data: {
+				url: 'movieapi/movie-info/get-city-list',
+				paramData: qs.stringify(data)
+			}
+		})
+	},
+	/**
+	 * 获取影院列表
+	 * @param {Object} data
+	 */
+	getCinemaList(data) {
+		return request({
+			url: fileCommonApiUrl,
+			method: 'post',
+			data: {
+				url: 'movieapi/movie-info/get-cinema-list',
+				paramData: qs.stringify(data)
+			}
+		})
+	},
+	/**
+	 * 包含某电影的影院
+	 * @param {Object} data
+	 */
+	getShowList(data) {
+		return request({
+			url: fileCommonApiUrl,
+			method: 'post',
+			data: {
+				url: 'movieapi/movie-info/get-show-list',
+				paramData: qs.stringify(data)
+			}
+		})
+	},
+	/**
+	 * 某电影在某影院的场次排期
+	 * @param {Object} data
+	 */
+	getScheduleList(data) {
+		return request({
+			url: fileCommonApiUrl,
+			method: 'post',
+			data: {
+				url: 'movieapi/movie-info/get-schedule-list',
+				paramData: qs.stringify(data)
+			}
+		})
+	},
+	/**
+	 * 查账户余额
+	 * @param {Object} data
+	 */
+	getInfo(data) {
+		return request({
+			url: fileCommonApiUrl,
+			method: 'post',
+			data: {
+				url: 'api/user/info',
+				paramData: qs.stringify(data)
+			}
+		})
+	},
+	/**
+	 * 根据订单查影票信息
+	 * @param {Object} data
+	 */
+	orderQuery(data) {
+		return request({
+			url: fileCommonApiUrl,
+			method: 'post',
+			data: {
+				url: 'api/order/query',
+				paramData: qs.stringify(data)
+			}
+		})
+	},
+	/**
+	 * 某次电影的座位
+	 * @param {Object} data
+	 */
+	getSeat(data) {
+		return request({
+			url: fileCommonApiUrl,
+			method: 'post',
+			data: {
+				url: 'movieapi/movie-info/get-seat',
+				paramData: qs.stringify(data)
+			}
+		})
+	},
+	/**
+	 * 获取电影票支付数据
+	 * @param {Object} data
+	 */
+	prepareOrder(data) {
+		return request({
+			url: '/student/wx/prepareOrder',
+			method: 'post',
+			data
+		})
+	}
+}
+
+export default cinema 
+

+ 125 - 0
src/api/modules/fulu.js

@@ -0,0 +1,125 @@
+import request from '../request'
+
+//福禄会员api
+const fulu = {
+	/**
+	 * 获取福禄商品折扣
+	 */
+	getPriceKeyword() {
+		return request({
+			url: `/system/config/configKey/fulu_vip_discount`,
+		})
+	},
+	/**
+	 * @param {
+		 buy_num: Number			购买数量
+		 charge_account: string		充值账号
+		 goodsPictureUrl: string	商品图片地址
+		 product_id: Number 		商品编号
+	 } data
+	 * 微信支付福禄下单
+	 */
+	prepareOrder(data) {
+		return request({
+			url: `/student/wx/prepareOrderForFulu`,
+			method: 'post',
+			data
+		})
+	},
+	/**
+	 * @param {
+		 customer_order_no:string  外部订单号
+	 } data
+	 */
+	orderInfoGet(data) {
+		return request({
+			url: `student/fulu/fuluCommonApi`,
+			method: 'post',
+			data: {
+				method: 'fulu.order.info.get',
+				biz_content: JSON.stringify(data)
+			}
+		})
+	},
+	//商品api
+	goods: {
+		/**
+		 * 获取福禄商品类型列表
+		 * mock
+		 */
+		async getTypeList() {
+			let res = await request({
+				url: `student/applet/fulu/list`
+			})
+
+			res.data = res.data.map(val => {
+				val.type_name = val.typeName
+				val.list = val.list.map(val2 => {
+					val2.icon = val2.iconUrl
+					val2.product_ids = val2.productIds.split(',')
+					val2.remark = val2.remark.split('|')
+					return val2
+				})
+				return val
+			})
+			
+			return res
+		},
+		/**
+		 * 获取商品信息
+		 * @param {
+			 product_id: string '商品ID'
+		 } data
+		 */
+		infoGet(data) {
+			return request({
+				url: `student/fulu/fuluCommonApi`,
+				method: 'post',
+				data: {
+					method: 'fulu.goods.info.get',
+					biz_content: JSON.stringify(data)
+				}
+			})
+		},
+		/**
+		 * 获取商品模板
+		 * @param {
+			 template_id: string '商品模板编号'
+		 } data
+		 */
+		templateGet(data) {
+			return request({
+				url: `student/fulu/fuluCommonApi`,
+				method: 'post',
+				data: {
+					method: 'fulu.goods.template.get',
+					biz_content: JSON.stringify(data)
+				}
+			})
+		},
+		/**
+		 * 获取商品列表
+		 * @param {
+			 first_category_id?: int 	'商品分类Id(一级)'
+			 second_category_id?: int 	'商品分类Id(二级)'
+			 third_category_id?: int 	'商品分类Id(三级)'
+			 product_id?: int 			'商品编号'
+			 product_name?: string 		'商品名称'
+			 product_type?: string 		'库存类型:卡密、直充'
+			 face_value?: double 		'面值'
+		 } data
+		 */
+		listGet(data) {
+			return request({
+				url: `student/fulu/fuluCommonApi`,
+				method: 'post',
+				data: {
+					method: 'fulu.goods.list.get',
+					biz_content: JSON.stringify(data)
+				}
+			})
+		}
+	}
+}
+
+export default fulu

+ 104 - 0
src/api/modules/home.js

@@ -0,0 +1,104 @@
+import request from '../request'
+import md5 from 'crypto-js/md5'
+
+let pddKeyword = [],
+	keyIndex = 0
+
+//首页模块
+const home = {
+	/**
+	 * 查询轮播图列表
+	 */
+	getHomePageDataList(keys) {
+		return request({
+			url: `student/applet/homePage/dictValueHomePageDataList/` + keys,
+			method: 'get'
+		})
+	},
+	async getPddKeyword() {
+		if (pddKeyword.length != 0) {
+			keyIndex++
+			return pddKeyword[keyIndex % pddKeyword.length]
+		}
+		let {
+			data
+		} = await request({
+			url: `/system/config/configKey/pdd_keyword`,
+		})
+		pddKeyword = data.split('/')
+		return pddKeyword[keyIndex % pddKeyword.length]
+	},
+	/**
+	 * 查询轮播图列表
+	 * @param {Object} data
+	 */
+	async getPDD(data) {
+		let keyword = await home.getPddKeyword()
+		let params = {
+			// type: 'pdd.ddk.goods.recommend.get',
+			type: 'pdd.ddk.goods.search',
+			data_type: 'JSON',
+			client_id: 'fa0f2debb5b0444b9719919d7b8204d1',
+			pid: '1642187_203462988',
+			timestamp: new Date().getTime().toString().slice(0, 10),
+			keyword,
+			...data
+		}
+		let client_secret = '3305b6bb37252495848e67fd991134651e308495'
+		params.sign = calcAuth(params, client_secret)
+		return request({
+			url: `https://gw-api.pinduoduo.com/api/router`,
+			method: 'get',
+			params
+		})
+	},
+	/**
+	 * 查询小程序跳转参数
+	 * @param {Object} data
+	 */
+	async getPddWxData(data) {
+		let params = {
+			type: 'pdd.ddk.goods.promotion.url.generate',
+			data_type: 'JSON',
+			client_id: 'fa0f2debb5b0444b9719919d7b8204d1',
+			p_id: '1642187_203462988',
+			timestamp: new Date().getTime().toString().slice(0, 10),
+			generate_we_app: true
+		}
+		let getPDDRes = await home.getPDD(data)
+		params.search_id = getPDDRes.goods_search_response.search_id
+		let arr = '['
+		getPDDRes.goods_search_response.goods_list.map((val) => {
+			arr += '"' + val.goods_sign + '",'
+		})
+		params.goods_sign_list = arr.slice(0, -1) + ']'
+		let client_secret = '3305b6bb37252495848e67fd991134651e308495'
+		params.sign = calcAuth(params, client_secret)
+		let wxDataRes = await request({
+			url: `https://gw-api.pinduoduo.com/api/router`,
+			method: 'get',
+			params
+		})
+		let dataArr = []
+		getPDDRes.goods_search_response.goods_list.map((val, index) => {
+			val.we_app_info = wxDataRes.goods_promotion_url_generate_response.goods_promotion_url_list[
+				index].we_app_info
+		})
+		return getPDDRes.goods_search_response.goods_list
+	}
+
+}
+
+//拼多多密钥计算
+function calcAuth(params, client_secret) {
+	var arr = []
+	Object.keys(params).sort().forEach((key) => {
+		arr.push(key + params[key])
+	})
+	arr[0] = client_secret + arr[0]
+	arr[arr.length - 1] += client_secret
+	return md5(arr.join('')).toString().toUpperCase()
+}
+
+
+export default home

+ 136 - 0
src/api/modules/order.js

@@ -0,0 +1,136 @@
+import request from '../request'
+
+//订单模块
+const order = {
+	/**
+	 * 查询订单列表
+	 * @param {Object} params
+	 */
+	async getOrderList(params) {
+		let res = await request({
+			url: '/student/wx/order/list',
+			params
+		})
+
+		const orderStatusMap = new Map([
+			['1', '等待发货'],
+			['2', '交易完成'],
+			['3', '退款/售后']
+		])
+
+		const orderNameMap = new Map([
+			['1', (json) => {
+				return json.cinemaData.filmName
+			}],
+			['2', (json) => {
+				let nameArr = json.wxFuluOrderDetailDTO.product_name.split('-')
+				return nameArr[1] + '-' + nameArr[2]
+			}],
+			['3', (json) => {
+				let nameArr = json.rechargePhoneNo+'话费充值'
+				return nameArr
+			}]
+		])
+
+		res.rows = res.rows.map(val => {
+
+			try {
+				var orderDataJson = JSON.parse(val.orderDataJson)
+			} catch {
+				orderDataJson = {
+					wxFuluOrderDetailDTO: {
+						product_name: ''
+					}
+				}
+			}
+
+			return {
+				createTime: val.createTime,
+				goodsPictureUrl: val.goodsPictureUrl,
+				orderName: orderNameMap.get(val.goodsType)(orderDataJson),
+				outTradeNo: val.outTradeNo,
+				total: val.total / 100,
+				orderStatus: orderStatusMap.get(val.orderStatus),
+				id: val.id,
+				goodsType: val.goodsType
+			}
+		})
+
+		return res
+	},
+	/**
+	 * 查询订单详情
+	 * @param path:string 订单号
+	 */
+	async getWxOrder(path) {
+		let res = await request({
+			url: `/student/wx/${path}`,
+		})
+
+		const orderStatusMap = new Map([
+			['1', '等待发货'],
+			['2', '交易完成'],
+			['3', '退款/售后']
+		])
+
+		const jsonMap = new Map([
+			['1', (data) => {
+				return {
+					filmName: data.orderDataJson.cinemaData.filmName,
+					showTime: data.orderDataJson.cinemaData.showTime,
+					cinemaName: data.orderDataJson.cinemaData.cinemaName,
+					hallName: data.orderDataJson.cinemaData.hallName,
+					seat: data.orderDataJson.wxOrderCreateDTO.seat.split(','),
+					total: data.total / 100,
+					orderStatus: data.orderStatus,
+					orderStatusDesc: orderStatusMap.get(data.orderStatus),
+				}
+			}],
+			['2', (data) => {
+				return {
+					charge_account: data.orderDataJson.wxFuluOrderDetailDTO.charge_account,
+					product_name: data.orderDataJson.wxFuluOrderDetailDTO.product_name,
+					create_time: data.orderDataJson.wxFuluOrderDetailDTO.create_time,
+					buy_num: data.orderDataJson.wxFuluOrderDetailDTO.buy_num,
+					recharge_description: data.orderDataJson.wxFuluOrderDetailDTO.recharge_description,
+					total: data.total / 100,
+					orderStatus: data.orderStatus,
+					orderStatusDesc: orderStatusMap.get(data.orderStatus),
+					goodsPictureUrl: data.goodsPictureUrl
+				}
+			}],
+			['3', (data) => {
+				let operatorsMap = new Map([
+					[1,'移动'],
+					[2,'联通'],
+					[3,'电信'],
+				])
+				return {
+					rechargePhoneNo: data.orderDataJson.rechargePhoneNo,
+					tmallNo: data.orderDataJson.tmallNo,
+					operators: operatorsMap.get(data.orderDataJson.operators),
+					create_time: data.createTime,
+					total: data.total / 100,
+					orderStatus: data.orderStatus,
+					orderStatusDesc: orderStatusMap.get(data.orderStatus),
+					goodsPictureUrl: data.goodsPictureUrl
+				}
+			}]
+		])
+
+		try {
+			res.data.orderDataJson = JSON.parse(res.data.orderDataJson)
+		} catch {
+			res.data.orderDataJson = {
+				wxFuluOrderDetailDTO: {
+					product_name: ''
+				}
+			}
+		}
+		res.data = jsonMap.get(res.data.goodsType)(res.data)
+
+		return res
+	}
+}
+
+export default order

+ 28 - 0
src/api/modules/phoneBill.js

@@ -0,0 +1,28 @@
+import request from '../request'
+
+//福禄会员api
+const phoneBill = {
+	/**
+	 * @param {
+		 operators: Number			运营商:1-移动 2-联通 3-电信
+		 recharge_phone_no: Number		充值号码
+		 goodsPictureUrl: string	商品图片地址
+		 tmall_no: string 		天猫订单号
+	 } data
+	 * 微信支付福禄下单
+	 */
+	prepareOrder(data) {
+		return request({
+			url: `/student/wx/prepareOrderForPhoneBill`,
+			method: 'post',
+			data
+		})
+	},
+	getPriceKeyword() {
+		return request({
+			url: `/system/config/configKey/activities_phone_bill`,
+		})
+	},
+}
+
+export default phoneBill

+ 63 - 0
src/api/modules/user.js

@@ -0,0 +1,63 @@
+import request from '../request'
+
+//用户模块
+const user = {
+	/**
+	 * 用户登录获取token
+	 */
+	async login() {
+		let res = await wx.login()
+		return request({
+			url: '/login/jscode',
+			method: 'post',
+			params: {
+				jscode: res.code
+			},
+			headers: {
+				isLogin: true
+			}
+		})
+	},
+	/**
+	 * 更新用户信息
+	 * @param {Object} data
+	 */
+	updateUserInfo(data) {
+		return request({
+			url: '/student/user/info',
+			method: 'post',
+			data
+		})
+	},
+	/**
+	 * 获取用户详细信息
+	 */
+	getInfo() {
+		return request({
+			url: '/getInfo',
+			method: 'get'
+		})
+	},
+	/**
+	 * 退出登录
+	 */
+	logout() {
+		return request({
+			url: '/logout',
+			method: 'post'
+		})
+	},
+	/**
+	 * 绑定用户身份证信息
+	 * @param {Object} data
+	 */
+	bindUserCard(data) {
+		return request({
+			url: '/gzpt/userInfo/bind',
+			method: 'put',
+			data
+		})
+	}
+}
+
+export default user

+ 81 - 0
src/api/request.js

@@ -0,0 +1,81 @@
+import store from '@/store'
+import errorCode from '@/config/errorCode'
+import axios from 'axios'
+import mpAdapter from 'axios-miniprogram-adapter'
+axios.defaults.adapter = mpAdapter
+
+import mock from './mock'
+
+const baseUrl = 'https://zzjs.zzxcx.net/prod-api';
+
+// 创建axios实例
+const service = axios.create({
+	// axios中请求配置有baseURL选项,表示请求URL公共部分
+	// baseURL: process.env.VUE_APP_BASE_API,
+	baseURL: baseUrl,
+})
+mock.init(service)
+
+// request拦截器
+service.interceptors.request.use(
+	async config => {
+			// 是否需要设置 token
+			if (config.headers.isLogin) {
+				return config
+			}
+			config.headers['Authorization'] = 'Bearer ' + await store.dispatch("getToken") // 让每个请求携带自定义token 请根据实际情况自行修改
+			return config
+		},
+		error => {
+			Promise.reject(error)
+		}
+)
+
+// 响应拦截器
+service.interceptors.response.use(
+	res => {
+		// 未设置状态码则默认成功状态
+		const code = res.data.code || 200;
+		// 获取错误信息
+		const msg = errorCode[code] || res.data.msg || errorCode['default']
+		//重置Authorization时间
+		if (code !== 401) store.commit('REFRESH_TOKEN')
+
+		if (code !== 200) {
+			if (code == 500) {
+				console.log('code' + code + ':' + msg)
+				wx.showToast({
+					title: 'code' + code + ':系统错误' ,
+					icon: 'none'
+				})
+			}else{
+				console.log('code' + code + ':' + msg)
+				wx.showToast({
+					title: 'code' + code + ':' + msg,
+					icon: 'none'
+				})
+			}
+		}
+		
+		return res.data
+	},
+	error => {
+		let {
+			message
+		} = error;
+		if (message == "Network Error") {
+			message = "后端接口连接异常";
+		} else if (message.includes("timeout")) {
+			message = "系统接口请求超时";
+		} else if (message.includes("Request failed with status code")) {
+			message = "系统接口" + message.substr(message.length - 3) + "异常";
+		}
+		wx.showToast({
+			title: message,
+			icon: 'none'
+		})
+		return Promise.reject(error)
+	}
+)
+
+export default service

+ 177 - 0
src/common/css/animation.css

@@ -0,0 +1,177 @@
+/* 
+  Animation 微动画  
+ */
+
+
+/* Animation css */
+[class*=animation-] {
+    animation-duration: .1s;
+    animation-timing-function: ease-out;
+    animation-fill-mode: both
+}
+
+.animation-fade {
+    animation-name: fade;
+    animation-duration: .1s;
+    animation-timing-function: linear
+}
+
+.animation-scale-up {
+    animation-name: scale-up
+}
+
+.animation-scale-down {
+    animation-name: scale-down
+}
+
+.animation-slide-top {
+	animation-duration: .3s;
+    animation-name: slide-top
+}
+
+.animation-slide-bottom {
+	animation-duration: .3s;
+    animation-name: slide-bottom
+}
+
+.animation-slide-left {
+    animation-name: slide-left
+}
+
+.animation-slide-right {
+    animation-name: slide-right
+}
+
+.animation-shake {
+    animation-name: shake
+}
+
+.animation-reverse {
+    animation-direction: reverse
+}
+
+@keyframes fade {
+    0% {
+        opacity: 0
+    }
+
+    100% {
+        opacity: 1
+    }
+}
+
+@keyframes scale-up {
+    0% {
+        opacity: 0;
+        transform: scale(.2)
+    }
+
+    100% {
+        opacity: 1;
+        transform: scale(1)
+    }
+}
+
+@keyframes scale-down {
+    0% {
+        opacity: 0;
+        transform: scale(1.8)
+    }
+
+    100% {
+        opacity: 1;
+        transform: scale(1)
+    }
+}
+
+@keyframes slide-top {
+    0% {
+        /* opacity: 0; */
+        transform: translateY(-100%)
+    }
+
+    100% {
+        /* opacity: 1; */
+        transform: translateY(0)
+    }
+}
+
+@keyframes slide-bottom {
+    0% {
+        opacity: 0;
+        transform: translateY(100%)
+    }
+
+    100% {
+        opacity: 1;
+        transform: translateY(0)
+    }
+}
+
+@keyframes shake {
+
+    0%,
+    100% {
+        transform: translateX(0)
+    }
+
+    10% {
+        transform: translateX(-9px)
+    }
+
+    20% {
+        transform: translateX(8px)
+    }
+
+    30% {
+        transform: translateX(-7px)
+    }
+
+    40% {
+        transform: translateX(6px)
+    }
+
+    50% {
+        transform: translateX(-5px)
+    }
+
+    60% {
+        transform: translateX(4px)
+    }
+
+    70% {
+        transform: translateX(-3px)
+    }
+
+    80% {
+        transform: translateX(2px)
+    }
+
+    90% {
+        transform: translateX(-1px)
+    }
+}
+
+@keyframes slide-left {
+    0% {
+        opacity: 0;
+        transform: translateX(-100%)
+    }
+
+    100% {
+        opacity: 1;
+        transform: translateX(0)
+    }
+}
+
+@keyframes slide-right {
+    0% {
+        opacity: 0;
+        transform: translateX(100%)
+    }
+
+    100% {
+        opacity: 1;
+        transform: translateX(0)
+    }
+}

+ 219 - 0
src/components/loadSke/loadSke.vue

@@ -0,0 +1,219 @@
+<template>
+	<view class="skeleton-box">
+		<view v-if="loading" class="skeleton">
+			<div class="spinner">
+				<div class="spinner-container container1">
+					<div class="circle1"></div>
+					<div class="circle2"></div>
+					<div class="circle3"></div>
+					<div class="circle4"></div>
+				</div>
+				<div class="spinner-container container2">
+					<div class="circle1"></div>
+					<div class="circle2"></div>
+					<div class="circle3"></div>
+					<div class="circle4"></div>
+				</div>
+				<div class="spinner-container container3">
+					<div class="circle1"></div>
+					<div class="circle2"></div>
+					<div class="circle3"></div>
+					<div class="circle4"></div>
+				</div>
+			</div>
+		</view>
+		<view v-else-if="list.length==0" class="skeleton">
+			暂时没有数据
+		</view>
+		<slot v-else></slot>
+	</view>
+</template>
+
+<script>
+	export default {
+		props: {
+			loading: {
+				type: Boolean,
+				default: true
+			},
+			list: {
+				type: Array,
+				default: [1]
+			}
+		}
+	}
+</script>
+
+<style lang="scss" scoped>
+	.skeleton {
+		display: flex;
+		justify-content: center;
+		align-items: center;
+		padding: 50rpx;
+		height: 320rpx;
+	}
+
+	.led {
+		width: 10rpx;
+		height: 30rpx;
+		border-radius: 10rpx;
+		top: 50rpx;
+		position: absolute;
+		transform: rotate(calc(360deg / var(--all) * var(--i)));
+		transform-origin: 0 160rpx;
+		animation: loading 2s linear infinite;
+		animation-delay: calc(var(--i) * 1s);
+		background-color: green;
+	}
+
+	@keyframes loading {
+		from {
+			opacity: 0;
+		}
+
+		to {
+			opacity: 1;
+		}
+	}
+
+	.spinner {
+		margin: 100px auto;
+		width: 20px;
+		height: 20px;
+		position: relative;
+	}
+
+	.container1>div,
+	.container2>div,
+	.container3>div {
+		width: 6px;
+		height: 6px;
+		background-color: #333;
+
+		border-radius: 100%;
+		position: absolute;
+		-webkit-animation: bouncedelay 1.2s infinite ease-in-out;
+		animation: bouncedelay 1.2s infinite ease-in-out;
+		-webkit-animation-fill-mode: both;
+		animation-fill-mode: both;
+	}
+
+	.spinner .spinner-container {
+		position: absolute;
+		width: 100%;
+		height: 100%;
+	}
+
+	.container2 {
+		-webkit-transform: rotateZ(45deg);
+		transform: rotateZ(45deg);
+	}
+
+	.container3 {
+		-webkit-transform: rotateZ(90deg);
+		transform: rotateZ(90deg);
+	}
+
+	.circle1 {
+		top: 0;
+		left: 0;
+	}
+
+	.circle2 {
+		top: 0;
+		right: 0;
+	}
+
+	.circle3 {
+		right: 0;
+		bottom: 0;
+	}
+
+	.circle4 {
+		left: 0;
+		bottom: 0;
+	}
+
+	.container2 .circle1 {
+		-webkit-animation-delay: -1.1s;
+		animation-delay: -1.1s;
+	}
+
+	.container3 .circle1 {
+		-webkit-animation-delay: -1.0s;
+		animation-delay: -1.0s;
+	}
+
+	.container1 .circle2 {
+		-webkit-animation-delay: -0.9s;
+		animation-delay: -0.9s;
+	}
+
+	.container2 .circle2 {
+		-webkit-animation-delay: -0.8s;
+		animation-delay: -0.8s;
+	}
+
+	.container3 .circle2 {
+		-webkit-animation-delay: -0.7s;
+		animation-delay: -0.7s;
+	}
+
+	.container1 .circle3 {
+		-webkit-animation-delay: -0.6s;
+		animation-delay: -0.6s;
+	}
+
+	.container2 .circle3 {
+		-webkit-animation-delay: -0.5s;
+		animation-delay: -0.5s;
+	}
+
+	.container3 .circle3 {
+		-webkit-animation-delay: -0.4s;
+		animation-delay: -0.4s;
+	}
+
+	.container1 .circle4 {
+		-webkit-animation-delay: -0.3s;
+		animation-delay: -0.3s;
+	}
+
+	.container2 .circle4 {
+		-webkit-animation-delay: -0.2s;
+		animation-delay: -0.2s;
+	}
+
+	.container3 .circle4 {
+		-webkit-animation-delay: -0.1s;
+		animation-delay: -0.1s;
+	}
+
+	@-webkit-keyframes bouncedelay {
+
+		0%,
+		80%,
+		100% {
+			-webkit-transform: scale(0.0)
+		}
+
+		40% {
+			-webkit-transform: scale(1.0)
+		}
+	}
+
+	@keyframes bouncedelay {
+
+		0%,
+		80%,
+		100% {
+			transform: scale(0.0);
+			-webkit-transform: scale(0.0);
+		}
+
+		40% {
+			transform: scale(1.0);
+			-webkit-transform: scale(1.0);
+		}
+	}
+</style>

+ 177 - 0
src/components/loading/loading.vue

@@ -0,0 +1,177 @@
+<template>
+	<view>
+		<div class="spinner">
+			<div class="spinner-container container1">
+				<div class="circle1"></div>
+				<div class="circle2"></div>
+				<div class="circle3"></div>
+				<div class="circle4"></div>
+			</div>
+			<div class="spinner-container container2">
+				<div class="circle1"></div>
+				<div class="circle2"></div>
+				<div class="circle3"></div>
+				<div class="circle4"></div>
+			</div>
+			<div class="spinner-container container3">
+				<div class="circle1"></div>
+				<div class="circle2"></div>
+				<div class="circle3"></div>
+				<div class="circle4"></div>
+			</div>
+		</div>
+	</view>
+</template>
+
+<script>
+	export default {
+		data() {
+			return {
+
+			};
+		}
+	}
+</script>
+
+<style lang="scss">
+	.spinner {
+		margin: 10px auto;
+		width: 20px;
+		height: 20px;
+		position: relative;
+	}
+
+	.container1>div,
+	.container2>div,
+	.container3>div {
+		width: 6px;
+		height: 6px;
+		background-color: #333;
+
+		border-radius: 100%;
+		position: absolute;
+		-webkit-animation: bouncedelay 1.2s infinite ease-in-out;
+		animation: bouncedelay 1.2s infinite ease-in-out;
+		-webkit-animation-fill-mode: both;
+		animation-fill-mode: both;
+	}
+
+	.spinner .spinner-container {
+		position: absolute;
+		width: 100%;
+		height: 100%;
+	}
+
+	.container2 {
+		-webkit-transform: rotateZ(45deg);
+		transform: rotateZ(45deg);
+	}
+
+	.container3 {
+		-webkit-transform: rotateZ(90deg);
+		transform: rotateZ(90deg);
+	}
+
+	.circle1 {
+		top: 0;
+		left: 0;
+	}
+
+	.circle2 {
+		top: 0;
+		right: 0;
+	}
+
+	.circle3 {
+		right: 0;
+		bottom: 0;
+	}
+
+	.circle4 {
+		left: 0;
+		bottom: 0;
+	}
+
+	.container2 .circle1 {
+		-webkit-animation-delay: -1.1s;
+		animation-delay: -1.1s;
+	}
+
+	.container3 .circle1 {
+		-webkit-animation-delay: -1.0s;
+		animation-delay: -1.0s;
+	}
+
+	.container1 .circle2 {
+		-webkit-animation-delay: -0.9s;
+		animation-delay: -0.9s;
+	}
+
+	.container2 .circle2 {
+		-webkit-animation-delay: -0.8s;
+		animation-delay: -0.8s;
+	}
+
+	.container3 .circle2 {
+		-webkit-animation-delay: -0.7s;
+		animation-delay: -0.7s;
+	}
+
+	.container1 .circle3 {
+		-webkit-animation-delay: -0.6s;
+		animation-delay: -0.6s;
+	}
+
+	.container2 .circle3 {
+		-webkit-animation-delay: -0.5s;
+		animation-delay: -0.5s;
+	}
+
+	.container3 .circle3 {
+		-webkit-animation-delay: -0.4s;
+		animation-delay: -0.4s;
+	}
+
+	.container1 .circle4 {
+		-webkit-animation-delay: -0.3s;
+		animation-delay: -0.3s;
+	}
+
+	.container2 .circle4 {
+		-webkit-animation-delay: -0.2s;
+		animation-delay: -0.2s;
+	}
+
+	.container3 .circle4 {
+		-webkit-animation-delay: -0.1s;
+		animation-delay: -0.1s;
+	}
+
+	@-webkit-keyframes bouncedelay {
+
+		0%,
+		80%,
+		100% {
+			-webkit-transform: scale(0.0)
+		}
+
+		40% {
+			-webkit-transform: scale(1.0)
+		}
+	}
+
+	@keyframes bouncedelay {
+
+		0%,
+		80%,
+		100% {
+			transform: scale(0.0);
+			-webkit-transform: scale(0.0);
+		}
+
+		40% {
+			transform: scale(1.0);
+			-webkit-transform: scale(1.0);
+		}
+	}
+</style>

+ 38 - 0
src/components/m-banner/m-banner.vue

@@ -0,0 +1,38 @@
+<template>
+	<swiper class="swiper-box" :style="{height:`${height}rpx`}" :current="current" autoplay circular indicator-dots>
+		<swiper-item v-for="(item,index) in bannerList" :key='item.id'>
+			<image @click="$utils.route.clickJumpType(item)" class="image" :src="item.fileUrl" mode="scaleToFill"
+				:draggable="false" />
+		</swiper-item>
+	</swiper>
+</template>
+
+<script>
+	export default {
+		props: {
+			bannerList: {
+				type: Array,
+				default: []
+			},
+			height: {
+				type: String,
+				default: '342'
+			}
+		}
+	}
+</script>
+
+<style lang="scss">
+	.swiper-box {
+		width: 690rpx;
+		margin: 20rpx auto;
+		border-radius: 20rpx;
+		overflow: hidden;
+
+		.image {
+			width: 100%;
+			height: 100%;
+			border-radius: 20rpx;
+		}
+	}
+</style>

+ 65 - 0
src/components/m-home-bottomad/m-home-bottomad.vue

@@ -0,0 +1,65 @@
+<template>
+	<view class="bottom-ad" v-for="(item,index) in bottomAD" :key='item.id' @click="$utils.route.clickJumpType(item.$orig)">
+		<image style="width: 100%;" :src="item.fileUrl" mode="widthFix"></image>
+		<text>今日仅剩{{index|dynamicQuantity}}个</text>
+		<button>免费领取</button>
+	</view>
+</template>
+
+<script>
+	export default {
+		name: "m-home-bottomad",
+		props:{
+			bottomAD:{
+				type: Array,
+				default:[]
+			}
+		},
+		filters: {
+			dynamicQuantity(index) {
+				index++
+				let x = new Date().getHours() / 3
+				let num = ((x - 8) ** 2) + index * (8 - x) * 1 + index * 3 + 1
+				return parseInt(num)
+			}
+		},
+	}
+</script>
+
+<style lang="scss">
+	.bottom-ad {
+		margin-top: 15rpx;
+		position: relative;
+
+		&:nth-child(2) {
+			margin-top: 20rpx;
+		}
+
+		text {
+			position: absolute;
+			top: 104rpx;
+			left: 220rpx;
+			padding: 10rpx 15rpx;
+			background: #FFE1D9;
+			font-size: 22rpx;
+			font-family: PingFang SC;
+			font-weight: 400;
+			color: #A40303;
+		}
+
+		button {
+			position: absolute;
+			top: 67rpx;
+			right: 40rpx;
+			display: inline-block;
+			margin: 0;
+			padding: 0rpx 26rpx;
+			background: linear-gradient(90deg, #E31818, #ED3E24, #ED4F24);
+			border-radius: 30rpx;
+			font-size: 26rpx;
+			font-family: PingFang SC;
+			font-weight: 400;
+			color: #FFFFFF;
+		}
+	}
+</style>

+ 75 - 0
src/components/m-home-coupon/m-home-coupon.vue

@@ -0,0 +1,75 @@
+<template>
+	<view class="eat-box">
+		<view class="eat" v-for="(item,index) in couponList" :key='item.id' @click="$utils.route.clickJumpType(item.$orig)">
+			<image :src="item.fileUrl" mode="scaleToFill" class="img"></image>
+			<view class="text-box">
+				<text class="text-1">{{item.pictureName}}</text>
+				<text class="text-2">{{item.dataDescribe.split(' ')[0]}}</text>
+				<text class="text-3">{{item.dataDescribe.split(' ')[1]}}</text>
+			</view>
+		</view>
+	</view>
+</template>
+
+<script>
+	export default {
+		name:"m-home-coupon",
+		props:{
+			couponList:{
+				type: Array,
+				default:[]
+			}
+		}
+	}
+</script>
+
+<style lang="scss">
+		.eat-box {
+			margin-top: 30rpx;
+			display: flex;
+			justify-content: space-between;
+
+			.eat {
+				width: 158rpx;
+				height: 240rpx;
+				position: relative;
+
+				.img {
+					width: 100%;
+					height: 100%;
+				}
+
+				.text-box {
+					display: flex;
+					flex-direction: column;
+					justify-content: center;
+					align-items: center;
+					position: absolute;
+					bottom: 10rpx;
+					left: 50%;
+					width: 100%;
+					transform: translateX(-50%);
+
+					.text-1 {
+						font-size: 24rpx;
+						color: #0F0404;
+						text-align: center;
+					}
+
+					.text-2 {
+						margin-top: 5rpx;
+						font-size: 20rpx;
+						color: #FE3232;
+						text-align: center;
+					}
+
+					.text-3 {
+						font-size: 20rpx;
+						color: #666666;
+						text-align: center;
+					}
+				}
+
+			}
+		}
+</style>

+ 68 - 0
src/components/m-home-menu/m-home-menu.vue

@@ -0,0 +1,68 @@
+<template>
+	<view class="menu-box">
+		<view class="menu" v-for="(item,index) in menuList" :key='item.id' @click="$utils.route.clickJumpType(item)">
+			<image :src="item.fileUrl" mode="scaleToFill" class="img"></image>
+			<text class="text-1">{{item.pictureName}}</text>
+			<text class="text-2">{{item.dataDescribe || '暂无描述'}}</text>
+		</view>
+	</view>
+</template>
+
+<script>
+	export default {
+		name: "m-home-menu",
+		props:{
+			menuList:{
+				type: Array,
+				default:[]
+			}
+		}
+	}
+</script>
+
+<style lang="scss">
+	.menu-box {
+		display: flex;
+		justify-content: flex-start;
+		flex-wrap: wrap;
+		margin: 0 -10rpx;
+
+		.menu {
+			width: 20%;
+			padding: 0 10rpx;
+			box-sizing: border-box;
+			// height: 121rpx;
+			margin-top: 40rpx;
+			display: flex;
+			flex-direction: column;
+			justify-content: space-between;
+			align-items: center;
+
+			.img {
+				flex-shrink: 0;
+				width: 83rpx;
+				height: 83rpx;
+				border-radius: 50%;
+			}
+
+			.text-1 {
+				margin-top: 10rpx;
+				font-size: 24rpx;
+				color: #0F0404;
+				text-align: center;
+				overflow: hidden;
+				text-overflow: ellipsis;
+				white-space: nowrap;
+			}
+
+			.text-2 {
+				font-size: 20rpx;
+				color: #666666;
+				text-align: center;
+				overflow: hidden;
+				text-overflow: ellipsis;
+				white-space: nowrap;
+			}
+		}
+	}
+</style>

+ 194 - 0
src/components/m-home-pdd/m-home-pdd.vue

@@ -0,0 +1,194 @@
+<template>
+	<view class="item-box">
+		<view class="item-titBox">
+			<text class="item-tit">学车必备</text>
+			<!-- <text class="item-tit-right" @click="$utils.route.goPage('/pages/carVideo/index')">更多类型 ></text> -->
+		</view>
+		<loadSke :loading='pddLoading' :list='pddList'>
+			<view class="flex-box">
+				<view class="film-box" v-for="(item,index) in pddList" :key='index'
+					@click="pddGoApp({appId:item.we_app_info.app_id,path:item.we_app_info.page_path})">
+					<image :src="item.goods_image_url" mode="widthFix" class="img" draggable></image>
+					<view class="bottom-box">
+						<view class="tit">
+							<text class="text-1">{{item.goods_name}}</text>
+						</view>
+						<view class="des-box">
+							<view class="des">{{item.unified_tags}}</view>
+						</view>
+						<view class="buy-box">
+							<text class="price">{{'¥'+(item.min_group_price)/100}}</text>
+							<button type="default" class="buy">活动价
+								{{'¥'+(item.min_group_price-item.coupon_discount)/100}}</button>
+						</view>
+					</view>
+				</view>
+				<view v-if="pddDataLoading" class="bottom-loading">
+					<loading />
+				</view>
+			</view>
+		</loadSke>
+	</view>
+</template>
+
+<script>
+	export default {
+		name:"m-home-pdd",
+		data:()=>({
+			pddList: [],
+			pddLoading: true,
+			limit: 6,
+			page: 0,
+			pddDataLoading: false,
+		}),
+		mounted() {
+			this.init()
+		},
+		methods: {
+			pddGoApp(data) {
+				this.$utils.goMiniApp(JSON.stringify(data))
+			},
+			onBottom() {
+				if (this.pddDataLoading) return
+				this.pddDataLoading = true
+				this.page++
+				this.$api.home.getPddWxData({
+					limit: this.limit,
+					offset: this.page * this.limit
+				}).then(res => {
+					this.pddList = this.pddList.concat(res)
+					this.$nextTick(() => {
+						this.pddLoading = false
+						this.pddDataLoading = false
+					})
+				})
+			},
+			init() {
+				this.$api.home.getPddWxData({
+					limit: this.limit,
+					offset: this.page * this.limit
+				}).then(res => {
+					this.pddList = res
+					this.$nextTick(() => {
+						this.pddLoading = false
+					})
+				})
+			}
+		}
+	}
+</script>
+
+<style lang="scss" scoped>
+	.item-box {
+		background-color: #fff;
+		// margin-top: 40rpx;
+
+		.item-titBox {
+			display: flex;
+			justify-content: space-between;
+			align-items: center;
+			padding: 20rpx;
+			border-bottom: 1rpx solid #e8e8e8;
+
+			.item-tit {
+				border-left: 8rpx solid #E31818;
+				font-size: 30rpx;
+				padding: 11rpx;
+				margin-left: 20rpx;
+			}
+
+			.item-tit-right {
+				font-size: 26rpx;
+				color: #666666;
+				line-height: 58rpx;
+				padding: 11rpx;
+			}
+		}
+
+		.flex-box {
+			width: 100%;
+			display: flex;
+			justify-content: center;
+			align-items: flex-start;
+			flex-wrap: wrap;
+			background-color: #F8F8F8;
+			padding-bottom: 20rpx;
+
+			.film-box {
+				width: 334rpx;
+				border-radius: 20rpx;
+				overflow: hidden;
+				background: #FFFFFF;
+				margin: 30rpx 11rpx 0;
+
+				.img {
+					width: 100%;
+				}
+
+				.bottom-box {
+					padding: 30rpx 20rpx;
+
+					.tit {
+						display: flex;
+						justify-content: space-between;
+
+						.text-1 {
+							width: 100%;
+							font-size: 26rpx;
+							overflow: hidden;
+							text-overflow: ellipsis;
+							// white-space: nowrap;
+						}
+					}
+
+					.des-box {
+						margin-top: 10rpx;
+
+						.des {
+							width: 100%;
+							font-size: 22rpx;
+							color: #666666;
+							overflow: hidden;
+							text-overflow: ellipsis;
+							white-space: nowrap;
+						}
+					}
+
+					.buy-box {
+						margin-top: 20rpx;
+						display: flex;
+						justify-content: flex-start;
+						align-items: center;
+
+						.price {
+							// color: #E31818;
+							text-decoration: line-through;
+							font-size: 34rpx;
+						}
+
+						.buy {
+							height: 40rpx;
+							background: linear-gradient(90deg, #E31818, #ED3E24, #ED4F24);
+							border-radius: 20rpx;
+							margin-left: 10rpx;
+							font-size: 20rpx;
+							color: #FFFFFF;
+							display: flex;
+							justify-content: center;
+							align-items: center;
+							white-space: nowrap;
+						}
+					}
+
+				}
+
+			}
+
+		}
+
+		.bottom-loading {
+			margin-top: 5rpx;
+			padding: 10rpx;
+		}
+	}
+</style>

+ 539 - 0
src/components/m-icon/demo.css

@@ -0,0 +1,539 @@
+/* Logo 字体 */
+@font-face {
+  font-family: "iconfont logo";
+  src: url('https://at.alicdn.com/t/font_985780_km7mi63cihi.eot?t=1545807318834');
+  src: url('https://at.alicdn.com/t/font_985780_km7mi63cihi.eot?t=1545807318834#iefix') format('embedded-opentype'),
+    url('https://at.alicdn.com/t/font_985780_km7mi63cihi.woff?t=1545807318834') format('woff'),
+    url('https://at.alicdn.com/t/font_985780_km7mi63cihi.ttf?t=1545807318834') format('truetype'),
+    url('https://at.alicdn.com/t/font_985780_km7mi63cihi.svg?t=1545807318834#iconfont') format('svg');
+}
+
+.logo {
+  font-family: "iconfont logo";
+  font-size: 160px;
+  font-style: normal;
+  -webkit-font-smoothing: antialiased;
+  -moz-osx-font-smoothing: grayscale;
+}
+
+/* tabs */
+.nav-tabs {
+  position: relative;
+}
+
+.nav-tabs .nav-more {
+  position: absolute;
+  right: 0;
+  bottom: 0;
+  height: 42px;
+  line-height: 42px;
+  color: #666;
+}
+
+#tabs {
+  border-bottom: 1px solid #eee;
+}
+
+#tabs li {
+  cursor: pointer;
+  width: 100px;
+  height: 40px;
+  line-height: 40px;
+  text-align: center;
+  font-size: 16px;
+  border-bottom: 2px solid transparent;
+  position: relative;
+  z-index: 1;
+  margin-bottom: -1px;
+  color: #666;
+}
+
+
+#tabs .active {
+  border-bottom-color: #f00;
+  color: #222;
+}
+
+.tab-container .content {
+  display: none;
+}
+
+/* 页面布局 */
+.main {
+  padding: 30px 100px;
+  width: 960px;
+  margin: 0 auto;
+}
+
+.main .logo {
+  color: #333;
+  text-align: left;
+  margin-bottom: 30px;
+  line-height: 1;
+  height: 110px;
+  margin-top: -50px;
+  overflow: hidden;
+  *zoom: 1;
+}
+
+.main .logo a {
+  font-size: 160px;
+  color: #333;
+}
+
+.helps {
+  margin-top: 40px;
+}
+
+.helps pre {
+  padding: 20px;
+  margin: 10px 0;
+  border: solid 1px #e7e1cd;
+  background-color: #fffdef;
+  overflow: auto;
+}
+
+.icon_lists {
+  width: 100% !important;
+  overflow: hidden;
+  *zoom: 1;
+}
+
+.icon_lists li {
+  width: 100px;
+  margin-bottom: 10px;
+  margin-right: 20px;
+  text-align: center;
+  list-style: none !important;
+  cursor: default;
+}
+
+.icon_lists li .code-name {
+  line-height: 1.2;
+}
+
+.icon_lists .icon {
+  display: block;
+  height: 100px;
+  line-height: 100px;
+  font-size: 42px;
+  margin: 10px auto;
+  color: #333;
+  -webkit-transition: font-size 0.25s linear, width 0.25s linear;
+  -moz-transition: font-size 0.25s linear, width 0.25s linear;
+  transition: font-size 0.25s linear, width 0.25s linear;
+}
+
+.icon_lists .icon:hover {
+  font-size: 100px;
+}
+
+.icon_lists .svg-icon {
+  /* 通过设置 font-size 来改变图标大小 */
+  width: 1em;
+  /* 图标和文字相邻时,垂直对齐 */
+  vertical-align: -0.15em;
+  /* 通过设置 color 来改变 SVG 的颜色/fill */
+  fill: currentColor;
+  /* path 和 stroke 溢出 viewBox 部分在 IE 下会显示
+      normalize.css 中也包含这行 */
+  overflow: hidden;
+}
+
+.icon_lists li .name,
+.icon_lists li .code-name {
+  color: #666;
+}
+
+/* markdown 样式 */
+.markdown {
+  color: #666;
+  font-size: 14px;
+  line-height: 1.8;
+}
+
+.highlight {
+  line-height: 1.5;
+}
+
+.markdown img {
+  vertical-align: middle;
+  max-width: 100%;
+}
+
+.markdown h1 {
+  color: #404040;
+  font-weight: 500;
+  line-height: 40px;
+  margin-bottom: 24px;
+}
+
+.markdown h2,
+.markdown h3,
+.markdown h4,
+.markdown h5,
+.markdown h6 {
+  color: #404040;
+  margin: 1.6em 0 0.6em 0;
+  font-weight: 500;
+  clear: both;
+}
+
+.markdown h1 {
+  font-size: 28px;
+}
+
+.markdown h2 {
+  font-size: 22px;
+}
+
+.markdown h3 {
+  font-size: 16px;
+}
+
+.markdown h4 {
+  font-size: 14px;
+}
+
+.markdown h5 {
+  font-size: 12px;
+}
+
+.markdown h6 {
+  font-size: 12px;
+}
+
+.markdown hr {
+  height: 1px;
+  border: 0;
+  background: #e9e9e9;
+  margin: 16px 0;
+  clear: both;
+}
+
+.markdown p {
+  margin: 1em 0;
+}
+
+.markdown>p,
+.markdown>blockquote,
+.markdown>.highlight,
+.markdown>ol,
+.markdown>ul {
+  width: 80%;
+}
+
+.markdown ul>li {
+  list-style: circle;
+}
+
+.markdown>ul li,
+.markdown blockquote ul>li {
+  margin-left: 20px;
+  padding-left: 4px;
+}
+
+.markdown>ul li p,
+.markdown>ol li p {
+  margin: 0.6em 0;
+}
+
+.markdown ol>li {
+  list-style: decimal;
+}
+
+.markdown>ol li,
+.markdown blockquote ol>li {
+  margin-left: 20px;
+  padding-left: 4px;
+}
+
+.markdown code {
+  margin: 0 3px;
+  padding: 0 5px;
+  background: #eee;
+  border-radius: 3px;
+}
+
+.markdown strong,
+.markdown b {
+  font-weight: 600;
+}
+
+.markdown>table {
+  border-collapse: collapse;
+  border-spacing: 0px;
+  empty-cells: show;
+  border: 1px solid #e9e9e9;
+  width: 95%;
+  margin-bottom: 24px;
+}
+
+.markdown>table th {
+  white-space: nowrap;
+  color: #333;
+  font-weight: 600;
+}
+
+.markdown>table th,
+.markdown>table td {
+  border: 1px solid #e9e9e9;
+  padding: 8px 16px;
+  text-align: left;
+}
+
+.markdown>table th {
+  background: #F7F7F7;
+}
+
+.markdown blockquote {
+  font-size: 90%;
+  color: #999;
+  border-left: 4px solid #e9e9e9;
+  padding-left: 0.8em;
+  margin: 1em 0;
+}
+
+.markdown blockquote p {
+  margin: 0;
+}
+
+.markdown .anchor {
+  opacity: 0;
+  transition: opacity 0.3s ease;
+  margin-left: 8px;
+}
+
+.markdown .waiting {
+  color: #ccc;
+}
+
+.markdown h1:hover .anchor,
+.markdown h2:hover .anchor,
+.markdown h3:hover .anchor,
+.markdown h4:hover .anchor,
+.markdown h5:hover .anchor,
+.markdown h6:hover .anchor {
+  opacity: 1;
+  display: inline-block;
+}
+
+.markdown>br,
+.markdown>p>br {
+  clear: both;
+}
+
+
+.hljs {
+  display: block;
+  background: white;
+  padding: 0.5em;
+  color: #333333;
+  overflow-x: auto;
+}
+
+.hljs-comment,
+.hljs-meta {
+  color: #969896;
+}
+
+.hljs-string,
+.hljs-variable,
+.hljs-template-variable,
+.hljs-strong,
+.hljs-emphasis,
+.hljs-quote {
+  color: #df5000;
+}
+
+.hljs-keyword,
+.hljs-selector-tag,
+.hljs-type {
+  color: #a71d5d;
+}
+
+.hljs-literal,
+.hljs-symbol,
+.hljs-bullet,
+.hljs-attribute {
+  color: #0086b3;
+}
+
+.hljs-section,
+.hljs-name {
+  color: #63a35c;
+}
+
+.hljs-tag {
+  color: #333333;
+}
+
+.hljs-title,
+.hljs-attr,
+.hljs-selector-id,
+.hljs-selector-class,
+.hljs-selector-attr,
+.hljs-selector-pseudo {
+  color: #795da3;
+}
+
+.hljs-addition {
+  color: #55a532;
+  background-color: #eaffea;
+}
+
+.hljs-deletion {
+  color: #bd2c00;
+  background-color: #ffecec;
+}
+
+.hljs-link {
+  text-decoration: underline;
+}
+
+/* 代码高亮 */
+/* PrismJS 1.15.0
+https://prismjs.com/download.html#themes=prism&languages=markup+css+clike+javascript */
+/**
+ * prism.js default theme for JavaScript, CSS and HTML
+ * Based on dabblet (http://dabblet.com)
+ * @author Lea Verou
+ */
+code[class*="language-"],
+pre[class*="language-"] {
+  color: black;
+  background: none;
+  text-shadow: 0 1px white;
+  font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace;
+  text-align: left;
+  white-space: pre;
+  word-spacing: normal;
+  word-break: normal;
+  word-wrap: normal;
+  line-height: 1.5;
+
+  -moz-tab-size: 4;
+  -o-tab-size: 4;
+  tab-size: 4;
+
+  -webkit-hyphens: none;
+  -moz-hyphens: none;
+  -ms-hyphens: none;
+  hyphens: none;
+}
+
+pre[class*="language-"]::-moz-selection,
+pre[class*="language-"] ::-moz-selection,
+code[class*="language-"]::-moz-selection,
+code[class*="language-"] ::-moz-selection {
+  text-shadow: none;
+  background: #b3d4fc;
+}
+
+pre[class*="language-"]::selection,
+pre[class*="language-"] ::selection,
+code[class*="language-"]::selection,
+code[class*="language-"] ::selection {
+  text-shadow: none;
+  background: #b3d4fc;
+}
+
+@media print {
+
+  code[class*="language-"],
+  pre[class*="language-"] {
+    text-shadow: none;
+  }
+}
+
+/* Code blocks */
+pre[class*="language-"] {
+  padding: 1em;
+  margin: .5em 0;
+  overflow: auto;
+}
+
+:not(pre)>code[class*="language-"],
+pre[class*="language-"] {
+  background: #f5f2f0;
+}
+
+/* Inline code */
+:not(pre)>code[class*="language-"] {
+  padding: .1em;
+  border-radius: .3em;
+  white-space: normal;
+}
+
+.token.comment,
+.token.prolog,
+.token.doctype,
+.token.cdata {
+  color: slategray;
+}
+
+.token.punctuation {
+  color: #999;
+}
+
+.namespace {
+  opacity: .7;
+}
+
+.token.property,
+.token.tag,
+.token.boolean,
+.token.number,
+.token.constant,
+.token.symbol,
+.token.deleted {
+  color: #905;
+}
+
+.token.selector,
+.token.attr-name,
+.token.string,
+.token.char,
+.token.builtin,
+.token.inserted {
+  color: #690;
+}
+
+.token.operator,
+.token.entity,
+.token.url,
+.language-css .token.string,
+.style .token.string {
+  color: #9a6e3a;
+  background: hsla(0, 0%, 100%, .5);
+}
+
+.token.atrule,
+.token.attr-value,
+.token.keyword {
+  color: #07a;
+}
+
+.token.function,
+.token.class-name {
+  color: #DD4A68;
+}
+
+.token.regex,
+.token.important,
+.token.variable {
+  color: #e90;
+}
+
+.token.important,
+.token.bold {
+  font-weight: bold;
+}
+
+.token.italic {
+  font-style: italic;
+}
+
+.token.entity {
+  cursor: help;
+}

+ 1267 - 0
src/components/m-icon/demo_index.html

@@ -0,0 +1,1267 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <meta charset="utf-8"/>
+  <title>iconfont Demo</title>
+  <link rel="shortcut icon" href="//img.alicdn.com/imgextra/i2/O1CN01ZyAlrn1MwaMhqz36G_!!6000000001499-73-tps-64-64.ico" type="image/x-icon"/>
+  <link rel="icon" type="image/svg+xml" href="//img.alicdn.com/imgextra/i4/O1CN01EYTRnJ297D6vehehJ_!!6000000008020-55-tps-64-64.svg"/>
+  <link rel="stylesheet" href="https://g.alicdn.com/thx/cube/1.3.2/cube.min.css">
+  <link rel="stylesheet" href="demo.css">
+  <link rel="stylesheet" href="iconfont.css">
+  <script src="iconfont.js"></script>
+  <!-- jQuery -->
+  <script src="https://a1.alicdn.com/oss/uploads/2018/12/26/7bfddb60-08e8-11e9-9b04-53e73bb6408b.js"></script>
+  <!-- 代码高亮 -->
+  <script src="https://a1.alicdn.com/oss/uploads/2018/12/26/a3f714d0-08e6-11e9-8a15-ebf944d7534c.js"></script>
+  <style>
+    .main .logo {
+      margin-top: 0;
+      height: auto;
+    }
+
+    .main .logo a {
+      display: flex;
+      align-items: center;
+    }
+
+    .main .logo .sub-title {
+      margin-left: 0.5em;
+      font-size: 22px;
+      color: #fff;
+      background: linear-gradient(-45deg, #3967FF, #B500FE);
+      -webkit-background-clip: text;
+      -webkit-text-fill-color: transparent;
+    }
+  </style>
+</head>
+<body>
+  <div class="main">
+    <h1 class="logo"><a href="https://www.iconfont.cn/" title="iconfont 首页" target="_blank">
+      <img width="200" src="https://img.alicdn.com/imgextra/i3/O1CN01Mn65HV1FfSEzR6DKv_!!6000000000514-55-tps-228-59.svg">
+      
+    </a></h1>
+    <div class="nav-tabs">
+      <ul id="tabs" class="dib-box">
+        <li class="dib active"><span>Unicode</span></li>
+        <li class="dib"><span>Font class</span></li>
+        <li class="dib"><span>Symbol</span></li>
+      </ul>
+      
+      <a href="https://www.iconfont.cn/manage/index?manage_type=myprojects&projectId=2599049" target="_blank" class="nav-more">查看项目</a>
+      
+    </div>
+    <div class="tab-container">
+      <div class="content unicode" style="display: block;">
+          <ul class="icon_lists dib-box">
+          
+            <li class="dib">
+              <span class="icon iconfont">&#xe637;</span>
+                <div class="name">分享</div>
+                <div class="code-name">&amp;#xe637;</div>
+              </li>
+          
+            <li class="dib">
+              <span class="icon iconfont">&#xe620;</span>
+                <div class="name">点赞</div>
+                <div class="code-name">&amp;#xe620;</div>
+              </li>
+          
+            <li class="dib">
+              <span class="icon iconfont">&#xe629;</span>
+                <div class="name">收 藏</div>
+                <div class="code-name">&amp;#xe629;</div>
+              </li>
+          
+            <li class="dib">
+              <span class="icon iconfont">&#xe611;</span>
+                <div class="name">设置</div>
+                <div class="code-name">&amp;#xe611;</div>
+              </li>
+          
+            <li class="dib">
+              <span class="icon iconfont">&#xe6ad;</span>
+                <div class="name">替换视频</div>
+                <div class="code-name">&amp;#xe6ad;</div>
+              </li>
+          
+            <li class="dib">
+              <span class="icon iconfont">&#xe634;</span>
+                <div class="name">详情</div>
+                <div class="code-name">&amp;#xe634;</div>
+              </li>
+          
+            <li class="dib">
+              <span class="icon iconfont">&#xf5fe;</span>
+                <div class="name">升序</div>
+                <div class="code-name">&amp;#xf5fe;</div>
+              </li>
+          
+            <li class="dib">
+              <span class="icon iconfont">&#xe632;</span>
+                <div class="name">升序</div>
+                <div class="code-name">&amp;#xe632;</div>
+              </li>
+          
+            <li class="dib">
+              <span class="icon iconfont">&#xe61f;</span>
+                <div class="name">叉</div>
+                <div class="code-name">&amp;#xe61f;</div>
+              </li>
+          
+            <li class="dib">
+              <span class="icon iconfont">&#xe61e;</span>
+                <div class="name">勾</div>
+                <div class="code-name">&amp;#xe61e;</div>
+              </li>
+          
+            <li class="dib">
+              <span class="icon iconfont">&#xe61c;</span>
+                <div class="name">删除</div>
+                <div class="code-name">&amp;#xe61c;</div>
+              </li>
+          
+            <li class="dib">
+              <span class="icon iconfont">&#xe61b;</span>
+                <div class="name">非全屏</div>
+                <div class="code-name">&amp;#xe61b;</div>
+              </li>
+          
+            <li class="dib">
+              <span class="icon iconfont">&#xe61a;</span>
+                <div class="name">上传视频</div>
+                <div class="code-name">&amp;#xe61a;</div>
+              </li>
+          
+            <li class="dib">
+              <span class="icon iconfont">&#xe619;</span>
+                <div class="name">学车视频</div>
+                <div class="code-name">&amp;#xe619;</div>
+              </li>
+          
+            <li class="dib">
+              <span class="icon iconfont">&#xe618;</span>
+                <div class="name">锁头</div>
+                <div class="code-name">&amp;#xe618;</div>
+              </li>
+          
+            <li class="dib">
+              <span class="icon iconfont">&#xe617;</span>
+                <div class="name">解锁</div>
+                <div class="code-name">&amp;#xe617;</div>
+              </li>
+          
+            <li class="dib">
+              <span class="icon iconfont">&#xe616;</span>
+                <div class="name">全屏</div>
+                <div class="code-name">&amp;#xe616;</div>
+              </li>
+          
+            <li class="dib">
+              <span class="icon iconfont">&#xe614;</span>
+                <div class="name">暂停</div>
+                <div class="code-name">&amp;#xe614;</div>
+              </li>
+          
+            <li class="dib">
+              <span class="icon iconfont">&#xe62f;</span>
+                <div class="name">箭头</div>
+                <div class="code-name">&amp;#xe62f;</div>
+              </li>
+          
+            <li class="dib">
+              <span class="icon iconfont">&#xe613;</span>
+                <div class="name">播放视频</div>
+                <div class="code-name">&amp;#xe613;</div>
+              </li>
+          
+            <li class="dib">
+              <span class="icon iconfont">&#xf5fd;</span>
+                <div class="name">二手车</div>
+                <div class="code-name">&amp;#xf5fd;</div>
+              </li>
+          
+            <li class="dib">
+              <span class="icon iconfont">&#xe61d;</span>
+                <div class="name">相机</div>
+                <div class="code-name">&amp;#xe61d;</div>
+              </li>
+          
+            <li class="dib">
+              <span class="icon iconfont">&#xe612;</span>
+                <div class="name">添加图片</div>
+                <div class="code-name">&amp;#xe612;</div>
+              </li>
+          
+            <li class="dib">
+              <span class="icon iconfont">&#xe70e;</span>
+                <div class="name">编辑</div>
+                <div class="code-name">&amp;#xe70e;</div>
+              </li>
+          
+            <li class="dib">
+              <span class="icon iconfont">&#xe610;</span>
+                <div class="name">联系客服</div>
+                <div class="code-name">&amp;#xe610;</div>
+              </li>
+          
+            <li class="dib">
+              <span class="icon iconfont">&#xe60f;</span>
+                <div class="name">电话</div>
+                <div class="code-name">&amp;#xe60f;</div>
+              </li>
+          
+            <li class="dib">
+              <span class="icon iconfont">&#xe60e;</span>
+                <div class="name">微信</div>
+                <div class="code-name">&amp;#xe60e;</div>
+              </li>
+          
+            <li class="dib">
+              <span class="icon iconfont">&#xe60d;</span>
+                <div class="name">关闭</div>
+                <div class="code-name">&amp;#xe60d;</div>
+              </li>
+          
+            <li class="dib">
+              <span class="icon iconfont">&#xe60c;</span>
+                <div class="name">勾</div>
+                <div class="code-name">&amp;#xe60c;</div>
+              </li>
+          
+            <li class="dib">
+              <span class="icon iconfont">&#xe60b;</span>
+                <div class="name">搜索</div>
+                <div class="code-name">&amp;#xe60b;</div>
+              </li>
+          
+            <li class="dib">
+              <span class="icon iconfont">&#xe60a;</span>
+                <div class="name">向下2</div>
+                <div class="code-name">&amp;#xe60a;</div>
+              </li>
+          
+            <li class="dib">
+              <span class="icon iconfont">&#xe8ba;</span>
+                <div class="name">向下2</div>
+                <div class="code-name">&amp;#xe8ba;</div>
+              </li>
+          
+            <li class="dib">
+              <span class="icon iconfont">&#xe609;</span>
+                <div class="name">向下</div>
+                <div class="code-name">&amp;#xe609;</div>
+              </li>
+          
+            <li class="dib">
+              <span class="icon iconfont">&#xe606;</span>
+                <div class="name">选中</div>
+                <div class="code-name">&amp;#xe606;</div>
+              </li>
+          
+            <li class="dib">
+              <span class="icon iconfont">&#xe604;</span>
+                <div class="name">type_name_right</div>
+                <div class="code-name">&amp;#xe604;</div>
+              </li>
+          
+            <li class="dib">
+              <span class="icon iconfont">&#xe601;</span>
+                <div class="name">type_name_left</div>
+                <div class="code-name">&amp;#xe601;</div>
+              </li>
+          
+            <li class="dib">
+              <span class="icon iconfont">&#xe665;</span>
+                <div class="name">arrow-right</div>
+                <div class="code-name">&amp;#xe665;</div>
+              </li>
+          
+            <li class="dib">
+              <span class="icon iconfont">&#xe603;</span>
+                <div class="name">意见反馈</div>
+                <div class="code-name">&amp;#xe603;</div>
+              </li>
+          
+            <li class="dib">
+              <span class="icon iconfont">&#xe608;</span>
+                <div class="name">待发货</div>
+                <div class="code-name">&amp;#xe608;</div>
+              </li>
+          
+            <li class="dib">
+              <span class="icon iconfont">&#xe6f2;</span>
+                <div class="name">退款 售后02</div>
+                <div class="code-name">&amp;#xe6f2;</div>
+              </li>
+          
+            <li class="dib">
+              <span class="icon iconfont">&#xe600;</span>
+                <div class="name">全部订单</div>
+                <div class="code-name">&amp;#xe600;</div>
+              </li>
+          
+            <li class="dib">
+              <span class="icon iconfont">&#xe602;</span>
+                <div class="name">交易-完成</div>
+                <div class="code-name">&amp;#xe602;</div>
+              </li>
+          
+            <li class="dib">
+              <span class="icon iconfont">&#xe86a;</span>
+                <div class="name">定位</div>
+                <div class="code-name">&amp;#xe86a;</div>
+              </li>
+          
+            <li class="dib">
+              <span class="icon iconfont">&#xe8b9;</span>
+                <div class="name">当地玩乐2</div>
+                <div class="code-name">&amp;#xe8b9;</div>
+              </li>
+          
+            <li class="dib">
+              <span class="icon iconfont">&#xe607;</span>
+                <div class="name">我 的</div>
+                <div class="code-name">&amp;#xe607;</div>
+              </li>
+          
+            <li class="dib">
+              <span class="icon iconfont">&#xe615;</span>
+                <div class="name">主页</div>
+                <div class="code-name">&amp;#xe615;</div>
+              </li>
+          
+            <li class="dib">
+              <span class="icon iconfont">&#xe642;</span>
+                <div class="name">电影</div>
+                <div class="code-name">&amp;#xe642;</div>
+              </li>
+          
+          </ul>
+          <div class="article markdown">
+          <h2 id="unicode-">Unicode 引用</h2>
+          <hr>
+
+          <p>Unicode 是字体在网页端最原始的应用方式,特点是:</p>
+          <ul>
+            <li>支持按字体的方式去动态调整图标大小,颜色等等。</li>
+            <li>默认情况下不支持多色,直接添加多色图标会自动去色。</li>
+          </ul>
+          <blockquote>
+            <p>注意:新版 iconfont 支持两种方式引用多色图标:SVG symbol 引用方式和彩色字体图标模式。(使用彩色字体图标需要在「编辑项目」中开启「彩色」选项后并重新生成。)</p>
+          </blockquote>
+          <p>Unicode 使用步骤如下:</p>
+          <h3 id="-font-face">第一步:拷贝项目下面生成的 <code>@font-face</code></h3>
+<pre><code class="language-css"
+>@font-face {
+  font-family: 'iconfont';
+  src: url('iconfont.ttf?t=1627377154886') format('truetype');
+}
+</code></pre>
+          <h3 id="-iconfont-">第二步:定义使用 iconfont 的样式</h3>
+<pre><code class="language-css"
+>.iconfont {
+  font-family: "iconfont" !important;
+  font-size: 16px;
+  font-style: normal;
+  -webkit-font-smoothing: antialiased;
+  -moz-osx-font-smoothing: grayscale;
+}
+</code></pre>
+          <h3 id="-">第三步:挑选相应图标并获取字体编码,应用于页面</h3>
+<pre>
+<code class="language-html"
+>&lt;span class="iconfont"&gt;&amp;#x33;&lt;/span&gt;
+</code></pre>
+          <blockquote>
+            <p>"iconfont" 是你项目下的 font-family。可以通过编辑项目查看,默认是 "iconfont"。</p>
+          </blockquote>
+          </div>
+      </div>
+      <div class="content font-class">
+        <ul class="icon_lists dib-box">
+          
+          <li class="dib">
+            <span class="icon iconfont icon-share-fill"></span>
+            <div class="name">
+              分享
+            </div>
+            <div class="code-name">.icon-share-fill
+            </div>
+          </li>
+          
+          <li class="dib">
+            <span class="icon iconfont icon-dianzan"></span>
+            <div class="name">
+              点赞
+            </div>
+            <div class="code-name">.icon-dianzan
+            </div>
+          </li>
+          
+          <li class="dib">
+            <span class="icon iconfont icon-shoucang"></span>
+            <div class="name">
+              收 藏
+            </div>
+            <div class="code-name">.icon-shoucang
+            </div>
+          </li>
+          
+          <li class="dib">
+            <span class="icon iconfont icon-shezhi"></span>
+            <div class="name">
+              设置
+            </div>
+            <div class="code-name">.icon-shezhi
+            </div>
+          </li>
+          
+          <li class="dib">
+            <span class="icon iconfont icon-thsp"></span>
+            <div class="name">
+              替换视频
+            </div>
+            <div class="code-name">.icon-thsp
+            </div>
+          </li>
+          
+          <li class="dib">
+            <span class="icon iconfont icon-xiangqing"></span>
+            <div class="name">
+              详情
+            </div>
+            <div class="code-name">.icon-xiangqing
+            </div>
+          </li>
+          
+          <li class="dib">
+            <span class="icon iconfont icon-jiangxu-copy"></span>
+            <div class="name">
+              升序
+            </div>
+            <div class="code-name">.icon-jiangxu-copy
+            </div>
+          </li>
+          
+          <li class="dib">
+            <span class="icon iconfont icon-qiehuan"></span>
+            <div class="name">
+              升序
+            </div>
+            <div class="code-name">.icon-qiehuan
+            </div>
+          </li>
+          
+          <li class="dib">
+            <span class="icon iconfont icon-cha"></span>
+            <div class="name">
+              叉
+            </div>
+            <div class="code-name">.icon-cha
+            </div>
+          </li>
+          
+          <li class="dib">
+            <span class="icon iconfont icon-gou1"></span>
+            <div class="name">
+              勾
+            </div>
+            <div class="code-name">.icon-gou1
+            </div>
+          </li>
+          
+          <li class="dib">
+            <span class="icon iconfont icon-shanchu"></span>
+            <div class="name">
+              删除
+            </div>
+            <div class="code-name">.icon-shanchu
+            </div>
+          </li>
+          
+          <li class="dib">
+            <span class="icon iconfont icon-feiquanping"></span>
+            <div class="name">
+              非全屏
+            </div>
+            <div class="code-name">.icon-feiquanping
+            </div>
+          </li>
+          
+          <li class="dib">
+            <span class="icon iconfont icon-shangchuanshipin"></span>
+            <div class="name">
+              上传视频
+            </div>
+            <div class="code-name">.icon-shangchuanshipin
+            </div>
+          </li>
+          
+          <li class="dib">
+            <span class="icon iconfont icon-xcsp"></span>
+            <div class="name">
+              学车视频
+            </div>
+            <div class="code-name">.icon-xcsp
+            </div>
+          </li>
+          
+          <li class="dib">
+            <span class="icon iconfont icon-suotou"></span>
+            <div class="name">
+              锁头
+            </div>
+            <div class="code-name">.icon-suotou
+            </div>
+          </li>
+          
+          <li class="dib">
+            <span class="icon iconfont icon-jiesuo"></span>
+            <div class="name">
+              解锁
+            </div>
+            <div class="code-name">.icon-jiesuo
+            </div>
+          </li>
+          
+          <li class="dib">
+            <span class="icon iconfont icon-quanping"></span>
+            <div class="name">
+              全屏
+            </div>
+            <div class="code-name">.icon-quanping
+            </div>
+          </li>
+          
+          <li class="dib">
+            <span class="icon iconfont icon-zanting"></span>
+            <div class="name">
+              暂停
+            </div>
+            <div class="code-name">.icon-zanting
+            </div>
+          </li>
+          
+          <li class="dib">
+            <span class="icon iconfont icon-jiantou"></span>
+            <div class="name">
+              箭头
+            </div>
+            <div class="code-name">.icon-jiantou
+            </div>
+          </li>
+          
+          <li class="dib">
+            <span class="icon iconfont icon-bofangshipin"></span>
+            <div class="name">
+              播放视频
+            </div>
+            <div class="code-name">.icon-bofangshipin
+            </div>
+          </li>
+          
+          <li class="dib">
+            <span class="icon iconfont icon-ershouche"></span>
+            <div class="name">
+              二手车
+            </div>
+            <div class="code-name">.icon-ershouche
+            </div>
+          </li>
+          
+          <li class="dib">
+            <span class="icon iconfont icon-xiangji"></span>
+            <div class="name">
+              相机
+            </div>
+            <div class="code-name">.icon-xiangji
+            </div>
+          </li>
+          
+          <li class="dib">
+            <span class="icon iconfont icon-tianjia"></span>
+            <div class="name">
+              添加图片
+            </div>
+            <div class="code-name">.icon-tianjia
+            </div>
+          </li>
+          
+          <li class="dib">
+            <span class="icon iconfont icon-bianji"></span>
+            <div class="name">
+              编辑
+            </div>
+            <div class="code-name">.icon-bianji
+            </div>
+          </li>
+          
+          <li class="dib">
+            <span class="icon iconfont icon-lxkf"></span>
+            <div class="name">
+              联系客服
+            </div>
+            <div class="code-name">.icon-lxkf
+            </div>
+          </li>
+          
+          <li class="dib">
+            <span class="icon iconfont icon-dianhua"></span>
+            <div class="name">
+              电话
+            </div>
+            <div class="code-name">.icon-dianhua
+            </div>
+          </li>
+          
+          <li class="dib">
+            <span class="icon iconfont icon-weixin"></span>
+            <div class="name">
+              微信
+            </div>
+            <div class="code-name">.icon-weixin
+            </div>
+          </li>
+          
+          <li class="dib">
+            <span class="icon iconfont icon-guanbi"></span>
+            <div class="name">
+              关闭
+            </div>
+            <div class="code-name">.icon-guanbi
+            </div>
+          </li>
+          
+          <li class="dib">
+            <span class="icon iconfont icon-gou"></span>
+            <div class="name">
+              勾
+            </div>
+            <div class="code-name">.icon-gou
+            </div>
+          </li>
+          
+          <li class="dib">
+            <span class="icon iconfont icon-sousuo"></span>
+            <div class="name">
+              搜索
+            </div>
+            <div class="code-name">.icon-sousuo
+            </div>
+          </li>
+          
+          <li class="dib">
+            <span class="icon iconfont icon-xiangxia2"></span>
+            <div class="name">
+              向下2
+            </div>
+            <div class="code-name">.icon-xiangxia2
+            </div>
+          </li>
+          
+          <li class="dib">
+            <span class="icon iconfont icon-xiangshang"></span>
+            <div class="name">
+              向下2
+            </div>
+            <div class="code-name">.icon-xiangshang
+            </div>
+          </li>
+          
+          <li class="dib">
+            <span class="icon iconfont icon-xiangxia"></span>
+            <div class="name">
+              向下
+            </div>
+            <div class="code-name">.icon-xiangxia
+            </div>
+          </li>
+          
+          <li class="dib">
+            <span class="icon iconfont icon-xuanzhong"></span>
+            <div class="name">
+              选中
+            </div>
+            <div class="code-name">.icon-xuanzhong
+            </div>
+          </li>
+          
+          <li class="dib">
+            <span class="icon iconfont icon-name_left"></span>
+            <div class="name">
+              type_name_right
+            </div>
+            <div class="code-name">.icon-name_left
+            </div>
+          </li>
+          
+          <li class="dib">
+            <span class="icon iconfont icon-name_right"></span>
+            <div class="name">
+              type_name_left
+            </div>
+            <div class="code-name">.icon-name_right
+            </div>
+          </li>
+          
+          <li class="dib">
+            <span class="icon iconfont icon-arrow-right"></span>
+            <div class="name">
+              arrow-right
+            </div>
+            <div class="code-name">.icon-arrow-right
+            </div>
+          </li>
+          
+          <li class="dib">
+            <span class="icon iconfont icon-yjfk"></span>
+            <div class="name">
+              意见反馈
+            </div>
+            <div class="code-name">.icon-yjfk
+            </div>
+          </li>
+          
+          <li class="dib">
+            <span class="icon iconfont icon-dfh"></span>
+            <div class="name">
+              待发货
+            </div>
+            <div class="code-name">.icon-dfh
+            </div>
+          </li>
+          
+          <li class="dib">
+            <span class="icon iconfont icon-tksh"></span>
+            <div class="name">
+              退款 售后02
+            </div>
+            <div class="code-name">.icon-tksh
+            </div>
+          </li>
+          
+          <li class="dib">
+            <span class="icon iconfont icon-qbdd"></span>
+            <div class="name">
+              全部订单
+            </div>
+            <div class="code-name">.icon-qbdd
+            </div>
+          </li>
+          
+          <li class="dib">
+            <span class="icon iconfont icon-jywc"></span>
+            <div class="name">
+              交易-完成
+            </div>
+            <div class="code-name">.icon-jywc
+            </div>
+          </li>
+          
+          <li class="dib">
+            <span class="icon iconfont icon-dingwei"></span>
+            <div class="name">
+              定位
+            </div>
+            <div class="code-name">.icon-dingwei
+            </div>
+          </li>
+          
+          <li class="dib">
+            <span class="icon iconfont icon-ddwl"></span>
+            <div class="name">
+              当地玩乐2
+            </div>
+            <div class="code-name">.icon-ddwl
+            </div>
+          </li>
+          
+          <li class="dib">
+            <span class="icon iconfont icon-wode"></span>
+            <div class="name">
+              我 的
+            </div>
+            <div class="code-name">.icon-wode
+            </div>
+          </li>
+          
+          <li class="dib">
+            <span class="icon iconfont icon-shouye"></span>
+            <div class="name">
+              主页
+            </div>
+            <div class="code-name">.icon-shouye
+            </div>
+          </li>
+          
+          <li class="dib">
+            <span class="icon iconfont icon-dianying"></span>
+            <div class="name">
+              电影
+            </div>
+            <div class="code-name">.icon-dianying
+            </div>
+          </li>
+          
+        </ul>
+        <div class="article markdown">
+        <h2 id="font-class-">font-class 引用</h2>
+        <hr>
+
+        <p>font-class 是 Unicode 使用方式的一种变种,主要是解决 Unicode 书写不直观,语意不明确的问题。</p>
+        <p>与 Unicode 使用方式相比,具有如下特点:</p>
+        <ul>
+          <li>相比于 Unicode 语意明确,书写更直观。可以很容易分辨这个 icon 是什么。</li>
+          <li>因为使用 class 来定义图标,所以当要替换图标时,只需要修改 class 里面的 Unicode 引用。</li>
+        </ul>
+        <p>使用步骤如下:</p>
+        <h3 id="-fontclass-">第一步:引入项目下面生成的 fontclass 代码:</h3>
+<pre><code class="language-html">&lt;link rel="stylesheet" href="./iconfont.css"&gt;
+</code></pre>
+        <h3 id="-">第二步:挑选相应图标并获取类名,应用于页面:</h3>
+<pre><code class="language-html">&lt;span class="iconfont icon-xxx"&gt;&lt;/span&gt;
+</code></pre>
+        <blockquote>
+          <p>"
+            iconfont" 是你项目下的 font-family。可以通过编辑项目查看,默认是 "iconfont"。</p>
+        </blockquote>
+      </div>
+      </div>
+      <div class="content symbol">
+          <ul class="icon_lists dib-box">
+          
+            <li class="dib">
+                <svg class="icon svg-icon" aria-hidden="true">
+                  <use xlink:href="#icon-share-fill"></use>
+                </svg>
+                <div class="name">分享</div>
+                <div class="code-name">#icon-share-fill</div>
+            </li>
+          
+            <li class="dib">
+                <svg class="icon svg-icon" aria-hidden="true">
+                  <use xlink:href="#icon-dianzan"></use>
+                </svg>
+                <div class="name">点赞</div>
+                <div class="code-name">#icon-dianzan</div>
+            </li>
+          
+            <li class="dib">
+                <svg class="icon svg-icon" aria-hidden="true">
+                  <use xlink:href="#icon-shoucang"></use>
+                </svg>
+                <div class="name">收 藏</div>
+                <div class="code-name">#icon-shoucang</div>
+            </li>
+          
+            <li class="dib">
+                <svg class="icon svg-icon" aria-hidden="true">
+                  <use xlink:href="#icon-shezhi"></use>
+                </svg>
+                <div class="name">设置</div>
+                <div class="code-name">#icon-shezhi</div>
+            </li>
+          
+            <li class="dib">
+                <svg class="icon svg-icon" aria-hidden="true">
+                  <use xlink:href="#icon-thsp"></use>
+                </svg>
+                <div class="name">替换视频</div>
+                <div class="code-name">#icon-thsp</div>
+            </li>
+          
+            <li class="dib">
+                <svg class="icon svg-icon" aria-hidden="true">
+                  <use xlink:href="#icon-xiangqing"></use>
+                </svg>
+                <div class="name">详情</div>
+                <div class="code-name">#icon-xiangqing</div>
+            </li>
+          
+            <li class="dib">
+                <svg class="icon svg-icon" aria-hidden="true">
+                  <use xlink:href="#icon-jiangxu-copy"></use>
+                </svg>
+                <div class="name">升序</div>
+                <div class="code-name">#icon-jiangxu-copy</div>
+            </li>
+          
+            <li class="dib">
+                <svg class="icon svg-icon" aria-hidden="true">
+                  <use xlink:href="#icon-qiehuan"></use>
+                </svg>
+                <div class="name">升序</div>
+                <div class="code-name">#icon-qiehuan</div>
+            </li>
+          
+            <li class="dib">
+                <svg class="icon svg-icon" aria-hidden="true">
+                  <use xlink:href="#icon-cha"></use>
+                </svg>
+                <div class="name">叉</div>
+                <div class="code-name">#icon-cha</div>
+            </li>
+          
+            <li class="dib">
+                <svg class="icon svg-icon" aria-hidden="true">
+                  <use xlink:href="#icon-gou1"></use>
+                </svg>
+                <div class="name">勾</div>
+                <div class="code-name">#icon-gou1</div>
+            </li>
+          
+            <li class="dib">
+                <svg class="icon svg-icon" aria-hidden="true">
+                  <use xlink:href="#icon-shanchu"></use>
+                </svg>
+                <div class="name">删除</div>
+                <div class="code-name">#icon-shanchu</div>
+            </li>
+          
+            <li class="dib">
+                <svg class="icon svg-icon" aria-hidden="true">
+                  <use xlink:href="#icon-feiquanping"></use>
+                </svg>
+                <div class="name">非全屏</div>
+                <div class="code-name">#icon-feiquanping</div>
+            </li>
+          
+            <li class="dib">
+                <svg class="icon svg-icon" aria-hidden="true">
+                  <use xlink:href="#icon-shangchuanshipin"></use>
+                </svg>
+                <div class="name">上传视频</div>
+                <div class="code-name">#icon-shangchuanshipin</div>
+            </li>
+          
+            <li class="dib">
+                <svg class="icon svg-icon" aria-hidden="true">
+                  <use xlink:href="#icon-xcsp"></use>
+                </svg>
+                <div class="name">学车视频</div>
+                <div class="code-name">#icon-xcsp</div>
+            </li>
+          
+            <li class="dib">
+                <svg class="icon svg-icon" aria-hidden="true">
+                  <use xlink:href="#icon-suotou"></use>
+                </svg>
+                <div class="name">锁头</div>
+                <div class="code-name">#icon-suotou</div>
+            </li>
+          
+            <li class="dib">
+                <svg class="icon svg-icon" aria-hidden="true">
+                  <use xlink:href="#icon-jiesuo"></use>
+                </svg>
+                <div class="name">解锁</div>
+                <div class="code-name">#icon-jiesuo</div>
+            </li>
+          
+            <li class="dib">
+                <svg class="icon svg-icon" aria-hidden="true">
+                  <use xlink:href="#icon-quanping"></use>
+                </svg>
+                <div class="name">全屏</div>
+                <div class="code-name">#icon-quanping</div>
+            </li>
+          
+            <li class="dib">
+                <svg class="icon svg-icon" aria-hidden="true">
+                  <use xlink:href="#icon-zanting"></use>
+                </svg>
+                <div class="name">暂停</div>
+                <div class="code-name">#icon-zanting</div>
+            </li>
+          
+            <li class="dib">
+                <svg class="icon svg-icon" aria-hidden="true">
+                  <use xlink:href="#icon-jiantou"></use>
+                </svg>
+                <div class="name">箭头</div>
+                <div class="code-name">#icon-jiantou</div>
+            </li>
+          
+            <li class="dib">
+                <svg class="icon svg-icon" aria-hidden="true">
+                  <use xlink:href="#icon-bofangshipin"></use>
+                </svg>
+                <div class="name">播放视频</div>
+                <div class="code-name">#icon-bofangshipin</div>
+            </li>
+          
+            <li class="dib">
+                <svg class="icon svg-icon" aria-hidden="true">
+                  <use xlink:href="#icon-ershouche"></use>
+                </svg>
+                <div class="name">二手车</div>
+                <div class="code-name">#icon-ershouche</div>
+            </li>
+          
+            <li class="dib">
+                <svg class="icon svg-icon" aria-hidden="true">
+                  <use xlink:href="#icon-xiangji"></use>
+                </svg>
+                <div class="name">相机</div>
+                <div class="code-name">#icon-xiangji</div>
+            </li>
+          
+            <li class="dib">
+                <svg class="icon svg-icon" aria-hidden="true">
+                  <use xlink:href="#icon-tianjia"></use>
+                </svg>
+                <div class="name">添加图片</div>
+                <div class="code-name">#icon-tianjia</div>
+            </li>
+          
+            <li class="dib">
+                <svg class="icon svg-icon" aria-hidden="true">
+                  <use xlink:href="#icon-bianji"></use>
+                </svg>
+                <div class="name">编辑</div>
+                <div class="code-name">#icon-bianji</div>
+            </li>
+          
+            <li class="dib">
+                <svg class="icon svg-icon" aria-hidden="true">
+                  <use xlink:href="#icon-lxkf"></use>
+                </svg>
+                <div class="name">联系客服</div>
+                <div class="code-name">#icon-lxkf</div>
+            </li>
+          
+            <li class="dib">
+                <svg class="icon svg-icon" aria-hidden="true">
+                  <use xlink:href="#icon-dianhua"></use>
+                </svg>
+                <div class="name">电话</div>
+                <div class="code-name">#icon-dianhua</div>
+            </li>
+          
+            <li class="dib">
+                <svg class="icon svg-icon" aria-hidden="true">
+                  <use xlink:href="#icon-weixin"></use>
+                </svg>
+                <div class="name">微信</div>
+                <div class="code-name">#icon-weixin</div>
+            </li>
+          
+            <li class="dib">
+                <svg class="icon svg-icon" aria-hidden="true">
+                  <use xlink:href="#icon-guanbi"></use>
+                </svg>
+                <div class="name">关闭</div>
+                <div class="code-name">#icon-guanbi</div>
+            </li>
+          
+            <li class="dib">
+                <svg class="icon svg-icon" aria-hidden="true">
+                  <use xlink:href="#icon-gou"></use>
+                </svg>
+                <div class="name">勾</div>
+                <div class="code-name">#icon-gou</div>
+            </li>
+          
+            <li class="dib">
+                <svg class="icon svg-icon" aria-hidden="true">
+                  <use xlink:href="#icon-sousuo"></use>
+                </svg>
+                <div class="name">搜索</div>
+                <div class="code-name">#icon-sousuo</div>
+            </li>
+          
+            <li class="dib">
+                <svg class="icon svg-icon" aria-hidden="true">
+                  <use xlink:href="#icon-xiangxia2"></use>
+                </svg>
+                <div class="name">向下2</div>
+                <div class="code-name">#icon-xiangxia2</div>
+            </li>
+          
+            <li class="dib">
+                <svg class="icon svg-icon" aria-hidden="true">
+                  <use xlink:href="#icon-xiangshang"></use>
+                </svg>
+                <div class="name">向下2</div>
+                <div class="code-name">#icon-xiangshang</div>
+            </li>
+          
+            <li class="dib">
+                <svg class="icon svg-icon" aria-hidden="true">
+                  <use xlink:href="#icon-xiangxia"></use>
+                </svg>
+                <div class="name">向下</div>
+                <div class="code-name">#icon-xiangxia</div>
+            </li>
+          
+            <li class="dib">
+                <svg class="icon svg-icon" aria-hidden="true">
+                  <use xlink:href="#icon-xuanzhong"></use>
+                </svg>
+                <div class="name">选中</div>
+                <div class="code-name">#icon-xuanzhong</div>
+            </li>
+          
+            <li class="dib">
+                <svg class="icon svg-icon" aria-hidden="true">
+                  <use xlink:href="#icon-name_left"></use>
+                </svg>
+                <div class="name">type_name_right</div>
+                <div class="code-name">#icon-name_left</div>
+            </li>
+          
+            <li class="dib">
+                <svg class="icon svg-icon" aria-hidden="true">
+                  <use xlink:href="#icon-name_right"></use>
+                </svg>
+                <div class="name">type_name_left</div>
+                <div class="code-name">#icon-name_right</div>
+            </li>
+          
+            <li class="dib">
+                <svg class="icon svg-icon" aria-hidden="true">
+                  <use xlink:href="#icon-arrow-right"></use>
+                </svg>
+                <div class="name">arrow-right</div>
+                <div class="code-name">#icon-arrow-right</div>
+            </li>
+          
+            <li class="dib">
+                <svg class="icon svg-icon" aria-hidden="true">
+                  <use xlink:href="#icon-yjfk"></use>
+                </svg>
+                <div class="name">意见反馈</div>
+                <div class="code-name">#icon-yjfk</div>
+            </li>
+          
+            <li class="dib">
+                <svg class="icon svg-icon" aria-hidden="true">
+                  <use xlink:href="#icon-dfh"></use>
+                </svg>
+                <div class="name">待发货</div>
+                <div class="code-name">#icon-dfh</div>
+            </li>
+          
+            <li class="dib">
+                <svg class="icon svg-icon" aria-hidden="true">
+                  <use xlink:href="#icon-tksh"></use>
+                </svg>
+                <div class="name">退款 售后02</div>
+                <div class="code-name">#icon-tksh</div>
+            </li>
+          
+            <li class="dib">
+                <svg class="icon svg-icon" aria-hidden="true">
+                  <use xlink:href="#icon-qbdd"></use>
+                </svg>
+                <div class="name">全部订单</div>
+                <div class="code-name">#icon-qbdd</div>
+            </li>
+          
+            <li class="dib">
+                <svg class="icon svg-icon" aria-hidden="true">
+                  <use xlink:href="#icon-jywc"></use>
+                </svg>
+                <div class="name">交易-完成</div>
+                <div class="code-name">#icon-jywc</div>
+            </li>
+          
+            <li class="dib">
+                <svg class="icon svg-icon" aria-hidden="true">
+                  <use xlink:href="#icon-dingwei"></use>
+                </svg>
+                <div class="name">定位</div>
+                <div class="code-name">#icon-dingwei</div>
+            </li>
+          
+            <li class="dib">
+                <svg class="icon svg-icon" aria-hidden="true">
+                  <use xlink:href="#icon-ddwl"></use>
+                </svg>
+                <div class="name">当地玩乐2</div>
+                <div class="code-name">#icon-ddwl</div>
+            </li>
+          
+            <li class="dib">
+                <svg class="icon svg-icon" aria-hidden="true">
+                  <use xlink:href="#icon-wode"></use>
+                </svg>
+                <div class="name">我 的</div>
+                <div class="code-name">#icon-wode</div>
+            </li>
+          
+            <li class="dib">
+                <svg class="icon svg-icon" aria-hidden="true">
+                  <use xlink:href="#icon-shouye"></use>
+                </svg>
+                <div class="name">主页</div>
+                <div class="code-name">#icon-shouye</div>
+            </li>
+          
+            <li class="dib">
+                <svg class="icon svg-icon" aria-hidden="true">
+                  <use xlink:href="#icon-dianying"></use>
+                </svg>
+                <div class="name">电影</div>
+                <div class="code-name">#icon-dianying</div>
+            </li>
+          
+          </ul>
+          <div class="article markdown">
+          <h2 id="symbol-">Symbol 引用</h2>
+          <hr>
+
+          <p>这是一种全新的使用方式,应该说这才是未来的主流,也是平台目前推荐的用法。相关介绍可以参考这篇<a href="">文章</a>
+            这种用法其实是做了一个 SVG 的集合,与另外两种相比具有如下特点:</p>
+          <ul>
+            <li>支持多色图标了,不再受单色限制。</li>
+            <li>通过一些技巧,支持像字体那样,通过 <code>font-size</code>, <code>color</code> 来调整样式。</li>
+            <li>兼容性较差,支持 IE9+,及现代浏览器。</li>
+            <li>浏览器渲染 SVG 的性能一般,还不如 png。</li>
+          </ul>
+          <p>使用步骤如下:</p>
+          <h3 id="-symbol-">第一步:引入项目下面生成的 symbol 代码:</h3>
+<pre><code class="language-html">&lt;script src="./iconfont.js"&gt;&lt;/script&gt;
+</code></pre>
+          <h3 id="-css-">第二步:加入通用 CSS 代码(引入一次就行):</h3>
+<pre><code class="language-html">&lt;style&gt;
+.icon {
+  width: 1em;
+  height: 1em;
+  vertical-align: -0.15em;
+  fill: currentColor;
+  overflow: hidden;
+}
+&lt;/style&gt;
+</code></pre>
+          <h3 id="-">第三步:挑选相应图标并获取类名,应用于页面:</h3>
+<pre><code class="language-html">&lt;svg class="icon" aria-hidden="true"&gt;
+  &lt;use xlink:href="#icon-xxx"&gt;&lt;/use&gt;
+&lt;/svg&gt;
+</code></pre>
+          </div>
+      </div>
+
+    </div>
+  </div>
+  <script>
+  $(document).ready(function () {
+      $('.tab-container .content:first').show()
+
+      $('#tabs li').click(function (e) {
+        var tabContent = $('.tab-container .content')
+        var index = $(this).index()
+
+        if ($(this).hasClass('active')) {
+          return
+        } else {
+          $('#tabs li').removeClass('active')
+          $(this).addClass('active')
+
+          tabContent.hide().eq(index).fadeIn()
+        }
+      })
+    })
+  </script>
+</body>
+</html>

+ 201 - 0
src/components/m-icon/iconfont.css

@@ -0,0 +1,201 @@
+@font-face {
+  font-family: "iconfont"; /* Project id 2599049 */
+  src: url('iconfont.ttf?t=1627377154886') format('truetype');
+}
+
+.iconfont {
+  font-family: "iconfont" !important;
+  font-size: 16px;
+  font-style: normal;
+  -webkit-font-smoothing: antialiased;
+  -moz-osx-font-smoothing: grayscale;
+}
+
+.icon-share-fill:before {
+  content: "\e637";
+}
+
+.icon-dianzan:before {
+  content: "\e620";
+}
+
+.icon-shoucang:before {
+  content: "\e629";
+}
+
+.icon-shezhi:before {
+  content: "\e611";
+}
+
+.icon-thsp:before {
+  content: "\e6ad";
+}
+
+.icon-xiangqing:before {
+  content: "\e634";
+}
+
+.icon-jiangxu-copy:before {
+  content: "\f5fe";
+}
+
+.icon-qiehuan:before {
+  content: "\e632";
+}
+
+.icon-cha:before {
+  content: "\e61f";
+}
+
+.icon-gou1:before {
+  content: "\e61e";
+}
+
+.icon-shanchu:before {
+  content: "\e61c";
+}
+
+.icon-feiquanping:before {
+  content: "\e61b";
+}
+
+.icon-shangchuanshipin:before {
+  content: "\e61a";
+}
+
+.icon-xcsp:before {
+  content: "\e619";
+}
+
+.icon-suotou:before {
+  content: "\e618";
+}
+
+.icon-jiesuo:before {
+  content: "\e617";
+}
+
+.icon-quanping:before {
+  content: "\e616";
+}
+
+.icon-zanting:before {
+  content: "\e614";
+}
+
+.icon-jiantou:before {
+  content: "\e62f";
+}
+
+.icon-bofangshipin:before {
+  content: "\e613";
+}
+
+.icon-ershouche:before {
+  content: "\f5fd";
+}
+
+.icon-xiangji:before {
+  content: "\e61d";
+}
+
+.icon-tianjia:before {
+  content: "\e612";
+}
+
+.icon-bianji:before {
+  content: "\e70e";
+}
+
+.icon-lxkf:before {
+  content: "\e610";
+}
+
+.icon-dianhua:before {
+  content: "\e60f";
+}
+
+.icon-weixin:before {
+  content: "\e60e";
+}
+
+.icon-guanbi:before {
+  content: "\e60d";
+}
+
+.icon-gou:before {
+  content: "\e60c";
+}
+
+.icon-sousuo:before {
+  content: "\e60b";
+}
+
+.icon-xiangxia2:before {
+  content: "\e60a";
+}
+
+.icon-xiangshang:before {
+  content: "\e8ba";
+}
+
+.icon-xiangxia:before {
+  content: "\e609";
+}
+
+.icon-xuanzhong:before {
+  content: "\e606";
+}
+
+.icon-name_left:before {
+  content: "\e604";
+}
+
+.icon-name_right:before {
+  content: "\e601";
+}
+
+.icon-arrow-right:before {
+  content: "\e665";
+}
+
+.icon-yjfk:before {
+  content: "\e603";
+}
+
+.icon-dfh:before {
+  content: "\e608";
+}
+
+.icon-tksh:before {
+  content: "\e6f2";
+}
+
+.icon-qbdd:before {
+  content: "\e600";
+}
+
+.icon-jywc:before {
+  content: "\e602";
+}
+
+.icon-dingwei:before {
+  content: "\e86a";
+}
+
+.icon-ddwl:before {
+  content: "\e8b9";
+}
+
+.icon-wode:before {
+  content: "\e607";
+}
+
+.icon-shouye:before {
+  content: "\e615";
+}
+
+.icon-dianying:before {
+  content: "\e642";
+}
+

Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 0 - 0
src/components/m-icon/iconfont.js


+ 338 - 0
src/components/m-icon/iconfont.json

@@ -0,0 +1,338 @@
+{
+  "id": "2599049",
+  "name": "极速生活圈",
+  "font_family": "iconfont",
+  "css_prefix_text": "icon-",
+  "description": "",
+  "glyphs": [
+    {
+      "icon_id": "9512641",
+      "name": "分享",
+      "font_class": "share-fill",
+      "unicode": "e637",
+      "unicode_decimal": 58935
+    },
+    {
+      "icon_id": "9688351",
+      "name": "点赞",
+      "font_class": "dianzan",
+      "unicode": "e620",
+      "unicode_decimal": 58912
+    },
+    {
+      "icon_id": "19954256",
+      "name": "收 藏",
+      "font_class": "shoucang",
+      "unicode": "e629",
+      "unicode_decimal": 58921
+    },
+    {
+      "icon_id": "20361165",
+      "name": "设置",
+      "font_class": "shezhi",
+      "unicode": "e611",
+      "unicode_decimal": 58897
+    },
+    {
+      "icon_id": "20995187",
+      "name": "替换视频",
+      "font_class": "thsp",
+      "unicode": "e6ad",
+      "unicode_decimal": 59053
+    },
+    {
+      "icon_id": "4996801",
+      "name": "详情",
+      "font_class": "xiangqing",
+      "unicode": "e634",
+      "unicode_decimal": 58932
+    },
+    {
+      "icon_id": "22593389",
+      "name": "升序",
+      "font_class": "jiangxu-copy",
+      "unicode": "f5fe",
+      "unicode_decimal": 62974
+    },
+    {
+      "icon_id": "12004692",
+      "name": "升序",
+      "font_class": "qiehuan",
+      "unicode": "e632",
+      "unicode_decimal": 58930
+    },
+    {
+      "icon_id": "22584404",
+      "name": "叉",
+      "font_class": "cha",
+      "unicode": "e61f",
+      "unicode_decimal": 58911
+    },
+    {
+      "icon_id": "22584317",
+      "name": "勾",
+      "font_class": "gou1",
+      "unicode": "e61e",
+      "unicode_decimal": 58910
+    },
+    {
+      "icon_id": "22584301",
+      "name": "删除",
+      "font_class": "shanchu",
+      "unicode": "e61c",
+      "unicode_decimal": 58908
+    },
+    {
+      "icon_id": "22584277",
+      "name": "非全屏",
+      "font_class": "feiquanping",
+      "unicode": "e61b",
+      "unicode_decimal": 58907
+    },
+    {
+      "icon_id": "22575197",
+      "name": "上传视频",
+      "font_class": "shangchuanshipin",
+      "unicode": "e61a",
+      "unicode_decimal": 58906
+    },
+    {
+      "icon_id": "22574627",
+      "name": "学车视频",
+      "font_class": "xcsp",
+      "unicode": "e619",
+      "unicode_decimal": 58905
+    },
+    {
+      "icon_id": "22548098",
+      "name": "锁头",
+      "font_class": "suotou",
+      "unicode": "e618",
+      "unicode_decimal": 58904
+    },
+    {
+      "icon_id": "22547394",
+      "name": "解锁",
+      "font_class": "jiesuo",
+      "unicode": "e617",
+      "unicode_decimal": 58903
+    },
+    {
+      "icon_id": "22547378",
+      "name": "全屏",
+      "font_class": "quanping",
+      "unicode": "e616",
+      "unicode_decimal": 58902
+    },
+    {
+      "icon_id": "22547353",
+      "name": "暂停",
+      "font_class": "zanting",
+      "unicode": "e614",
+      "unicode_decimal": 58900
+    },
+    {
+      "icon_id": "2279253",
+      "name": "箭头",
+      "font_class": "jiantou",
+      "unicode": "e62f",
+      "unicode_decimal": 58927
+    },
+    {
+      "icon_id": "22510836",
+      "name": "播放视频",
+      "font_class": "bofangshipin",
+      "unicode": "e613",
+      "unicode_decimal": 58899
+    },
+    {
+      "icon_id": "21830671",
+      "name": "二手车",
+      "font_class": "ershouche",
+      "unicode": "f5fd",
+      "unicode_decimal": 62973
+    },
+    {
+      "icon_id": "6170868",
+      "name": "相机",
+      "font_class": "xiangji",
+      "unicode": "e61d",
+      "unicode_decimal": 58909
+    },
+    {
+      "icon_id": "22363247",
+      "name": "添加图片",
+      "font_class": "tianjia",
+      "unicode": "e612",
+      "unicode_decimal": 58898
+    },
+    {
+      "icon_id": "4933277",
+      "name": "编辑",
+      "font_class": "bianji",
+      "unicode": "e70e",
+      "unicode_decimal": 59150
+    },
+    {
+      "icon_id": "22349357",
+      "name": "联系客服",
+      "font_class": "lxkf",
+      "unicode": "e610",
+      "unicode_decimal": 58896
+    },
+    {
+      "icon_id": "22349245",
+      "name": "电话",
+      "font_class": "dianhua",
+      "unicode": "e60f",
+      "unicode_decimal": 58895
+    },
+    {
+      "icon_id": "22348890",
+      "name": "微信",
+      "font_class": "weixin",
+      "unicode": "e60e",
+      "unicode_decimal": 58894
+    },
+    {
+      "icon_id": "22326326",
+      "name": "关闭",
+      "font_class": "guanbi",
+      "unicode": "e60d",
+      "unicode_decimal": 58893
+    },
+    {
+      "icon_id": "22317764",
+      "name": "勾",
+      "font_class": "gou",
+      "unicode": "e60c",
+      "unicode_decimal": 58892
+    },
+    {
+      "icon_id": "22315857",
+      "name": "搜索",
+      "font_class": "sousuo",
+      "unicode": "e60b",
+      "unicode_decimal": 58891
+    },
+    {
+      "icon_id": "22315652",
+      "name": "向下2",
+      "font_class": "xiangxia2",
+      "unicode": "e60a",
+      "unicode_decimal": 58890
+    },
+    {
+      "icon_id": "22318192",
+      "name": "向下2",
+      "font_class": "xiangshang",
+      "unicode": "e8ba",
+      "unicode_decimal": 59578
+    },
+    {
+      "icon_id": "22314879",
+      "name": "向下",
+      "font_class": "xiangxia",
+      "unicode": "e609",
+      "unicode_decimal": 58889
+    },
+    {
+      "icon_id": "22203897",
+      "name": "选中",
+      "font_class": "xuanzhong",
+      "unicode": "e606",
+      "unicode_decimal": 58886
+    },
+    {
+      "icon_id": "22190051",
+      "name": "type_name_right",
+      "font_class": "name_left",
+      "unicode": "e604",
+      "unicode_decimal": 58884
+    },
+    {
+      "icon_id": "22190016",
+      "name": "type_name_left",
+      "font_class": "name_right",
+      "unicode": "e601",
+      "unicode_decimal": 58881
+    },
+    {
+      "icon_id": "15838431",
+      "name": "arrow-right",
+      "font_class": "arrow-right",
+      "unicode": "e665",
+      "unicode_decimal": 58981
+    },
+    {
+      "icon_id": "22128889",
+      "name": "意见反馈",
+      "font_class": "yjfk",
+      "unicode": "e603",
+      "unicode_decimal": 58883
+    },
+    {
+      "icon_id": "17610317",
+      "name": "待发货",
+      "font_class": "dfh",
+      "unicode": "e608",
+      "unicode_decimal": 58888
+    },
+    {
+      "icon_id": "8266393",
+      "name": "退款 售后02",
+      "font_class": "tksh",
+      "unicode": "e6f2",
+      "unicode_decimal": 59122
+    },
+    {
+      "icon_id": "13001981",
+      "name": "全部订单",
+      "font_class": "qbdd",
+      "unicode": "e600",
+      "unicode_decimal": 58880
+    },
+    {
+      "icon_id": "13522645",
+      "name": "交易-完成",
+      "font_class": "jywc",
+      "unicode": "e602",
+      "unicode_decimal": 58882
+    },
+    {
+      "icon_id": "9626852",
+      "name": "定位",
+      "font_class": "dingwei",
+      "unicode": "e86a",
+      "unicode_decimal": 59498
+    },
+    {
+      "icon_id": "2076362",
+      "name": "当地玩乐2",
+      "font_class": "ddwl",
+      "unicode": "e8b9",
+      "unicode_decimal": 59577
+    },
+    {
+      "icon_id": "6997483",
+      "name": "我 的",
+      "font_class": "wode",
+      "unicode": "e607",
+      "unicode_decimal": 58887
+    },
+    {
+      "icon_id": "6427825",
+      "name": "主页",
+      "font_class": "shouye",
+      "unicode": "e615",
+      "unicode_decimal": 58901
+    },
+    {
+      "icon_id": "6446340",
+      "name": "电影",
+      "font_class": "dianying",
+      "unicode": "e642",
+      "unicode_decimal": 58946
+    }
+  ]
+}

binární
src/components/m-icon/iconfont.ttf


+ 34 - 0
src/components/m-icon/m-icon.vue

@@ -0,0 +1,34 @@
+<template>
+	<view class="iconfont" :class="['icon-'+type]" :style="{color:color,'font-size':size}" @click="onClick()"></view>
+</template>
+
+<script>
+export default {
+  props: {
+    /**
+      * 图标类型
+      */
+    type: String,
+    /**
+      * 图标颜色
+      */
+    color: String,
+    /**
+      * 图标大小
+      */
+    size: {
+      type: String,
+      default: '24px'
+    }
+  },
+  methods: {
+    onClick() {
+      this.$emit('click')
+    }
+  }
+}
+</script>
+
+<style>
+	@import "./iconfont.css";
+</style>

+ 37 - 0
src/components/m-return/m-return.vue

@@ -0,0 +1,37 @@
+<template>
+	<view class="return-box"
+		:style="{'left': `calc(100vw - ${tophight.right}px)`,top: tophight.top + 'px',height:tophight.height+'px',width:tophight.width/2+'px'}">
+		<m-icon type="arrow-right" class="return" @click='returnPage'></m-icon>
+	</view>
+
+</template>
+
+<script>
+	export default {
+		name: "m-return",
+		data: () => ({
+			tophight: uni.getMenuButtonBoundingClientRect(),
+		}),
+		methods: {
+			returnPage() {
+				wx.navigateBack({
+					delta: 1
+				})
+			}
+		}
+	}
+</script>
+
+<style lang="scss">
+	.return-box {
+		position: fixed;
+		display: flex;
+		justify-content: center;
+		align-items: center;
+
+		.return {
+			color: #FFFFFF;
+			transform: rotate(180deg);
+		}
+	}
+</style>

+ 102 - 0
src/components/m-video-box/m-video-box.vue

@@ -0,0 +1,102 @@
+<template>
+	<view>
+		<van-cell @click='clickCell' :title="carVideoList.chapterName" is-link value="更多" />
+		<!-- <view class="cell">
+			<text class="item-tit">{{carVideoList.chapterName}}</text>
+			<view class="right-box" @click='clickCell'>
+				<text class="item-tit-right">更多</text>
+				<m-icon type="arrow-right"></m-icon>
+			</view>
+		</view> -->
+		<view class="video-box" v-if="type=='top-bottom'">
+			<m-video-topbottom :column='column' :carVideoItem='item' v-for="(item,index) in showList"
+				:key='index' :palyObj='palyObj' @click='returnData(item)' />
+		</view>
+		<view class="video-box" v-if="type=='left-right'">
+			<m-video-leftright @click='returnData(item)' :palyObj='palyObj' :carVideoItem='item'
+				v-for="(item,index) in showList" :key='index' />
+		</view>
+	</view>
+</template>
+
+<script>
+	export default {
+		props: {
+			type: {
+				type: String,
+				default: 'top-bottom'
+			},
+			column: {
+				type: Number,
+				default: 2
+			},
+			carVideoList: {
+				type: Object,
+				default: {}
+			},
+			palyObj: {
+				type: Object,
+				default: null
+			}
+		},
+		name: "m-video-box",
+		computed:{
+			showList(){
+				return this.carVideoList.list
+			}
+		},
+		methods: {
+			returnData(item) {
+				if (this.palyObj) {
+					this.$emit('update:palyObj', item)
+				}
+			},
+			clickCell() {
+				this.$utils.route.goPage('/pages/carVideo/more', null, {
+					carVideoList: this.carVideoList
+				})
+			}
+		}
+	}
+</script>
+
+<style lang="scss" scoped>
+	.cell {
+		display: flex;
+		justify-content: space-between;
+		align-items: center;
+		background-color: #FFFFFF;
+		padding: 10rpx 20rpx;
+		border-bottom: 1rpx solid #e8e8e8;
+
+		.item-tit {
+			border-left: 8rpx solid #E31818;
+			font-size: 30rpx;
+			font-weight: 400;
+			padding: 5rpx;
+		}
+
+		.right-box {
+			display: flex;
+			align-items: center;
+
+			.item-tit-right {
+				font-size: 26rpx;
+				color: #666666;
+				line-height: 58rpx;
+				padding: 11rpx;
+			}
+		}
+
+	}
+
+	.video-box {
+		background-color: #FFFFFF;
+		display: flex;
+		flex-wrap: wrap;
+		padding-left: 30rpx;
+		padding-bottom: 30rpx;
+		margin-bottom: 30rpx;
+		z-index: 0;
+	}
+</style>

+ 89 - 0
src/components/m-video-leftright/m-video-leftright.vue

@@ -0,0 +1,89 @@
+<template>
+	<view class="video-item" @click="gotoPaly">
+		<view class="img-box">
+			<image class="image" :src="carVideoItem.cover" mode="aspectFill"></image>
+			<m-icon class="icon" type="bofangshipin"></m-icon>
+		</view>
+		<view class="tit-box">
+			<text>{{carVideoItem.title}}</text>
+			<text>{{carVideoItem.duration}}</text>
+		</view>
+	</view>
+</template>
+
+<script>
+	export default {
+		props: {
+			carVideoItem: {
+				type: Object,
+				default: {}
+			},
+			palyObj: {
+				type: Object,
+				default: null
+			}
+		},
+		name: "m-video-leftright",
+		data() {
+			return {
+
+			};
+		},
+		methods:{
+			gotoPaly(){
+				if(!this.palyObj){
+					this.$utils.route.goPage('/pages/carVideo/play',null,{carVideoItem:this.carVideoItem})
+				}else{
+					this.$emit('click')
+				}
+			}
+		}
+	}
+</script>
+
+<style lang="scss">
+	.video-item {
+		display: flex;
+		margin: 20rpx;
+
+		.img-box {
+			flex-shrink: 0;
+			width: 240rpx;
+			height: 160rpx;
+			position: relative;
+
+			.image {
+				width: 100%;
+				height: 100%;
+			}
+			.icon {
+				position: absolute;
+				left: 50%;
+				top: 50%;
+				transform: translate(-50%, -50%);
+			}
+		}
+
+
+		.tit-box {
+			display: flex;
+			flex-direction: column;
+			justify-content: space-between;
+			padding: 16rpx 16rpx;
+
+			text {
+				&:nth-child(1) {
+					font-size: 30rpx;
+					font-weight: 400;
+					color: #0F0404;
+				}
+
+				&:nth-child(2) {
+					font-size: 26rpx;
+					font-weight: 400;
+					color: #999999;
+				}
+			}
+		}
+	}
+</style>

+ 100 - 0
src/components/m-video-topbottom-short/m-video-topbottom-short.vue

@@ -0,0 +1,100 @@
+<template>
+	<view class="video-item" @click="gotoPaly">
+		<view class="image-box">
+			<view class="img-box">
+				<image class="image" :src="carVideoItem.cover" mode="aspectFill"></image>
+			</view>
+			<text>{{carVideoItem.duration}}</text>
+			<m-icon class="icon" type="bofangshipin"></m-icon>
+		</view>
+		<text>{{carVideoItem.title}}</text>
+	</view>
+</template>
+
+<script>
+	export default {
+		props: {
+			carVideoItem: {
+				type: Object,
+				default: {}
+			},
+			column: {
+				type: Number,
+				default: 2
+			},
+			palyObj: {
+				type: Object,
+				default: null
+			}
+		},
+		name: "m-video-topbottom",
+		methods: {
+			gotoPaly() {
+				if (!this.palyObj) {
+					this.$utils.route.goPage('/pages/carVideo/play', null, {
+						carVideoItem: this.carVideoItem
+					})
+				} else {
+					this.$emit('click')
+				}
+			}
+		}
+	}
+</script>
+
+<style lang="scss">
+	.video-item {
+		margin-right: 30rpx;
+		margin-top: 30rpx;
+		position: relative;
+		display: flex;
+		flex-direction: column;
+		justify-content: center;
+		text-align: center;
+		width: 200rpx;
+
+		.image-box {
+			position: relative;
+
+			.img-box {
+				width: 100%;
+				padding-bottom: 144%;
+				position: relative;
+
+				.image {
+					position: absolute;
+					left: 0;
+					top: 0;
+					width: 100%;
+					height: 100%;
+				}
+			}
+
+
+			text {
+				position: absolute;
+				color: #8A9099;
+				right: 2rpx;
+				bottom: 2rpx;
+
+			}
+
+			.icon {
+				position: absolute;
+				left: 50%;
+				top: 50%;
+				transform: translate(-50%, -50%);
+			}
+		}
+
+		text {
+			font-size: 30rpx;
+			font-weight: 400;
+			line-height: 39rpx;
+			color: #0F0404;
+			white-space: nowrap;
+			text-overflow: ellipsis;
+			overflow: hidden;
+		}
+	}
+</style>

+ 98 - 0
src/components/m-video-topbottom/m-video-topbottom.vue

@@ -0,0 +1,98 @@
+<template>
+	<view class="video-item" :style="{width: `${(750-30*column-30)/column}rpx`}"
+		@click="gotoPaly">
+		<view class="image-box">
+			<view class="img-box">
+				<image class="image" :src="carVideoItem.cover" mode="aspectFill"></image>
+			</view>
+			<text>{{carVideoItem.duration}}</text>
+			<m-icon class="icon" type="bofangshipin"></m-icon>
+		</view>
+		<text>{{carVideoItem.title}}</text>
+	</view>
+</template>
+
+<script>
+	export default {
+		props: {
+			carVideoItem: {
+				type: Object,
+				default: {}
+			},
+			column: {
+				type: Number,
+				default: 2
+			},
+			palyObj: {
+				type: Object,
+				default: null
+			}
+		},
+		name: "m-video-topbottom",
+		methods:{
+			gotoPaly(){
+				if(!this.palyObj){
+					this.$utils.route.goPage('/pages/carVideo/play',null,{carVideoItem:this.carVideoItem})
+				}else{
+					this.$emit('click')
+				}
+			}
+		}
+	}
+</script>
+
+<style lang="scss">
+	.video-item {
+		margin-right: 30rpx;
+		margin-top: 30rpx;
+		position: relative;
+		display: flex;
+		flex-direction: column;
+		justify-content: center;
+		text-align: center;
+
+		.image-box {
+			position: relative;
+
+			.img-box {
+				width: 100%;
+				padding-bottom: 64%;
+				position: relative;
+
+				.image {
+					position: absolute;
+					left: 0;
+					top: 0;
+					width: 100%;
+					height: 100%;
+				}
+			}
+
+
+			text {
+				position: absolute;
+				color: #8A9099;
+				right: 2rpx;
+				bottom: 2rpx;
+
+			}
+
+			.icon {
+				position: absolute;
+				left: 50%;
+				top: 50%;
+				transform: translate(-50%, -50%);
+			}
+		}
+
+		text {
+			font-size: 30rpx;
+			font-weight: 400;
+			line-height: 39rpx;
+			color: #0F0404;
+			white-space: nowrap;
+			text-overflow: ellipsis;
+			overflow: hidden;
+		}
+	}
+</style>

+ 32 - 0
src/components/topbar/topbar.vue

@@ -0,0 +1,32 @@
+<template>
+	<view class="tabbar">
+		<view :style="{ 'margin-top': tophight.top + 'px', 'margin-bottom': '15rpx' }">
+			<view class="slot-box" :style="{'padding-left': `calc(100vw - ${tophight.right}px)`,'padding-right': `calc(100vw - ${tophight.left}px)`,height: tophight.height + 'px'}">
+				<slot></slot>
+			</view>
+		</view>
+	</view>
+
+</template>
+
+<script>
+	export default {
+		data: () => ({
+			tophight: uni.getMenuButtonBoundingClientRect(),
+		}),
+		mounted() {
+			console.log(uni.getMenuButtonBoundingClientRect())
+		}
+	};
+</script>
+
+<style lang="scss" scoped>
+	.tabbar {
+		display: flex;
+		background-color: #FFFFFF;
+		.slot-box{
+			display: flex;
+			align-items: center;
+		}
+	}
+</style>

+ 7 - 0
src/config/errorCode.js

@@ -0,0 +1,7 @@
+export default {
+  '401': '认证失败,无法访问系统资源',
+  '403': '当前操作没有权限',
+  '404': '访问资源不存在',
+  '500': '系统内部错误',
+  'default': '系统未知错误,请反馈给管理员'
+}

+ 24 - 0
src/main.js

@@ -0,0 +1,24 @@
+import Vue from 'vue'
+import App from './App'
+//引入vuex
+import store from '@/store'
+//引入所有工具函数
+import utils from '@/utils'
+//引入所有接口函数
+import api from '@/api'
+
+Vue.config.productionTip = false
+App.mpType = 'app'
+
+//goPageGetData中存在this需要引用当前
+Vue.prototype.goPageGetData = utils.goPageGetData
+//挂载工具类
+Vue.prototype.$utils = utils
+//挂载请求接口
+Vue.prototype.$api = api
+
+const app = new Vue({
+	store,
+	...App
+})
+app.$mount()

+ 25 - 0
src/manifest.json

@@ -0,0 +1,25 @@
+{
+  "name": "sqxp-uniapp",
+  "appid": "__UNI__C992BC3",
+  "description": "",
+  "versionName": "1.0.0",
+  "versionCode": "100",
+  "transformPx": false,
+  "mp-weixin": {
+    "appid": "wx8f43db501343feab",
+    "setting": {
+      "urlCheck": false,
+      "es6": true,
+      "minified": true
+    },
+    "usingComponents": true,
+    "permission": {
+      "scope.userLocation": {
+        "desc": "电影院位置定位请求"
+      }
+    }
+  },
+  "uniStatistics": {
+    "enable": false
+  }
+}

+ 253 - 0
src/pages.json

@@ -0,0 +1,253 @@
+{
+  "pages": [
+    // {
+    //   "path": "pages/home/index",
+    //   "style": {
+    //     "navigationBarTitleText": "",
+    //     "navigationStyle": "custom"
+    //   }
+    // },
+	{
+	  "path": "pages/carVideo/index",
+	  "style": {
+	    "navigationBarTitleText": "学车",
+	    "enablePullDownRefresh": false,
+	    "navigationStyle": "custom"
+	  }
+	},
+    {
+      "path": "pages/index/index",
+      "style": {
+        "navigationBarTitleText": "极速生活圈",
+        "navigationStyle": "custom"
+      }
+    },
+    {
+      "path": "pages/user/set",
+      "style": {
+        "navigationBarTitleText": "我的设置"
+      }
+    },
+    {
+      "path": "pages/user/collectionList",
+      "style": {
+        "navigationBarTitleText": "我的收藏"
+      }
+    },
+    {
+      "path": "pages/user/browserecord",
+      "style": {
+        "navigationBarTitleText": "浏览足迹"
+      }
+    },
+	//webview页面
+    {
+      "path": "pages/webview/webview",
+      "style": {
+        "navigationBarTitleText": "",
+        "enablePullDownRefresh": false
+      }
+    },
+    {
+      "path": "pages/cinema/cinemalist",
+      "style": {
+        "navigationBarTitleText": "影院列表",
+        "enablePullDownRefresh": false
+      }
+    },
+    {
+      "path": "pages/cinema/schedulelist",
+      "style": {
+        "navigationBarTitleText": "",
+        "enablePullDownRefresh": false,
+        "backgroundColor": "#ffffff"
+      }
+    },
+    {
+      "path": "pages/cinema/selectseat",
+      "style": {
+        "navigationBarTitleText": "",
+        "enablePullDownRefresh": false
+      }
+    },
+    {
+      "path": "pages/cinema/placeorder",
+      "style": {
+        "navigationBarTitleText": "付款",
+        "enablePullDownRefresh": false
+      }
+    },
+    {
+      "path": "pages/user/order",
+      "style": {
+        "navigationBarTitleText": "我的订单",
+        "enablePullDownRefresh": false
+      }
+    },
+    {
+      "path": "pages/cinema/orderdes",
+      "style": {
+        "navigationBarTitleText": "订单详情",
+        "enablePullDownRefresh": false
+      }
+    },
+    {
+      "path": "pages/cinema/citylist",
+      "style": {
+        "navigationBarTitleText": "选择城市",
+        "enablePullDownRefresh": false
+      }
+    },
+    {
+      "path": "pages/fulu/index",
+      "style": {
+        "navigationBarTitleText": "",
+        "enablePullDownRefresh": false
+      }
+    },
+    {
+      "path": "pages/fulu/placeorder",
+      "style": {
+        "navigationBarTitleText": "",
+        "enablePullDownRefresh": false
+      }
+    },
+    {
+      "path": "pages/fulu/orderdes",
+      "style": {
+        "navigationBarTitleText": "",
+        "enablePullDownRefresh": false
+      }
+    },
+    // {
+    //   "path": "pages/phoneBill/index",
+    //   "style": {
+    //     "navigationBarTitleText": "",
+    //     "enablePullDownRefresh": false
+    //   }
+    // },
+    // {
+    //   "path": "pages/phoneBill/orderdes",
+    //   "style": {
+    //     "navigationBarTitleText": "",
+    //     "enablePullDownRefresh": false
+    //   }
+    // },
+    {
+      "path": "pages/carVideo/play",
+      "style": {
+        "navigationBarTitleText": "",
+        "enablePullDownRefresh": false
+      }
+    },
+    {
+      "path": "pages/carVideo/more",
+      "style": {
+        "navigationBarTitleText": ""
+      }
+    },
+    {
+      "path": "pages/user/index",
+      "style": {
+        "navigationBarTitleText": "",
+        "navigationStyle": "custom"
+      }
+    },
+    {
+      "path": "pages/cinema/index",
+      "style": {
+        "navigationBarTitleText": "",
+        "navigationStyle": "custom"
+      }
+    },
+    {
+      "path": "pages/carVideo/shortVideoPaly",
+      "style": {
+        "navigationStyle": "custom",
+        "disableScroll": true
+      }
+    }
+  ],
+  "tabBar": {
+    "color": "#7A7E83",
+    "selectedColor": "#E31818",
+    "borderStyle": "white",
+    "backgroundColor": "#ffffff",
+    "list": [
+      // {
+      //   "pagePath": "pages/home/index",
+      //   "iconPath": "static/imgs/home.png",
+      //   "selectedIconPath": "static/imgs/home-avtive.png",
+      //   "text": "首页"
+      // },
+      {
+        "pagePath": "pages/carVideo/index",
+        "iconPath": "static/imgs/video.png",
+        "selectedIconPath": "static/imgs/video-avtive.png",
+        "text": "学车"
+      },
+      {
+        "pagePath": "pages/cinema/index",
+        "iconPath": "static/imgs/theFilm.png",
+        "selectedIconPath": "static/imgs/theFilm-avtive.png",
+        "text": "电影"
+      },
+      {
+        "pagePath": "pages/user/index",
+        "iconPath": "static/imgs/user.png",
+        "selectedIconPath": "static/imgs/user-avtive.png",
+        "text": "我的"
+      }
+    ]
+  },
+  "globalStyle": {
+    "navigationBarTextStyle": "black",
+    "navigationBarTitleText": "",
+    "navigationBarBackgroundColor": "#F8F8F8",
+    "backgroundColor": "#F8F8F8",
+    "usingComponents": {
+      "van-tabbar": "./wxcomponents/vant/tabbar/index",
+      "van-tabbar-item": "./wxcomponents/vant/tabbar-item/index",
+      "van-search": "./wxcomponents/vant/search/index",
+      "van-icon": "./wxcomponents/vant/icon/index",
+      "van-row": "./wxcomponents/vant/row/index",
+      "van-col": "./wxcomponents/vant/col/index",
+      "van-transition": "./wxcomponents/vant/transition/index",
+      "van-image": "./wxcomponents/vant/image/index",
+      "van-checkbox": "./wxcomponents/vant/checkbox/index",
+      "van-checkbox-group": "./wxcomponents/vant/checkbox-group/index",
+      "van-radio": "./wxcomponents/vant/radio/index",
+      "van-radio-group": "./wxcomponents/vant/radio-group/index",
+      "van-cell": "./wxcomponents/vant/cell/index",
+      "van-cell-group": "./wxcomponents/vant/cell-group/index",
+      "van-switch": "./wxcomponents/vant/switch/index",
+      "van-popup": "./wxcomponents/vant/popup/index",
+      "van-skeleton": "./wxcomponents/vant/skeleton/index",
+      "van-field": "./wxcomponents/vant/field/index",
+      "van-area": "./wxcomponents/vant/area/index",
+      "van-button": "./wxcomponents/vant/button/index",
+      "van-divider": "./wxcomponents/vant/divider/index",
+      "van-count-down": "./wxcomponents/vant/count-down/index",
+      "van-dialog": "./wxcomponents/vant/dialog/index",
+      "van-tab": "./wxcomponents/vant/tab/index",
+      "van-tabs": "./wxcomponents/vant/tabs/index",
+      "van-share-sheet": "./wxcomponents/vant/share-sheet/index",
+      "van-index-bar": "./wxcomponents/vant/index-bar/index",
+      "van-index-anchor": "./wxcomponents/vant/index-anchor/index",
+      "van-stepper": "./wxcomponents/vant/stepper/index",
+      "van-sidebar": "wxcomponents/vant/sidebar/index",
+      "van-sidebar-item": "wxcomponents/vant/sidebar-item/index"
+    }
+  },
+  "condition": {
+    //模式配置,仅开发期间生效
+    "current": 0, //当前激活的模式(list 的索引项)
+    "list": [
+      {
+        "name": "", //模式名称
+        "path": "", //启动页面,必选
+        "query": "" //启动参数,在页面的onLoad函数里面得到
+      }
+    ]
+  }
+}

+ 67 - 0
src/pages/carVideo/components/branchOne.vue

@@ -0,0 +1,67 @@
+<template>
+	<loading v-if="loading"></loading>
+	<view v-else class="branch-one">
+		<view class="sidebar-box">
+			<van-sidebar custom-class='van-sidebar' :active-key="activeKey" @change='sidebarOnChange'>
+				<van-sidebar-item :title="item.chapterName" v-for="(item,index) in carVideoList" :key='index' />
+			</van-sidebar>
+			<view class="video-box">
+				<m-video-leftright :carVideoItem='item' v-for="(item,index) in carVideoList[activeKey].list" :key='index'>
+				</m-video-leftright>
+			</view>
+		</view>
+	</view>
+</template>
+
+<script>
+	export default {
+		props:{
+			carVideoList: {
+				type: Array
+			}
+		},
+		data: () => ({
+			bannerList: [],
+			loading: true,
+			activeKey: 0
+		}),
+		methods: {
+			sidebarOnChange(e) {
+				this.activeKey = e.detail
+			}
+		},
+		async mounted() {
+			let {
+				data: bannerListData
+			} = await this.$api.home.getHomePageDataList(['carouselChart'])
+			this.bannerList = bannerListData.carouselChart
+			this.$nextTick(() => {
+				this.loading = false
+			})
+		}
+	}
+</script>
+
+<style lang="scss" scoped>
+	.sidebar-box {
+		display: flex;
+		background-color: #FFFFFF;
+		height: calc(100vh - 130px);
+		overflow: auto;
+
+		/deep/ .van-sidebar {
+			width: 220rpx;
+			height: 100%;
+			overflow-y: auto;
+			font-size: 26rpx;
+			font-weight: 400;
+			line-height: 39rpx;
+			color: #0F0404;
+		}
+
+		.video-box {
+			height: 100%;
+			overflow-y: auto;
+		}
+	}
+</style>

+ 51 - 0
src/pages/carVideo/components/branchTwo.vue

@@ -0,0 +1,51 @@
+<template>
+	<loading v-if="loading"></loading>
+	<view v-else class="vant-tab">
+		<!-- <m-banner :bannerList="bannerList" height="150"></m-banner> -->
+		<ShortVideo type="slide" class="top-margin"></ShortVideo>
+		<view v-for="(item,index) in carVideoList" :key='index'>
+			<m-video-box :column="[2, 1, 3][index % 3]" :type="[2, 1, 3][index % 3]==1?'left-right':'top-bottom'"
+				:carVideoList='item' v-if="item.children.length==0" />
+			<VideoListBox :carVideoList='item' v-else />
+		</view>
+	</view>
+</template>
+
+<script>
+	import ShortVideo from './shortVideo.vue'
+	import VideoListBox from './videoListBox.vue'
+	export default {
+		components:{
+			ShortVideo,
+			VideoListBox
+		},
+		props: {
+			carVideoList: {
+				type: Array
+			}
+		},
+		data: () => ({
+			bannerList: [],
+			loading: true
+		}),
+		async mounted() {
+			let {
+				data: bannerListData
+			} = await this.$api.home.getHomePageDataList(['carouselChart'])
+			this.bannerList = bannerListData.carouselChart
+			this.$nextTick(() => {
+				this.loading = false
+			})
+		}
+	}
+</script>
+
+<style lang="scss">
+	.vant-tab{
+		height: calc(100vh - 130px);
+		overflow: auto;
+	}
+	.top-margin{
+		margin-top: 10px;
+	}
+</style>

+ 112 - 0
src/pages/carVideo/components/shortVideo.vue

@@ -0,0 +1,112 @@
+<template>
+	<view class="shortVideo-box">
+		<van-cell @click='clickCell' title="短视频" is-link value="更多" />
+		<view class="video-box" v-if="type=='top-bottom'">
+			<m-video-topbottom :column='column' :carVideoItem='item' v-for="(item,index) in carVideoList.list"
+				:key='index' :palyObj='palyObj' @click='returnData(item)' />
+		</view>
+		<view class="video-box" v-if="type=='left-right'">
+			<m-video-leftright @click='returnData(item)' :palyObj='palyObj' :carVideoItem='item'
+				v-for="(item,index) in carVideoList.list" :key='index' />
+		</view>
+		<view class="video-box-slide" v-if="type=='slide'">
+			<m-video-topbottom-short :column='column' :carVideoItem='item' v-for="(item,index) in carVideoList.list"
+				:key='index' :palyObj='palyObj' @click='returnData(item)' />
+		</view>
+	</view>
+</template>
+
+<script>
+	export default {
+		props: {
+			type: {
+				type: String,
+				default: 'top-bottom'
+			},
+			column: {
+				type: Number,
+				default: 2
+			},
+			palyObj: {
+				type: Object,
+				default: {}
+			}
+		},
+		name: "m-video-box",
+		data: () => ({
+			carVideoList: null
+		}),
+		async mounted() {
+			let {
+				data
+			} = await this.$api.carVideo.getShortVideoList()
+			this.carVideoList = data
+		},
+		methods: {
+			returnData(item) {
+				console.log(item)
+				this.$utils.route.goPage('/pages/carVideo/shortVideoPaly',null, {
+					carVideoList: this.carVideoList.list
+				})
+			},
+			clickCell() {
+				this.$utils.route.goPage('/pages/carVideo/more', null, {
+					carVideoList: this.carVideoList
+				})
+			}
+		}
+	}
+</script>
+
+<style lang="scss" scoped>
+	.shortVideo-box{
+		margin-top: 10px;
+	}
+	.cell {
+		display: flex;
+		justify-content: space-between;
+		align-items: center;
+		background-color: #FFFFFF;
+		padding: 10rpx 20rpx;
+		border-bottom: 1rpx solid #e8e8e8;
+
+		.item-tit {
+			border-left: 8rpx solid #E31818;
+			font-size: 30rpx;
+			font-weight: 400;
+			padding: 5rpx;
+		}
+
+		.right-box {
+			display: flex;
+			align-items: center;
+
+			.item-tit-right {
+				font-size: 26rpx;
+				color: #666666;
+				line-height: 58rpx;
+				padding: 11rpx;
+			}
+		}
+
+	}
+
+	.video-box {
+		background-color: #FFFFFF;
+		display: flex;
+		flex-wrap: wrap;
+		padding-left: 30rpx;
+		padding-bottom: 30rpx;
+		margin-bottom: 30rpx;
+		z-index: 0;
+	}
+	.video-box-slide{
+		background-color: #FFFFFF;
+		display: flex;
+		z-index: 0;
+		overflow-x: auto;
+		margin-bottom: 30rpx;
+		padding-left: 30rpx;
+		padding-bottom: 30rpx;
+	}
+</style>

+ 163 - 0
src/pages/carVideo/components/videoListBox.vue

@@ -0,0 +1,163 @@
+<template>
+	<view class="list-box">
+		<van-cell @click='clickCell' :title="carVideoList.chapterName" />
+		<view class="tabs-box">
+			<view class="video-item" @click="gotoPaly(currentItem.list[0])">
+				<view class="image-box">
+					<view class="img-box">
+						<image class="image" :src="currentItem.list[0].cover" mode="aspectFill"></image>
+					</view>
+					<text>{{currentItem.list[0].duration}}</text>
+					<m-icon class="icon" type="bofangshipin"></m-icon>
+				</view>
+			</view>
+			<view class="tabs-bfc">
+				<view class="tabs">
+					<view class="tab" :class="{'tab-active':active===index}" @click="active=index" v-for="(item,index) in carVideoList.children"
+					 :key='index'>
+						{{item.chapterName}}
+					</view>
+				</view>
+			</view>
+			
+		</view>
+	</view>
+</template>
+
+<script>
+	export default {
+		name: "m-video-listBox",
+		props: {
+			carVideoList: {
+				type: Object,
+				default: {}
+			},
+		},
+		data() {
+			return {
+				active: 0
+			};
+		},
+		computed: {
+			currentItem() {
+				return this.carVideoList.children[this.active]
+			}
+		},
+		methods: {
+			gotoPaly(item) {
+				this.$utils.route.goPage('/pages/carVideo/play', null, {
+					carVideoItem: item
+				})
+			}
+		}
+	}
+</script>
+
+<style lang="scss" scoped>
+	.list-box {
+		margin-bottom: 10px;
+		background-color: #FFFFFF;
+
+		.tabs-box {
+			margin: 5px 15px;
+			border-radius: 10px;
+			overflow: hidden;
+		}
+		
+		.tabs-bfc{
+			overflow: auto;
+		}
+		
+		.tabs {
+			background-color: #0A1A33;
+			overflow: auto;
+			white-space: nowrap;
+
+			.tab {
+				display: inline-flex;
+				justify-content: center;
+				align-items: center;
+				text-align: center;
+				width: 75px;
+				height: 37px;
+				background: #5C6066;
+				border-radius: 3px;
+				margin: 3px;
+				font-size: 11px;
+				font-family: PingFang SC;
+				font-weight: 500;
+				color: #FFFFFF;
+				letter-spacing: 0.2800000011920929px;
+			}
+
+			.tab-active {
+				background-color: #498EF5;
+				position: relative;
+				&::after{
+					content: '';
+					width: 5px;
+					height: 5px;
+					position: absolute;
+					top: 0;
+					left: 50%;
+					transform: translate(-50%,-50%) rotate(45deg);
+					background-color: #498EF5;
+					z-index: 1;
+				}
+			}
+		}
+
+		.video-item {
+			position: relative;
+			background-color: #ffffff;
+			display: flex;
+			flex-direction: column;
+			justify-content: center;
+			text-align: center;
+
+			.image-box {
+				position: relative;
+
+				.img-box {
+					width: 100%;
+					padding-bottom: 64%;
+					position: relative;
+
+					.image {
+						position: absolute;
+						left: 0;
+						top: 0;
+						width: 100%;
+						height: 100%;
+					}
+				}
+
+				text {
+					position: absolute;
+					color: red;
+					right: 8rpx;
+					bottom: 8rpx;
+					color: #8A9099;
+				}
+
+				.icon {
+					width: 44rpx;
+					position: absolute;
+					left: 50%;
+					top: 50%;
+					transform: translate(-50%, -50%);
+				}
+			}
+
+			text {
+				font-size: 30rpx;
+				font-weight: 400;
+				line-height: 39rpx;
+				color: #0F0404;
+				white-space: nowrap;
+				text-overflow: ellipsis;
+				overflow: hidden;
+			}
+		}
+	}
+</style>

+ 64 - 0
src/pages/carVideo/index.vue

@@ -0,0 +1,64 @@
+<template>
+	<loading v-if="loading"></loading>
+	<view v-else class="carVideo">
+		<topbar>
+			<van-search shape="round" placeholder="搜索学车视频" @search='search' />
+		</topbar>
+		<van-tabs id='tabs' :active="active" :sticky='true'>
+			<van-tab :title="item.chapterName" v-for="(item,index) in typeList" :key='index' class="vant-tab">
+				<branch-one v-if="index==0" :carVideoList="item.children"></branch-one>
+				<branch-two v-else-if="index==1" :carVideoList="item.children"></branch-two>
+				<branch-two v-else-if="index==2" :carVideoList="item.children"></branch-two>
+				<branch-one v-else-if="index==3" :carVideoList="item.children"></branch-one>
+				<get-cert v-else-if="index==4"></get-cert>
+				<branch-two v-else :carVideoList="item.children"></branch-two>
+			</van-tab>
+		</van-tabs>
+	</view>
+</template>
+
+<script>
+	import branchOne from './components/branchOne.vue'
+	import branchTwo from './components/branchTwo.vue'
+	export default {
+		components: {
+			branchOne,
+			branchTwo,
+		},
+		data: () => ({
+			active: 1,
+			typeList: [],
+			loading: true
+		}),
+		async mounted() {
+			let {
+				data
+			} = await this.$api.carVideo.getTreeList()
+			this.typeList = data
+			this.loading = false
+			this.$nextTick(() => {
+				this.selectComponent('#tabs').resize();
+			})
+		},
+		methods: {
+			async search(e) {
+				let {
+					data
+				} = await this.$api.carVideo.getSearchList(e.detail)
+				console.log(data)
+				this.$utils.route.goPage('/pages/carVideo/more', null, {
+					carVideoList: data
+				})
+			}
+		}
+	}
+</script>
+
+<style lang="scss" scoped>
+	.carVideo {
+		position: relative;
+	}
+	 .vant-tab{
+		height: 100px;
+	}
+</style>

+ 24 - 0
src/pages/carVideo/more.vue

@@ -0,0 +1,24 @@
+<template>
+	<page-meta>
+		<navigation-bar :title="carVideoList.chapterName"/>
+	</page-meta>
+	<view>
+		<m-video-leftright :carVideoItem='item' v-for="(item,index) in carVideoList.list" :key='index'></m-video-leftright>
+	</view>
+</template>
+
+<script>
+	export default {
+		data: () => ({
+			carVideoList: []
+		}),
+		onLoad: async function(option) {
+			let data = await this.goPageGetData()
+			this.carVideoList = data.carVideoList
+		},
+	}
+</script>
+
+<style lang="scss">
+
+</style>

+ 100 - 0
src/pages/carVideo/play.vue

@@ -0,0 +1,100 @@
+<template>
+	<view>
+		<view class="video-box">
+			<video unit-id="adunit-c169acee32b4aa9f" class="video" :src="carVideoItem.videoUrl" controls
+				autoplay></video>
+			<view class="des">
+				<text>{{carVideoItem.title}}</text>
+				<!-- <text>{{carVideoItem.remarks}}</text> -->
+			</view>
+		</view>
+
+		<loading v-if="loading"></loading>
+		<scroll-view v-else>
+			<m-video-leftright :palyObj='{}' @click="videoListClick(item)" :carVideoItem='item' v-for="(item,index) in carVideoList"
+				:key='index'></m-video-leftright>
+		</scroll-view>
+
+		<!-- <loading v-if="loading"></loading>
+		<view v-else>
+			<m-video-box :palyObj.sync='carVideoItem' :column="[2, 1, 3][index % 3]"
+				:type="[1, 1, 1][index % 3]==1?'left-right':'top-bottom'" :carVideoList='item'
+				v-for="(item,index) in carVideoList" :key='index'></m-video-box>
+		</view> -->
+
+	</view>
+</template>
+
+<script>
+	export default {
+		data: () => ({
+			loading: true,
+			carVideoList: [],
+			carVideoItem: {},
+			videoAd: null,
+			switchingTimes: 1,
+		}),
+		watch: {
+			carVideoItem() {
+				//用于激励广告计数
+				this.switchingTimes++
+			}
+		},
+		onLoad: async function(option) {
+			let data = await this.goPageGetData()
+			this.carVideoItem = data.carVideoItem
+		},
+		async mounted() {
+			let {
+				data: carVideoData
+			} = await this.$api.carVideo.getCarVideoList(this.carVideoItem.pid)
+			this.carVideoList = carVideoData
+			this.loading = false
+		},
+		methods: {
+			videoListClick(item) {
+				this.carVideoItem = item
+			}
+		}
+	}
+</script>
+
+<style lang="scss">
+	.video-box {
+		width: 100vw;
+		box-sizing: border-box;
+		margin-bottom: 30rpx;
+		background-color: #FFFFFF;
+		position: sticky;
+		top: 0;
+		z-index: 100;
+
+		.video {
+			width: 100%;
+		}
+
+		.des {
+			display: flex;
+			flex-direction: column;
+			padding: 30rpx;
+			padding-top: 24rpx;
+
+			text {
+				&:nth-of-type(1) {
+					font-size: 30rpx;
+					font-weight: 400;
+					line-height: 39rpx;
+					color: #0F0404;
+				}
+
+				&:nth-of-type(2) {
+					margin-top: 6rpx;
+					font-size: 26rpx;
+					font-weight: 400;
+					line-height: 20rpx;
+					color: #666666;
+				}
+			}
+		}
+	}
+</style>

+ 115 - 0
src/pages/carVideo/shortVideoPaly.vue

@@ -0,0 +1,115 @@
+<template>
+	<view class="shortVideoPaly">
+		<swiper class="swiper-box" :current="current" circular vertical @change='swiperChange'>
+			<swiper-item v-for="(item,index) in videoList" :key='index'>
+				<view class="swiper-item">
+					<video :id='`video${index}`' @click="videoClick" @ended='videoEnded' class="video"
+						:src="item.videoUrl"></video>
+					<view class="des">
+						<text>{{item.title}}</text>
+						<!-- <text>{{item.remarks}}</text> -->
+					</view>
+					<!-- <view class="share">
+						<m-icon type="dianzan"></m-icon>
+						<m-icon type="shoucang"></m-icon>
+						<m-icon type="share-fill"></m-icon>
+					</view> -->
+				</view>
+			</swiper-item>
+		</swiper>
+
+		<m-return></m-return>
+
+	</view>
+</template>
+
+<script>
+	export default {
+		data: () => ({
+			videoContext: null,
+			current: 0,
+			videoList: []
+		}),
+		onLoad: async function(option) {
+			const data = await this.goPageGetData()
+			this.videoList = data.carVideoList
+		},
+		mounted() {
+			this.videoContext = uni.createVideoContext('video0')
+			this.videoContext.play()
+			console.log(this.videoContext)
+		},
+		watch: {
+			// current(newVal) {
+			// 	if (newVal % 5 == 0) {
+			// 		this.videoList.splice((newVal + 5) % 15, 5, ...[1, 1, 1, 1, 1])
+			// 	}
+			// }
+		},
+		methods: {
+			swiperChange(e) {
+				this.current = e.detail.current
+				this.videoContext.pause()
+				this.videoContext = uni.createVideoContext(`video${e.detail.current}`)
+				this.videoContext.play()
+			},
+			videoClick() {
+				console.log(this.videoContext)
+			},
+			videoEnded() {
+				this.current = (this.current + 1) % this.videoList.length
+			}
+		}
+	}
+</script>
+
+<style lang="scss">
+	.shortVideoPaly {
+		height: 100vh;
+		width: 100vw;
+		box-sizing: border-box;
+
+		.swiper-box {
+			width: 100%;
+			height: 100%;
+
+			.swiper-item {
+				width: 100%;
+				height: 100%;
+				position: relative;
+
+				.video {
+					width: 100%;
+					height: 100%;
+					z-index: 0;
+				}
+
+				.des {
+					width: 50%;
+					// background-color: #ffffff;
+					color: #FFFFFF;
+					position: absolute;
+					left: 20rpx;
+					bottom: 100rpx;
+					display: flex;
+					flex-direction: column;
+					z-index: 1;
+				}
+
+				.share {
+					background-color: #ffffff;
+					position: absolute;
+					right: 20rpx;
+					bottom: 100rpx;
+					display: flex;
+					flex-direction: column;
+					height: 200rpx;
+					justify-content: space-between;
+					align-items: center;
+					z-index: 1;
+				}
+			}
+
+		}
+	}
+</style>

+ 70 - 0
src/pages/cinema/cinemalist.vue

@@ -0,0 +1,70 @@
+<template>
+	<loading v-if="dateLoading"></loading>
+	<view v-else>
+		<van-tabs :active='active' :swipe-threshold='3' animated sticky id='tabs'>
+			<van-tab :title="$utils.getDay(dateItem)+' '+dateItem.slice(5)" v-for='(dateItem,dateIndex) in showDate' :key='index'>
+				<loadSke :loading='cinemaLoading' :list='cinemaList[dateItem]'>
+					<cinema-Item @tap='$utils.goPage(`/pages/cinema/schedulelist?cinemaId=${item.cinemaId}&filmId=${filmId}`)'
+					 v-for="(item,index) in cinemaList[dateItem]" :key='index' :cinema='item'></cinema-Item>
+				</loadSke>
+			</van-tab>
+		</van-tabs>
+	</view>
+</template>
+
+<script>
+	import cinemaItem from '@/pages/cinema/components/cinema-Item.vue'
+	export default {
+		components: {
+			cinemaItem
+		},
+		data: () => ({
+			active: 0,
+			cinemaList: {},
+			cinemaLoading: true,
+			dateLoading: true,
+			filmId: null,
+			cityId: null,
+			location: null,
+			showDate: []
+		}),
+		onLoad: function(option) {
+			this.filmId = option.filmId
+			this.cityId = option.cityId
+			this.location = option.location.split(',')
+		},
+		mounted() {
+			this.init()
+		},
+		methods: {
+			async init() {
+				let showDateRes = await this.$api.cinema.getShowDate({
+					cityId: this.cityId,
+					filmId: this.filmId,
+				})
+				this.showDate = showDateRes.data.data.dateList
+				this.dateLoading = false
+				this.$nextTick(() => {
+					this.selectComponent('#tabs').resize();
+				})
+				this.showDate.forEach(async val => {
+					let showListRes = await this.$api.cinema.getShowList({
+						cityId: this.cityId,
+						filmId: this.filmId,
+						latitude: this.location[1],
+						longitude: this.location[0],
+						page: 1,
+						limit: 30,
+						date: val
+					})
+					this.$set(this.cinemaList, val, showListRes.data.data.list)
+					this.cinemaLoading = false
+				})
+
+			}
+		}
+	}
+</script>
+
+<style lang="scss">
+</style>

+ 36 - 0
src/pages/cinema/citylist.vue

@@ -0,0 +1,36 @@
+<template>
+	<view>
+		<van-index-bar>
+			<loading v-if="loading" />
+			<view v-for="(item,index) in cityList" :key='index'>
+				<van-index-anchor :index="index" />
+				<van-cell @click='selectCity(sonitem)' :title="sonitem.regionName" v-for="(sonitem,sonindex) in item" :key='sonindex' />
+			</view>
+		</van-index-bar>
+	</view>
+</template>
+
+<script>
+	export default {
+		data: () => ({
+			cityList: [],
+			loading: true
+		}),
+		onLoad: async function(option) {
+			let data = await this.goPageGetData()
+			this.cityList = data.cityList
+			this.loading = false
+		},
+		methods: {
+			selectCity(obj) {
+				this.$store.commit('SET_CITYOBJ', obj)
+				this.$store.commit('SET_CITYID', obj.cityId)
+				uni.navigateBack()
+			}
+		}
+	}
+</script>
+
+<style lang="scss">
+
+</style>

+ 68 - 0
src/pages/cinema/components/cinema-Item.vue

@@ -0,0 +1,68 @@
+<template>
+	<view class="cinema-box">
+		<view class="tit">
+			<text>{{cinema.cinemaName}}</text>
+			<text class="text-2"
+				@click.stop="openLocation(cinema)">{{cinema.distance.includes('m') ? cinema.distance : cinema.distance+' km'}}</text>
+		</view>
+		<view class="tit">
+			<text class="address">{{cinema.address}}</text>
+			<view @click.stop="openLocation(cinema)">
+				<m-icon type="dingwei" color="#304ECE" />
+			</view>
+		</view>
+	</view>
+</template>
+
+<script>
+	export default {
+		props: {
+			cinema: Object,
+		},
+		methods: {
+			openLocation(item) {
+				uni.openLocation({
+					latitude: item.latitude,
+					longitude: item.longitude
+				})
+			},
+		}
+	}
+</script>
+
+<style lang="scss" scoped>
+	.cinema-box {
+		padding: 30rpx;
+		border-top: 1rpx solid #E8E8E8;
+		background-color: #FFFFFF;
+		display: flex;
+		flex-direction: column;
+
+		.tit {
+			display: flex;
+			justify-content: space-between;
+			align-items: center;
+
+			.text-1 {
+				font-size: 30rpx;
+				color: #0F0404;
+			}
+
+			.text-2 {
+				font-size: 26rpx;
+				color: #999999;
+				white-space: nowrap;
+			}
+		}
+
+		.address {
+			margin-top: 20rpx;
+			width: 600rpx;
+			font-size: 26rpx;
+			color: #666666;
+			white-space: nowrap;
+			overflow: hidden;
+			text-overflow: ellipsis;
+		}
+	}
+</style>

+ 405 - 0
src/pages/cinema/index.vue

@@ -0,0 +1,405 @@
+<template>
+	<scroll-view scroll-y class="cinema">
+		<view class='topbar'>
+			<topbar>
+				<view class="topbar-box">
+					<view class="left-box" @click="$utils.goPage(`/pages/cinema/citylist`,null,{cityList:cityList})">
+						<van-icon name="location" />
+						<text>{{address}}</text>
+						<van-icon name="arrow-down" />
+					</view>
+					<van-search shape="round" :placeholder="searchTitle" @search='onSearchChange' @change='onSearchChange' />
+				</view>
+			</topbar>
+		</view>
+		<view class="tabs-box">
+			<van-tabs :active='tabActive' animated @change='tabsChange'>
+				<van-tab title="热映">
+					<loadSke :loading='hotLoading' :list='hotList'>
+						<view class="flex-box">
+							<view @click="$utils.goPage(`/pages/cinema/cinemalist?filmId=${item.filmId}&cityId=${cityId}&location=${location}`)"
+							 class="film-box" v-for="(item) in hotList" :key='item.filmId'>
+								<image :src="item.pic" mode="scaleToFill" class="img" draggable></image>
+								<view class="bottom-box">
+									<view class="tit">
+										<text class="text-1">{{item.name}}</text>
+										<text class="text-2">{{item.grade ?'评分'+item.grade : '暂无评分'}}</text>
+									</view>
+									<view class="des-box">
+										<view class="des">{{item.filmTypes}}</view>
+										<view class="des">{{item.cast}}</view>
+									</view>
+
+									<button type="default" class="buy">
+										购 票
+									</button>
+								</view>
+							</view>
+						</view>
+					</loadSke>
+				</van-tab>
+				<van-tab title="影院">
+					<loadSke :loading='cinemaLoading' :list='cinemaList'>
+						<cinema-Item @tap='$utils.goPage(`/pages/cinema/schedulelist?cinemaId=${item.cinemaId}&filmId=${filmId}`)'
+						 v-for="item in cinemaList" :key='item.cinemaId' :cinema='item'></cinema-Item>
+					</loadSke>
+				</van-tab>
+				<van-tab title="即将上映">
+					<loadSke :loading='soonLoading'>
+						<view class="soon-box" v-for="(ObjItem,ObjIndex) in soonList" :key='ObjIndex'>
+							<view class="tit-text">
+								<van-icon class='icon' name="https://t1-1305573081.cos.ap-shanghai.myqcloud.com/wxapp/static/imgs/%E6%97%A5%E6%9C%9F.png" />
+								{{ObjIndex}}
+							</view>
+							<view class="flex-box">
+								<view class="film-box" v-for="(item) in ObjItem" :key='item.filmId'>
+									<image :src="item.pic" mode="scaleToFill" class="img" draggable></image>
+									<view class="bottom-box">
+										<view class="tit">
+											<text class="text-1">{{item.name}}</text>
+											<text class="text-2">{{item.grade ?'评分'+item.grade : '暂无评分'}}</text>
+										</view>
+										<view class="des-box">
+											<view class="des">{{item.filmTypes}}</view>
+											<view class="des">{{item.cast}}</view>
+										</view>
+									</view>
+								</view>
+							</view>
+						</view>
+					</loadSke>
+				</van-tab>
+			</van-tabs>
+		</view>
+
+	</scroll-view>
+</template>
+
+
+<script>
+	import cinemaItem from '@/pages/cinema/components/cinema-Item.vue'
+	export default {
+		components: {
+			cinemaItem
+		},
+		data: () => ({
+			tabActive: 0,
+			hotList: [],
+			soonList: {},
+			hotLoading: true,
+			soonLoading: true,
+			location: [119.131390, 26.150210],
+			cityList: [],
+			address: '定位中',
+			cinemaList: [],
+			cinemaLoading: true,
+			searchList: null,
+			searchType: 0,
+			searchTitle: '请输入电影名称',
+		}),
+		async mounted() {
+			this.setFilmDiscount()
+			await this.getLocation()
+			await this.getCityList()
+			this.init()
+			this.cinemaListInit()
+		},
+		computed: {
+			cityId() {
+				return this.$store.state.cinema.cityId;
+			}
+		},
+		watch: {
+			cityId() {
+				this.address = this.$store.state.cinema.cityObj.regionName;
+				this.init()
+				this.cinemaListInit()
+			}
+		},
+		methods: {
+			onSearchChange(e) {
+				if (this.searchType == 0) {
+					this.searchList || (this.searchList = this.hotList)
+					this.hotList = this.searchList.filter(val => {
+						return val.name.includes(e.detail)
+					})
+				}
+				if (this.searchType == 1) {
+					this.searchList || (this.searchList = this.cinemaList)
+					this.cinemaList = this.searchList.filter(val => {
+						return val.cinemaName.includes(e.detail)
+					})
+				}
+				if (this.searchType == 2) {
+					this.searchList || (this.searchList = this.soonList)
+					this.soonList = {}
+					for (let key in this.searchList) {
+						let aDay = this.searchList[key].filter(val => {
+							return val.name.includes(e.detail)
+						})
+						aDay.length && (this.soonList[key] = aDay)
+					}
+				}
+			},
+			tabsChange(e) {
+				let listMap = new Map([
+					[0, () => this.hotList = this.searchList],
+					[1, () => this.cinemaList = this.searchList],
+					[2, () => this.soonList = this.searchList]
+				])
+				//切换搜索前复原数据
+				this.searchList && listMap.get(this.searchType)()
+
+				this.tabActive = e.detail.index
+				this.searchType = e.detail.index
+				this.searchList = null
+
+				let aMap = new Map([
+					[0, '请输入电影名称'],
+					[1, '请输入影院名称'],
+					[2, '请输入电影名称']
+				])
+				//修改搜索框提示
+				this.searchTitle = aMap.get(e.detail.index)
+			},
+			setFilmDiscount() {
+				this.$api.cinema.getFilmDiscount().then(res => {
+					this.$store.commit('SET_FILMDISCOUNT', res.data)
+				})
+			},
+			async getLocation() {
+				try {
+					let location = await wx.getLocation()
+					this.location = [location.longitude.toFixed(6), location.latitude.toFixed(6)]
+					let address = await this.$api.amap.regeo({
+						location: this.location.toString()
+					})
+					this.address = address.regeocode.addressComponent.city.slice(0, -1)
+				} catch (e) {
+					console.log(e)
+					this.address = '北京'
+				}
+			},
+			async getCityList() {
+				let cityListRes = await this.$api.cinema.getCityList()
+				let cityList = cityListRes.data.data.list
+				let cityObj = {}
+				cityList.map((val) => {
+					cityObj[val.pinYin] || (cityObj[val.pinYin] = [])
+					cityObj[val.pinYin].push(val)
+					if (val.regionName == this.address) {
+						this.selectCity(val)
+					}
+				})
+				this.cityList = cityObj
+			},
+			async init() {
+				this.hotLoading = true
+				this.soonLoading = true
+				let hotListRes = await this.$api.cinema.getHotList({
+					cityId: this.cityId
+				})
+				this.hotList = hotListRes.data.data.list
+				this.$nextTick(() => {
+					this.hotLoading = false
+				})
+
+				let soonListRes = await this.$api.cinema.getSoonList({
+					cityId: this.cityId
+				})
+				let soonListObj = {}
+				soonListRes.data.data.list.forEach((val) => {
+					soonListObj[val.publishDate.slice(0, 10)] || (soonListObj[val.publishDate.slice(0, 10)] = [])
+					soonListObj[val.publishDate.slice(0, 10)].push(val)
+				})
+				this.soonList = soonListObj
+				this.$store.commit('SET_FILMLIST', this.hotList.concat(soonListRes.data.data.list))
+				this.$nextTick(() => {
+					this.soonLoading = false
+				})
+			},
+			async cinemaListInit() {
+				this.cinemaLoading = true
+				let showListRes = await this.$api.cinema.getCinemaList({
+					cityId: this.cityId,
+					latitude: this.location[1],
+					longitude: this.location[0],
+				})
+				showListRes.data.data.list.map(val => {
+					val.distance = (Math.sqrt((val.latitude - this.location[1]) ** 2 + (val.longitude - this.location[0]) ** 2) *
+						111).toFixed(2)
+					return val
+				})
+				showListRes.data.data.list.sort(function(a, b) {
+					return a.distance - b.distance
+				})
+				this.cinemaList = showListRes.data.data.list
+				this.cinemaLoading = false
+			},
+			selectCity(obj) {
+				this.$store.commit('SET_CITYOBJ', obj)
+				this.$store.commit('SET_CITYID', obj.cityId)
+			}
+		}
+	}
+</script>
+
+<style scoped lang="scss">
+	.cinema {
+		height: 100%;
+		position: relative;
+	}
+
+	.topbar {
+		position: sticky;
+		top: 0;
+		left: 0;
+		right: 0;
+		z-index: 10;
+		overflow: hidden;
+
+		.topbar-box {
+			display: flex;
+			align-items: center;
+
+			.left-box {
+				min-width: 150rpx;
+				display: flex;
+				justify-content: center;
+				align-items: center;
+				margin-left: 20rpx;
+
+				text {
+					white-space: nowrap;
+				}
+			}
+		}
+	}
+
+	.tab {
+		display: flex;
+		justify-content: space-around;
+		align-items: stretch;
+		background-color: #FFFFFF;
+		position: sticky;
+		top: 0;
+		left: 0;
+		z-index: 1;
+
+		.text {
+			padding: 30rpx 0;
+			font-size: 30rpx;
+			color: #0F0404;
+
+		}
+
+		.hover {
+			border-bottom: 6rpx solid red;
+		}
+
+		.location-box {
+			padding: 30rpx 0;
+			font-size: 30rpx;
+			color: #0F0404;
+			display: flex;
+			justify-content: center;
+			align-items: center;
+		}
+
+	}
+
+	.flex-box {
+		display: flex;
+		justify-content: space-between;
+		flex-wrap: wrap;
+		background: #FFFFFF;
+		margin-top: 1rpx;
+		padding: 0rpx 20rpx;
+		padding-bottom: 20rpx;
+
+		.film-box {
+			width: 334rpx;
+			border-radius: 20rpx;
+			overflow: hidden;
+			background: #FFFFFF;
+			margin: 30rpx 11rpx 0;
+			box-shadow: 0px 2px 16px 0px rgba(68, 6, 6, 0.2);
+
+			.img {
+				width: 100%;
+				height: 456rpx;
+			}
+
+			.bottom-box {
+				padding: 30rpx 20rpx;
+
+				.tit {
+					display: flex;
+					justify-content: space-between;
+
+					.text-1 {
+						width: 200rpx;
+						font-size: 26rpx;
+						overflow: hidden;
+						text-overflow: ellipsis;
+						white-space: nowrap;
+					}
+
+					.text-2 {
+						font-size: 26rpx;
+						color: #ED4F24;
+						white-space: nowrap;
+					}
+				}
+
+				.des-box {
+					margin-top: 20rpx;
+
+					.des {
+						width: 100%;
+						font-size: 22rpx;
+						color: #666666;
+						overflow: hidden;
+						text-overflow: ellipsis;
+						white-space: nowrap;
+					}
+				}
+
+				.buy {
+					margin-top: 30rpx;
+					width: 126rpx;
+					height: 60rpx;
+					background: linear-gradient(90deg, #E31818, #ED3E24, #ED4F24);
+					border-radius: 30rpx;
+					font-size: 26rpx;
+					font-weight: 400;
+					color: #FFFFFF;
+					display: flex;
+					justify-content: center;
+					align-items: center;
+					white-space: nowrap;
+				}
+			}
+
+		}
+
+	}
+
+	.soon-box {
+		margin-top: 20rpx;
+
+		.tit-text {
+			background-color: #FFF0E5;
+			padding: 28rpx 55rpx;
+			font-size: 26rpx;
+			font-weight: bold;
+			color: #0F0404;
+			display: flex;
+			align-items: center;
+
+			.icon {
+				margin-right: 20rpx;
+			}
+		}
+	}
+</style>

+ 348 - 0
src/pages/cinema/orderdes.vue

@@ -0,0 +1,348 @@
+<template>
+	<view class="page">
+		<loadSke :loading='loading'>
+			<view class="remind-top">首页->我的->我的订单</view>
+			<view class="des-box">
+				<loadSke :loading='qrcodeLoading'>
+					<view v-if="filmDes.orderStatus < 4" class="code-box">
+						<image
+							src="https://t1-1305573081.cos.ap-shanghai.myqcloud.com/wxapp/static/imgs/%E7%94%B5%E5%BD%B1%E7%A5%A8%E7%AD%89%E5%BE%85.png"
+							class="qrcode-loading" mode="widthFix"></image>
+					</view>
+					<view v-else-if="filmDes.orderStatus != 10" class="code-box" v-for="(item,index) in filmDes.qrcode"
+						:key='index'>
+						<view class="code">
+							<text>取票码</text>
+							<text>{{item.code}}</text>
+						</view>
+						<image class="qrcode" :src="item.qrcode" mode="widthFix"></image>
+					</view>
+					<view v-else class="code-box">
+						<image
+							src="https://t1-1305573081.cos.ap-shanghai.myqcloud.com/wxapp/static/imgs/%E8%AE%A2%E5%8D%95%E5%85%B3%E9%97%AD.png"
+							class="qrcode-loading" mode="widthFix"></image>
+					</view>
+				</loadSke>
+				<view class="order-num">
+					<text>订单号:{{outTradeNo}}</text>
+					<text>{{orderDes.orderStatusDesc}}</text>
+					<text v-if="filmDes.closeCause">{{filmDes.closeCause}}</text>
+				</view>
+				<view class="des">
+					<text class="film-name">{{orderDes.filmName}}</text>
+					<view class="film-time">
+						<text>时间</text>
+						<text>{{orderDes.showTime}}</text>
+					</view>
+					<view class="film-address">
+						<text>影院</text>
+						<text>{{orderDes.cinemaName}}</text>
+					</view>
+					<view class="film-video">
+						<text>影厅</text>
+						<text>{{orderDes.hallName}}</text>
+					</view>
+					<view class="film-seat">
+						<text>座位</text>
+						<view class="seat-box">
+							<text v-for="(item,index) in orderDes.seat" :key='index'>{{item}}</text>
+						</view>
+					</view>
+				</view>
+				<view class="price">
+					<text>总价</text>
+					<text>¥{{orderDes.total}}</text>
+				</view>
+			</view>
+		</loadSke>
+	</view>
+</template>
+
+<script>
+	export default {
+		data: () => ({
+			orderDes: {},
+			outTradeNo: null,
+			loading: true,
+			pollingTiemId: null,
+			filmDes: {},
+			qrcode: null,
+			qrcodeLoading: true
+		}),
+		onLoad: function(option) {
+			this.outTradeNo = option.outTradeNo
+		},
+		mounted() {
+			this.init()
+		},
+		methods: {
+			async init() {
+				let orderRes = await this.$api.order.getWxOrder(this.outTradeNo)
+				this.orderDes = orderRes.data
+
+				let filmRes = await this.$api.cinema.orderQuery({
+					thirdOrderId: this.outTradeNo
+				})
+				this.filmDes = filmRes.data.data
+				if (this.filmDes.orderStatus < 4) {
+					this.polling()
+				} else if (this.filmDes.orderStatus < 10) {
+					this.qrcodeShow()
+				}
+
+				this.loading = false
+				this.qrcodeLoading = false
+			},
+			polling() {
+				this.pollingTiemId = setInterval(async () => {
+					let filmRes = await this.$api.cinema.orderQuery({
+						thirdOrderId: this.outTradeNo
+					})
+					this.filmDes = filmRes.data.data
+					if (this.filmDes.orderStatus == 4 || this.filmDes.orderStatus == 5) {
+						clearInterval(this.pollingTiemId)
+						this.qrcodeShow()
+					}
+				}, 3000)
+			},
+			qrcodeShow() {
+				let qrcode = []
+				this.filmDes.ticketCode.forEach(async val => {
+					if (val.type == 1) {
+						let qr = await this.$utils.qrcodeGenerate(val.code)
+						qrcode.push({
+							qrcode: qr,
+							code: val.code
+						})
+					}
+				})
+				this.$set(this.filmDes, 'qrcode', qrcode)
+			}
+		},
+		beforeDestroy() {
+			clearInterval(this.pollingTiemId)
+		}
+	}
+</script>
+
+<style lang="scss">
+	.page {
+		padding-bottom: 20rpx;
+	}
+
+	.remind {
+		padding-top: 36rpx;
+		font-size: 26rpx;
+		font-weight: 400;
+		color: #0F0404;
+		text-align: center;
+	}
+
+	.remind-top {
+		margin-top: 36rpx;
+		font-size: 26rpx;
+		font-weight: 400;
+		color: #ff0000;
+		text-align: center;
+	}
+
+	.des-box {
+		width: 564rpx;
+		background: #FFFFFF;
+		border-radius: 20rpx;
+		margin: auto;
+		margin-top: 30rpx;
+
+		.code-box {
+			display: flex;
+			flex-direction: column;
+			align-items: center;
+			padding-bottom: 38rpx;
+
+			.code {
+				margin-top: 43rpx;
+
+				text {
+					font-size: 26rpx;
+					font-weight: 400;
+					color: #666666;
+					margin-right: 20rpx;
+
+					&:nth-child(2) {
+						color: #0F0404;
+					}
+				}
+			}
+
+			.qrcode {
+				margin-top: 43rpx;
+				width: 360rpx;
+				height: 360rpx;
+			}
+
+			.qrcode-loading {
+				margin-top: 43rpx;
+				width: 100%;
+			}
+		}
+
+		.order-num {
+			display: flex;
+			flex-direction: column;
+			justify-content: space-between;
+			align-items: center;
+			padding: 34rpx 31rpx;
+			border-top: 1rpx dashed #D9D9D9;
+			border-bottom: 1rpx dashed #D9D9D9;
+			position: relative;
+
+			&::after {
+				content: '';
+				width: 24rpx;
+				height: 24rpx;
+				border-radius: 50%;
+				background-color: #F1F1F1;
+				position: absolute;
+				top: 0;
+				left: 0;
+				transform: translate(-50%, -50%);
+			}
+
+			&::before {
+				content: '';
+				width: 24rpx;
+				height: 24rpx;
+				border-radius: 50%;
+				background-color: #F1F1F1;
+				position: absolute;
+				top: 0;
+				right: 0;
+				transform: translate(50%, -50%);
+			}
+
+			text {
+				&:nth-child(1) {
+					margin-top: 60rpx;
+					word-break: break-all;
+					font-size: 22rpx;
+					font-weight: 400;
+					color: #666666;
+				}
+
+				&:nth-child(2) {
+					margin-top: 10rpx;
+					padding: 10rpx;
+					display: flex;
+					justify-content: center;
+					align-items: center;
+					background: #FFE5E5;
+					border-radius: 20rpx;
+					border-top-left-radius: 0;
+					border-bottom-left-radius: 0;
+					font-size: 20rpx;
+					font-weight: 400;
+					color: #E31818;
+					position: absolute;
+					left: 0;
+					top: 20rpx;
+				}
+
+				&:nth-child(3) {
+					margin-top: 10rpx;
+					padding: 10rpx;
+					display: flex;
+					justify-content: center;
+					align-items: center;
+					font-size: 20rpx;
+					font-weight: 400;
+					color: #E31818;
+				}
+			}
+		}
+
+		.des {
+			padding: 45rpx 30rpx;
+			border-bottom: 1rpx dashed #D9D9D9;
+			display: flex;
+			flex-direction: column;
+
+			.film-name {
+				font-size: 30rpx;
+				font-weight: 400;
+				color: #0F0404;
+			}
+
+			text {
+				font-size: 26rpx;
+				font-weight: 400;
+				color: #666666;
+				margin-right: 20rpx;
+				white-space: nowrap;
+			}
+
+			.film-time {
+				text:nth-child(2) {
+					color: #999999;
+				}
+			}
+
+			.film-address {
+				display: flex;
+				justify-content: flex-start;
+				align-items: stretch;
+				
+				text:nth-child(2) {
+					color: #999999;
+					white-space: pre-wrap;
+				}
+			}
+
+			.film-video {
+				display: flex;
+				justify-content: flex-start;
+				align-items: stretch;
+				
+				text:nth-child(2) {
+					color: #999999;
+					white-space: pre-wrap;
+				}
+			}
+
+			.film-seat {
+				display: flex;
+				justify-content: flex-start;
+				align-items: stretch;
+				margin-top: 10rpx;
+
+				.seat-box {
+					display: flex;
+					flex-wrap: wrap;
+
+					text {
+						height: 40rpx;
+						padding: 4rpx 15rpx;
+						margin-bottom: 10rpx;
+						background: #EBEBEB;
+						border-radius: 4rpx;
+						color: #999999;
+					}
+				}
+			}
+		}
+
+		.price {
+			padding: 40rpx 30rpx;
+
+			text {
+				font-size: 26rpx;
+				font-weight: 400;
+				color: #666666;
+				margin-right: 20rpx;
+
+				&:nth-child(2) {
+					color: #E31818;
+				}
+			}
+		}
+	}
+</style>

+ 508 - 0
src/pages/cinema/placeorder.vue

@@ -0,0 +1,508 @@
+<template>
+	<view>
+		<view class="film-des">
+			<image class="left-img" :src="filmDes.pic" mode="widthFix"></image>
+			<view class="right-box">
+				<view class="film-name">
+					{{showItem.filmName}}
+				</view>
+				<view class="film-time">
+					{{showItem.showTime}}<br />
+					{{showItem.cinemaName}}<br />
+					{{showItem.hallName}}
+				</view>
+				<view class="film-caveat">
+					<view class="item">
+						<van-icon name="clear" color='#E31818' />
+						不支持退票
+					</view>
+					<view class="item">
+						<van-icon name="clear" color='#E31818' />
+						不支持改签
+					</view>
+				</view>
+			</view>
+		</view>
+		<view class="select-des">
+			<view class="tit-text">
+				选择购票方式
+			</view>
+			<van-radio-group :value="radioType" @change="radioOnChange">
+				<view class="options-box">
+					<view class="left-box">
+						<image class="img" src="https://t1-1305573081.cos.ap-shanghai.myqcloud.com/wxapp/static/imgs/%E7%89%B9%E6%83%A0%E8%B4%AD%E7%A5%A8.png"
+						 mode="widthFix"></image>
+						<view class="text-box">
+							<text class="top">特惠购票</text>
+							<text class="bottom">固定折扣,快速出票</text>
+						</view>
+					</view>
+					<view class="right-box">
+						<view class="text-box">
+							<text class="top">¥{{aPrice}}/张</text>
+							<text class="bottom">优惠 ¥{{aDiscount}}元</text>
+						</view>
+						<van-radio :name="1" checked-color="#07c160"></van-radio>
+					</view>
+				</view>
+				<view class="options-box">
+					<view class="left-box">
+						<image class="img" src="https://t1-1305573081.cos.ap-shanghai.myqcloud.com/wxapp/static/imgs/%E5%BF%AB%E9%80%9F%E8%B4%AD%E7%A5%A8.png"
+						 mode="widthFix"></image>
+						<view class="text-box">
+							<text class="top">快速购票</text>
+							<text class="bottom">无需等待,即买即兑</text>
+						</view>
+					</view>
+					<view class="right-box">
+						<view class="text-box">
+							<text class="top">¥{{(showItem.netPrice/100).toFixed(2)}}/张</text>
+						</view>
+						<van-radio :name="2" checked-color="#07c160"></van-radio>
+					</view>
+				</view>
+				<view class="options-box">
+					<view class="left-box">
+						<image class="img" src="https://t1-1305573081.cos.ap-shanghai.myqcloud.com/wxapp/static/imgs/%E7%AB%9E%E4%BB%B7.png"
+						 mode="widthFix"></image>
+						<view class="text-box">
+							<text class="top">竞价购买</text>
+							<text class="bottom">为您网罗最低的折扣,约耗时几分钟</text>
+						</view>
+					</view>
+					<view class="right-box">
+						<view class="text-box">
+							<text class="top">等待竞价</text>
+						</view>
+						<van-radio :name="3" checked-color="#07c160" disabled></van-radio>
+					</view>
+				</view>
+			</van-radio-group>
+		</view>
+		<view class="seat-select">
+			<text class="tit-text">无座时接受系统调座</text>
+			<van-switch :checked="acceptChangeSeat==1" @change="onChange" size="24px" />
+		</view>
+		<!-- <button class="server" open-type="getPhoneNumber" @getphonenumber='getPhoneNumber' :plain="true">
+			<van-cell title="手机号(非必填)" :value="userPhone">
+				<m-icon slot="icon" type="lxkf" color="#d81e06"/>
+			</van-cell>
+		</button> -->
+		<view class="seat-des">
+			<view class="tit-text">
+				购票须知
+			</view>
+			<view class="seat-box">
+				<view class="left">
+					座位:
+				</view>
+				<view class="right">
+					<view class="item" v-for="(item,index) in seatResult" :key='index'>
+						<text class="top">{{item.seatNo}}</text>
+						<text class="bottom">¥{{aPrice}}</text>
+					</view>
+				</view>
+			</view>
+		</view>
+		<view class="buy-des">
+			<view class="left">
+				<text class="one">总价:</text>
+				<text class="two">¥{{allPrice}}</text>
+				<text class="three">优惠¥{{allDiscount}}元</text>
+			</view>
+			<view class="right">
+				<text class="text">{{seatResult.length}}张</text>
+				<button class="btn" type="default" @click="buy">去支付</button>
+			</view>
+		</view>
+	</view>
+</template>
+
+<script>
+	export default {
+		data: () => ({
+			showItem: {},
+			seatResult: [],
+			radioType: 1,
+			acceptChangeSeat: 0,
+			userPhone:null,
+			orderRes: {}
+		}),
+		onLoad: async function(option) {
+			let data = await this.goPageGetData()
+			this.showItem = data.showItem
+			this.seatResult = data.seatResult.map((val) => {
+				return JSON.parse(val)
+			})
+		},
+		computed: {
+			filmDes() {
+				let des = {}
+				this.$store.state.cinema.filmList.forEach((val) => {
+					if (val.filmId == this.showItem.filmId) {
+						des = val
+					}
+				})
+				return des;
+			},
+			filmDiscount() {
+				return this.$store.state.cinema.filmDiscount;
+			},
+			discountRule() {
+				return this.$store.state.cinema.discountRule;
+			},
+			aPrice() {
+				let discountRule = (this.showItem.netPrice > 3900 ? this.discountRule.upDiscountRate : this.discountRule.downDiscountRate)
+				let filmDiscount = this.filmDiscount
+				let netPrice = this.showItem.netPrice / 100
+				return (netPrice * discountRule * filmDiscount).toFixed(2)
+			},
+			aDiscount() {
+				let discountRule = (this.showItem.netPrice > 3900 ? this.discountRule.upDiscountRate : this.discountRule.downDiscountRate)
+				let filmDiscount = this.filmDiscount
+				let netPrice = this.showItem.netPrice / 100
+				return (netPrice - netPrice * discountRule * filmDiscount).toFixed(2)
+			},
+			allPrice() {
+				let discountRule = (this.showItem.netPrice > 3900 ? this.discountRule.upDiscountRate : this.discountRule.downDiscountRate)
+				let filmDiscount = this.filmDiscount
+				let netPrice = this.showItem.netPrice / 100
+				if (this.radioType == 1) {
+					return (this.seatResult.length * netPrice * discountRule * filmDiscount).toFixed(2)
+				}
+				if (this.radioType == 2) {
+					return (this.seatResult.length * netPrice).toFixed(2)
+				}
+			},
+			allDiscount() {
+				let discountRule = (this.showItem.netPrice > 3900 ? this.discountRule.upDiscountRate : this.discountRule.downDiscountRate)
+				let filmDiscount = this.filmDiscount
+				let netPrice = this.showItem.netPrice / 100
+				if (this.radioType == 1) {
+					return (this.seatResult.length * (netPrice - netPrice * discountRule * filmDiscount)).toFixed(2)
+				}
+				if (this.radioType == 2) {
+					return (this.seatResult.length * (netPrice - netPrice)).toFixed(2)
+				}
+			},
+		},
+		methods: {
+			getPhoneNumber(e){
+				console.log(e)
+				this.userPhone=e.phoneNumber
+			},
+			radioOnChange(e) {
+				this.orderRes = {}
+				this.radioType = e.detail
+			},
+			onChange({
+				detail
+			}) {
+				// 需要手动对 checked 状态进行更新
+				if (detail) {
+					this.acceptChangeSeat = 1
+				} else {
+					this.acceptChangeSeat = 0
+				}
+			},
+			async buy() {
+				//已有订单则直接请求历史数据
+				if (this.orderRes.code == 200) {
+					let payRes = await wx.requestPayment(this.orderRes.data)
+					console.log(payRes)
+					return false
+				}
+
+				let seat = [],
+					seatId = [],
+					seatNo = []
+				this.seatResult.forEach(val => {
+					seat.push(val.seatNo)
+					seatNo.push(val.seatNo)
+					seatId.push(val.seatId)
+				})
+				this.$utils.wxUtils.subscribeToNews().then(toNew=>{
+					console.log(toNew)
+					this.$api.cinema.prepareOrder({
+						acceptChangeSeat: this.acceptChangeSeat,
+						seat: seat.join(','),
+						seatId: seatId.join('|'),
+						seatNo: seatNo.join('|'),
+						showId: this.showItem.showId,
+						cinemaId: this.showItem.cinemaId,
+						goodsPictureUrl: this.filmDes.pic,
+						goodsType: '1',
+						ticketType: this.radioType
+					}).then(async res => {
+						this.orderRes = res
+						let payRes = await wx.requestPayment(this.orderRes.data)
+						if (payRes.errMsg == 'requestPayment:ok') {
+							this.$utils.goPage(`/pages/cinema/orderdes?outTradeNo=${this.orderRes.data.outTradeNo}`, 'reLaunch')
+						}
+					})
+				})
+			}
+		}
+	}
+</script>
+
+<style lang="scss" scoped>
+	.film-des {
+		padding: 40rpx 30rpx;
+		margin-top: 20rpx;
+		background-color: #FFFFFF;
+		display: flex;
+
+		.left-img {
+			width: 170rpx;
+			height: 236rpx;
+			margin-right: 20rpx;
+		}
+
+		.right-box {
+			display: flex;
+			flex-direction: column;
+			justify-content: space-between;
+
+			.film-name {
+				font-size: 30rpx;
+				font-weight: 400;
+				color: #0F0404;
+			}
+
+			.film-time {
+				font-size: 26rpx;
+				font-weight: 400;
+				color: #666666;
+				line-height: 39rpx;
+			}
+
+			.film-caveat {
+				display: flex;
+
+				.item {
+					display: flex;
+					align-items: center;
+					margin-right: 33rpx;
+					font-size: 26rpx;
+					font-weight: 400;
+					color: #0F0404;
+				}
+			}
+		}
+	}
+	
+	.server {
+		border: none;
+		background-color: none;
+		margin: 0;
+		padding: 0;
+		text-align: left;
+		display: flexbox;
+	}
+
+	.select-des {
+		background-color: #FFFFFF;
+		margin-top: 20rpx;
+		padding-bottom: 1rpx;
+
+		.tit-text {
+			padding: 30rpx;
+			font-size: 26rpx;
+			font-weight: 400;
+			color: #0F0404;
+			border-bottom: 1rpx solid #E8E8E8;
+		}
+
+		.options-box {
+			display: flex;
+			justify-content: space-between;
+			align-items: center;
+			margin: 30rpx;
+
+			.left-box {
+				display: flex;
+
+				.img {
+					width: 66rpx;
+					height: 66rpx;
+					margin-right: 20rpx;
+				}
+
+				.text-box {
+					display: flex;
+					flex-direction: column;
+
+					.top {
+						font-size: 26rpx;
+						font-weight: 400;
+						color: #0F0404;
+					}
+
+					.bottom {
+						font-size: 22rpx;
+						font-weight: 400;
+						color: #666666;
+					}
+				}
+			}
+
+			.right-box {
+				display: flex;
+				align-items: center;
+
+				.text-box {
+					display: flex;
+					flex-direction: column;
+					justify-content: space-around;
+					align-items: flex-end;
+					margin-right: 23rpx;
+
+					.top {
+						font-size: 26rpx;
+						font-weight: 400;
+						color: #E31818;
+					}
+
+					.bottom {
+						font-size: 20rpx;
+						font-weight: 400;
+						color: #605A5A;
+					}
+				}
+			}
+		}
+	}
+
+	.seat-select {
+		background-color: #FFFFFF;
+		margin-top: 20rpx;
+		display: flex;
+		justify-content: space-between;
+		align-items: center;
+		padding: 20rpx 30rpx;
+
+		.tit-text {
+			font-size: 26rpx;
+			font-weight: 400;
+			color: #E31818;
+		}
+	}
+
+	.seat-des {
+		background-color: #FFFFFF;
+		margin-top: 20rpx;
+
+		.tit-text {
+			font-size: 26rpx;
+			font-weight: 400;
+			color: #0F0404;
+			padding: 30rpx;
+			border-bottom: 1rpx solid #E8E8E8;
+		}
+
+		.seat-box {
+			display: flex;
+			justify-content: flex-start;
+			padding: 10rpx 30rpx;
+
+			.left {
+				white-space: nowrap;
+				height: 96rpx;
+				margin-top: 10rpx;
+			}
+
+			.right {
+				display: flex;
+				flex-wrap: wrap;
+				justify-content: flex-start;
+				align-items: center;
+
+				.item {
+					width: 134rpx;
+					height: 96rpx;
+					margin: 10rpx;
+					background: #EBEBEB;
+					border-radius: 10rpx;
+					display: flex;
+					flex-direction: column;
+					justify-content: center;
+					align-items: center;
+
+					.top {
+						font-size: 26rpx;
+						font-weight: 400;
+						color: #666666;
+					}
+
+					.bottom {
+						font-size: 22rpx;
+						font-weight: 400;
+						color: #E31923;
+					}
+				}
+			}
+		}
+	}
+
+	.buy-des {
+		display: flex;
+		justify-content: space-between;
+		align-items: center;
+		background-color: #FFFFFF;
+		width: 100vw;
+		box-sizing: border-box;
+		position: fixed;
+		bottom: 0;
+		padding: 15rpx 30rpx;
+		padding-bottom: calc(10px + env(safe-area-inset-bottom)/2);
+
+		.left {
+			display: flex;
+			justify-content: space-between;
+			align-items: center;
+			width: 50%;
+
+			.one {
+				font-size: 26rpx;
+				color: #0F0404;
+			}
+
+			.two {
+				font-size: 36rpx;
+				color: #E31919;
+			}
+
+			.three {
+				font-size: 22rpx;
+				color: #E86125;
+			}
+		}
+
+		.right {
+			width: 40%;
+			display: flex;
+			justify-content: space-between;
+			align-items: center;
+
+			.text {
+				font-size: 26rpx;
+				color: #0F0404;
+			}
+
+			.btn {
+				margin: 0;
+				width: 200rpx;
+				height: 80rpx;
+				background: linear-gradient(90deg, #E31818, #ED3E24, #ED4F24);
+				border-radius: 40rpx;
+				font-size: 30rpx;
+				color: #FFFFFF;
+				display: flex;
+				justify-content: center;
+				align-items: center;
+				white-space: nowrap;
+			}
+		}
+	}
+</style>

+ 335 - 0
src/pages/cinema/schedulelist.vue

@@ -0,0 +1,335 @@
+<template>
+	<page-meta>
+		<navigation-bar :title="filmList[filmId].name" background-color="#FFFFFF" front-color="#000000" />
+	</page-meta>
+	<view class="schedulelist">
+		<loadSke :loading='listLoading'>
+			<view class="des-box">
+				<view class="address">
+					{{cinemaName}}
+				</view>
+				<swiper class="swiper-box" :current="current" previous-margin='200rpx' next-margin='200rpx' @change='swiperChange'>
+					<swiper-item v-for="(item,index) in scheduleListKey" :key='index' class="swiper-item">
+						<image class="image" :class="{imgBig:current==index}" :src="filmList[item].pic" mode="heightFix" :draggable="false" />
+					</swiper-item>
+				</swiper>
+				<view class="film-name">
+					{{filmList[filmId].name}}
+				</view>
+				<view class="film-des">
+					{{filmList[filmId].duration}}分钟 | {{filmList[filmId].filmTypes}} | {{filmList[filmId].cast}}
+				</view>
+			</view>
+
+
+			<view class="schedule-box">
+				<van-tabs :active='tabActive' :swipe-threshold='3' animated swipeable id="tabs" @change='tabsChange'>
+					<van-tab class='schedule-tab' :title="$utils.getDay(index)+' '+index.slice(5)" v-for='(item,index) in scheduleItem'
+					 :key='index'>
+						<view v-for="(sonItem,sonIndex) in item" :key='sonItem.showId' class="schedule-des" @click="clickBuy(sonItem)">
+							<view class="left-box">
+								<view class="item-box">
+									<text>{{sonItem.showTime.slice(11,16)}}</text>
+									<text class="bottom-text">{{sonItem.duration}}分钟</text>
+								</view>
+								<view class="type-box">
+									<text>{{sonItem.planType}}</text>
+									<text class="bottom-text">{{sonItem.hallName}}</text>
+								</view>
+							</view>
+							<view class="right-box">
+								<view class="price-box">
+									<text>{{(sonItem.netPrice/100*(sonItem.netPrice>3900?discountRule.upDiscountRate:discountRule.downDiscountRate)*filmDiscount).toFixed(2)}}元</text>
+									<text class="bottom-text old-price">{{sonItem.netPrice/100}}元</text>
+								</view>
+								<button v-if='discontinued(sonItem.stopSellTime)'>购 票</button>
+								<button v-else type="default" style="background: linear-gradient(90deg, #c0c0c0, #c0c0c0, #c0c0c0);">停 售</button>
+							</view>
+						</view>
+					</van-tab>
+				</van-tabs>
+			</view>
+		</loadSke>
+	</view>
+</template>
+
+<script>
+	export default {
+		data: () => ({
+			listLoading: true,
+			tabActive: 0,
+			current: 0,
+			cinemaId: null,
+			filmId: null,
+			cinemaName: '',
+			scheduleList: {},
+			scheduleListKey: null,
+			discountRule: {},
+			scheduleItem: {}
+		}),
+		computed: {
+			filmList() {
+				let list = {}
+				this.$store.state.cinema.filmList.map((val) => {
+					list[val.filmId] = val
+				})
+				return list;
+			},
+			filmDiscount() {
+				return this.$store.state.cinema.filmDiscount;
+			}
+		},
+		onLoad: function(option) {
+			this.cinemaId = option.cinemaId;
+			this.filmId = option.filmId;
+		},
+		mounted() {
+			this.init()
+		},
+		methods: {
+			clickBuy(item) {
+				let flag = this.discontinued(item.stopSellTime)
+				if (flag) {
+					this.$utils.goPage(`/pages/cinema/selectseat`, null, {
+						showItem: item
+					})
+				}
+				return
+			},
+			init() {
+				this.listLoading = true
+				this.$api.cinema.getScheduleList({
+					cinemaId: this.cinemaId
+				}).then(res => {
+					this.scheduleList = {}
+					this.discountRule = res.data.data.discountRule
+					this.$store.commit('SET_DISCOUNTRULE', res.data.data.discountRule)
+					this.cinemaName = res.data.data.list[0].cinemaName
+					res.data.data.list.sort((a, b) => {
+						return this.$utils.dayjs(a.showTime).isAfter(b.showTime) ? 1 : -1
+					})
+					res.data.data.list.forEach((val) => {
+						this.scheduleList[val.filmId] || (this.scheduleList[val.filmId] = {})
+						this.scheduleList[val.filmId][val.showDate] || (this.scheduleList[val.filmId][val.showDate] = [])
+						this.scheduleList[val.filmId][val.showDate].push(val)
+					})
+					this.scheduleListKey = Object.keys(this.scheduleList);
+					//定位影片位置
+					(this.filmId == 'undefined') && (this.filmId = this.scheduleListKey[0])
+					this.scheduleItem = this.scheduleList[this.filmId]
+					this.current = this.scheduleListKey.indexOf(this.filmId)
+					this.listLoading = false
+					setTimeout(() => {
+						this.selectComponent('#tabs').resize();
+					}, 500)
+				})
+			},
+			discontinued(date) {
+				let flag = (new Date(date.replace(/-/g, "/")).getTime() - new Date().getTime() - 1000 * 60 * 60) > 0
+				return flag
+			},
+			swiperChange(e) {
+				this.current = e.detail.current
+				this.filmId = this.scheduleListKey[this.current]
+				this.scheduleItem = {}
+				this.$nextTick(() => {
+					this.scheduleItem = this.scheduleList[this.filmId]
+					this.$nextTick(() => {
+						this.tabActive = 0
+						this.selectComponent('#tabs').resize();
+					})
+				})
+			},
+			tabsChange(e) {
+				this.tabActive = e.detail.index
+			}
+		}
+	}
+</script>
+
+<style lang="scss" scoped>
+	.button-box {
+		width: 100%;
+		height: 100rpx;
+		display: flex;
+		justify-content: space-around;
+		align-items: stretch;
+		background-color: #ffffff;
+
+		.problem-type {
+			display: flex;
+			justify-content: center;
+			align-items: center;
+		}
+
+		.active {
+			border-bottom: 2px solid red;
+		}
+	}
+
+	.des-box {
+		background-image: url(https://t1-1305573081.cos.ap-shanghai.myqcloud.com/wxapp/static/imgs/filmBg.png);
+		padding: 35rpx 30rpx;
+		box-sizing: border-box;
+		width: 100%;
+		height: 690rpx;
+
+		.address {
+			font-size: 30rpx;
+			font-weight: bold;
+			color: #FFFFFF;
+		}
+
+		.swiper-box {
+			margin: auto;
+			margin-top: 60rpx;
+			padding: 0 45rpx;
+			box-sizing: border-box;
+			width: 100%;
+			height: 270rpx;
+
+			.swiper-item {
+				display: flex;
+				justify-content: center;
+				align-items: center;
+			}
+
+			.image {
+				height: 86%;
+			}
+
+			.imgBig {
+				height: 100% !important;
+			}
+		}
+
+		.film-name {
+			margin-top: 53rpx;
+			text-align: center;
+			font-size: 30rpx;
+			font-weight: bold;
+			color: #FFFFFF;
+		}
+
+		.film-des {
+			margin-top: 19rpx;
+			text-align: center;
+			font-size: 22rpx;
+			font-weight: 400;
+			color: #FFFFFF;
+			width: 100%;
+			overflow: hidden;
+			white-space: nowrap;
+			text-overflow: ellipsis;
+		}
+	}
+
+	.schedule-box {
+		width: 100vw;
+		min-height: calc(100vh - 690rpx + 122rpx - 10px - env(safe-area-inset-bottom)/2);
+		padding-bottom: calc(10px + env(safe-area-inset-bottom)/2);
+		background-color: #FFFFFF;
+		border-radius: 50rpx 50rpx 0px 0px;
+		margin-top: -122rpx;
+		overflow: hidden;
+
+		.schedule-tab {
+			overflow-y: auto;
+		}
+
+		.schedule-des {
+			display: flex;
+			justify-content: space-between;
+			align-items: center;
+			padding: 0 30rpx;
+			margin-top: 50rpx;
+
+			.bottom-text {
+				font-size: 22rpx;
+				font-weight: 400;
+				color: #999999;
+				width: 100rpx;
+				text-align: center;
+				white-space: nowrap;
+				overflow: hidden;
+				text-overflow: ellipsis;
+			}
+
+			.left-box {
+				width: 50%;
+				display: flex;
+				justify-content: space-around;
+				align-items: stretch;
+
+				.item-box {
+					display: flex;
+					flex-direction: column;
+					justify-content: space-between;
+					align-items: center;
+
+					&:first-child {
+						font-size: 40rpx;
+						font-weight: 400;
+						color: #0F0404;
+					}
+				}
+
+				.type-box {
+					display: flex;
+					flex-direction: column;
+					justify-content: space-between;
+					align-items: center;
+
+					&:first-child {
+						font-size: 26rpx;
+						font-weight: 400;
+						color: #0F0404;
+					}
+
+					:last-child {
+						width: 220rpx !important;
+					}
+				}
+			}
+
+			.right-box {
+				width: 45%;
+				display: flex;
+				justify-content: space-around;
+				align-items: center;
+
+				.price-box {
+					display: flex;
+					flex-direction: column;
+					justify-content: space-between;
+					align-items: center;
+
+					&:first-child {
+						font-size: 36rpx;
+						font-weight: 400;
+						color: #E31919;
+					}
+
+					.old-price {
+						text-decoration: line-through;
+					}
+				}
+
+				button {
+					margin: 0;
+					width: 126rpx;
+					height: 60rpx;
+					background: linear-gradient(90deg, #E31818, #ED3E24, #ED4F24);
+					border-radius: 30rpx;
+					font-size: 26rpx;
+					font-weight: 400;
+					color: #FFFFFF;
+					white-space: nowrap;
+					display: flex;
+					justify-content: center;
+					align-items: center;
+				}
+			}
+		}
+	}
+</style>

+ 379 - 0
src/pages/cinema/selectseat.vue

@@ -0,0 +1,379 @@
+<template>
+	<page-meta>
+		<navigation-bar :title="showItem.filmName" background-color="#FFFFFF" front-color="#000000" />
+	</page-meta>
+	<view>
+		<view class="seatSelection-box">
+			<view class="top-box">
+				<view class="address">
+					{{showItem.cinemaName}}
+				</view>
+				<view class="logo-box">
+					<view class="item">
+						<view class="seat selectable"></view>可选
+					</view>
+					<view class="item">
+						<view class="seat selected"></view>已选
+					</view>
+					<view class="item">
+						<view class="seat notSelect"></view>已售
+					</view>
+				</view>
+			</view>
+			<movable-area scale-area class="movable-area">
+				<movable-view scale out-of-bounds direction='all' scale-max="3" @scale='scaleChange'>
+					<view class="movable-box">
+						<view class="screen-box">
+							<image class="screen" src="https://t1-1305573081.cos.ap-shanghai.myqcloud.com/wxapp/static/imgs/%E9%93%B6%E5%B9%95.png"
+							 mode="widthFix"></image>
+							<text class="screen-name">{{showItem.hallName}}</text>
+						</view>
+						<loadSke :loading='loading'>
+							<view class="seat-box" :style="{'--col':collong}">
+								<van-checkbox-group :value="seatResult" @change="groupOnChange" :max="max">
+									<view class="col" v-for="(rowitem,rowindex) in rowlong" :key='rowindex'>
+										<view v-for="(colitem,colindex) in collong" :key='colindex'>
+											<van-checkbox use-icon-slot v-if="seatSet(rowindex,colindex,seatList)==='N'" :name="JSON.stringify(seatList[rowindex+1][colindex+1])">
+												<view class="seat" :class="{selected:selected(rowindex,colindex,seatResult),loveSeatLeft:isLoveSeatLeft(seatList[rowindex+1][colindex+1]),loveSeatRight:isLoveSeatRight(seatList[rowindex+1][colindex+1])}"
+												 slot="icon"></view>
+											</van-checkbox>
+											<view v-else-if="seatSet(rowindex,colindex,seatList)==='LK'" class="seat notSelect"></view>
+											<view v-else class="seat noneSeat"></view>
+										</view>
+									</view>
+								</van-checkbox-group>
+							</view>
+						</loadSke>
+					</view>
+				</movable-view>
+			</movable-area>
+		</view>
+
+		<view class="bottom-box">
+			<view class="buy-des">
+				<view class="film-des">
+					{{showItem.showTime}}
+				</view>
+				<view class="item-box">
+					<view class="seat-item" v-for="(item,index) in seatResult" :key='index'>
+						<view class="seat-name">
+							{{JSON.parse(item).seatNo}}
+						</view>
+						<van-icon name="cross" @click='remove(item)' />
+					</view>
+				</view>
+			</view>
+			<view class="price-box">
+				<view class="left-box">
+					总共:{{seatResult.length}}张
+				</view>
+				<button v-if="seatResult.length>0" class="btn" type="default" @click="$utils.goPage(`/pages/cinema/placeorder`,null,{seatResult:seatResult,showItem:showItem})">下一步</button>
+				<button v-else class="btn" style="background: linear-gradient(90deg, #c0c0c0, #c0c0c0, #c0c0c0);" type="default">下一步</button>
+			</view>
+		</view>
+
+	</view>
+</template>
+
+<script>
+	export default {
+		data: () => ({
+			showItem: null,
+			seatList: null,
+			rowlong: 0,
+			collong: 0,
+			seatResult: [],
+			max: null,
+			loading: true
+		}),
+		onLoad: async function(option) {
+			let data = await this.goPageGetData()
+			this.showItem = data.showItem
+		},
+		mounted() {
+			this.init()
+		},
+		methods: {
+			scaleChange(e) {
+				console.log(e)
+			},
+			groupOnChange(e) {
+				let isIncrease = this.seatResult.length < e.detail.length
+				e.detail.forEach(val => {
+					let seatObj = JSON.parse(val)
+					if (seatObj.lovestatus == 1) {
+						let loveSeat = JSON.stringify(this.seatList[parseInt(seatObj.rowNo)][parseInt(seatObj.columnNo) + 1])
+						e.detail.includes(loveSeat) || (isIncrease ? e.detail.push(loveSeat) : e.detail.splice(e.detail.indexOf(val), 1))
+					}
+					if (seatObj.lovestatus == 2) {
+						let loveSeat = JSON.stringify(this.seatList[parseInt(seatObj.rowNo)][parseInt(seatObj.columnNo) - 1])
+						e.detail.includes(loveSeat) || (isIncrease ? e.detail.push(loveSeat) : e.detail.splice(e.detail.indexOf(val), 1))
+					}
+				})
+				this.seatResult = e.detail
+			},
+			remove(item) {
+				let seatObj = JSON.parse(item)
+				if (seatObj.lovestatus == 1) {
+					let loveSeat = JSON.stringify(this.seatList[parseInt(seatObj.rowNo)][parseInt(seatObj.columnNo) + 1])
+					this.seatResult.includes(loveSeat) && this.seatResult.splice(this.seatResult.indexOf(loveSeat), 1)
+				}
+				if (seatObj.lovestatus == 2) {
+					let loveSeat = JSON.stringify(this.seatList[parseInt(seatObj.rowNo)][parseInt(seatObj.columnNo) - 1])
+					this.seatResult.includes(loveSeat) && this.seatResult.splice(this.seatResult.indexOf(loveSeat), 1)
+				}
+				this.seatResult.splice(this.seatResult.indexOf(item), 1)
+			},
+			seatSet(row, col, list) {
+				if (!list) {
+					return false
+				} else if (list[row + 1]) {
+					if (list[row + 1][col + 1])
+						return list[row + 1][col + 1].status
+				}
+			},
+			isLoveSeatLeft(item) {
+				return item.lovestatus == 1
+			},
+			isLoveSeatRight(item) {
+				return item.lovestatus == 2
+			},
+			selected(row, col, seatResult) {
+				let flag = false
+				seatResult.forEach((val) => {
+					if (JSON.parse(val).columnNo == col + 1 && JSON.parse(val).rowNo == row + 1)
+						flag = true
+				})
+				return flag
+			},
+			async init() {
+				let seatRes = await this.$api.cinema.getSeat({
+					showId: this.showItem.showId
+				})
+				console.log(seatRes)
+				this.max = seatRes.data.data.seatData.restrictions
+				seatRes.data.data.seatData.seats.forEach((val) => {
+					this.seatList || (this.seatList = {})
+					this.seatList[val.rowNo] || (this.seatList[val.rowNo] = {})
+					// this.$set(this.seatList[val.rowNo], val.columnNo, val)
+					if (parseInt(val.rowNo) > this.rowlong) {
+						this.rowlong = parseInt(val.rowNo)
+					}
+					if (parseInt(val.columnNo) > this.collong) {
+						this.collong = parseInt(val.columnNo)
+					}
+					this.seatList[val.rowNo][val.columnNo] = val
+				})
+				this.$nextTick(() => {
+					this.loading = false
+				})
+				console.log(this.seatList)
+			}
+		}
+	}
+</script>
+
+<style lang="scss">
+	.movable-area {
+		width: 100vw;
+		min-height: 500rpx;
+	}
+
+	.movable-box {
+		width: 100vw;
+		min-height: 500rpx;
+	}
+
+	.seatSelection-box {
+		box-sizing: border-box;
+
+		.top-box {
+			padding: 30rpx;
+			box-sizing: border-box;
+
+			.address {
+				font-size: 30rpx;
+				font-weight: 400;
+				color: #0F0404;
+			}
+
+			.logo-box {
+				margin-top: 43rpx;
+				width: 50%;
+				display: flex;
+				justify-content: space-between;
+				align-items: center;
+
+				.item {
+					display: flex;
+					justify-content: center;
+					align-items: center;
+				}
+
+
+			}
+		}
+
+
+		.seat {
+			width: 26rpx;
+			height: 26rpx;
+			border: 1rpx solid #D9D9D9;
+			border-radius: 4rpx;
+			background: #FFFFFF;
+		}
+
+		.noneSeat {
+			opacity: 0;
+		}
+
+		.notSelect {
+			opacity: 1;
+			background: #FB3D46;
+		}
+
+		.selected {
+			opacity: 1;
+			background: #47CB79;
+		}
+
+		.loveSeatLeft {
+			position: relative;
+			overflow: initial;
+
+			&::after {
+				content: '';
+				position: absolute;
+				right: 0;
+				transform: translate(50%, -50%);
+				top: 50%;
+				width: 50%;
+				height: 80%;
+				background-color: inherit;
+				z-index: 10;
+			}
+		}
+
+		.loveSeatRight {
+			position: relative;
+			overflow: initial;
+
+			&::after {
+				content: '';
+				position: absolute;
+				left: 0;
+				transform: translate(-50%, -50%);
+				top: 50%;
+				width: 50%;
+				height: 80%;
+				background-color: inherit;
+				z-index: 10;
+			}
+		}
+
+
+
+		.screen-box {
+			position: relative;
+			margin-top: 47rpx;
+
+			.screen {
+				width: 100%;
+			}
+
+			.screen-name {
+				position: absolute;
+				left: 50%;
+				top: 30rpx;
+				transform: translateX(-50%);
+				white-space: nowrap;
+				font-size: 22rpx;
+				font-weight: 400;
+				color: #999999;
+			}
+		}
+
+		.seat-box {
+			margin-top: 50rpx;
+			width: calc(var(--col) * 30rpx);
+			margin: auto;
+
+			.col {
+				display: flex;
+				justify-content: space-around;
+				align-items: center;
+				margin-top: 15rpx;
+			}
+		}
+	}
+
+	.bottom-box {
+		position: fixed;
+		width: 100vw;
+		bottom: 0;
+
+		.buy-des {
+			background-color: #FFFFFF;
+			padding: 30rpx;
+
+			.film-des {
+				font-size: 26rpx;
+				font-weight: 400;
+				color: #666666;
+			}
+
+			.item-box {
+				display: flex;
+				justify-content: flex-start;
+				flex-wrap: wrap;
+
+				.seat-item {
+					display: flex;
+					justify-content: space-between;
+					align-items: center;
+					width: 200rpx;
+					background: #E6E6E6;
+					border-radius: 10rpx;
+					margin: 20rpx 20rpx 0rpx 0rpx;
+					padding: 20rpx;
+					box-sizing: border-box;
+
+					.seat-name {
+						font-size: 24rpx;
+					}
+				}
+			}
+		}
+
+		.price-box {
+			display: flex;
+			justify-content: space-between;
+			align-items: center;
+			background-color: #FFFFFF;
+			padding: 15rpx 30rpx;
+			padding-bottom: calc(15rpx + 10px + env(safe-area-inset-bottom)/2);
+			margin-top: 20rpx;
+
+			.left-box {
+				font-size: 26rpx;
+				font-weight: 400;
+				color: #0F0404;
+			}
+
+			.btn {
+				margin: 0;
+				width: 200rpx;
+				height: 80rpx;
+				background: linear-gradient(90deg, #E31818, #ED3E24, #ED4F24);
+				border-radius: 40rpx;
+				font-size: 30rpx;
+				font-weight: 400;
+				color: #FFFFFF;
+				display: flex;
+				justify-content: center;
+				align-items: center;
+				white-space: nowrap;
+			}
+		}
+	}
+</style>

+ 196 - 0
src/pages/fulu/index.vue

@@ -0,0 +1,196 @@
+<template>
+	<view class="page">
+		<loadSke :loading="loading" :list="typeList">
+			<view class="tabs">
+				<view class="tab" :class="{selected:index==active}" @click="tabClick(index)"
+					v-for="(item,index) in typeList" :key='index'>
+					{{item.type_name}}
+				</view>
+			</view>
+			<scroll-view class='scroll-view' :scroll-into-view="scrollId" :scroll-y='true' :scroll-with-animation='true' @scroll='scrollChange'>
+				<view class="box" v-for="(item,index) in typeList" :key='index' :id="'scroll'+index">
+					<view class="type_name">
+						<m-icon type="name_left" color="red" />
+						<text>{{item.type_name}}</text>
+						<m-icon type="name_right" color="red" />
+					</view>
+					<view class="type-box">
+						<view class="type" v-for="(itemSon,indexSon) in item.list" :key='indexSon'
+							@click="$utils.goPage('/pages/fulu/placeorder',null,{product_ids:itemSon.product_ids,icon:itemSon.icon,remark:itemSon.remark})">
+							<view class="top-des">
+								<image class="icon" :src="itemSon.icon" mode="scaleToFill"></image>
+								<view class="right">
+									<text class="name">{{itemSon.name}}</text>
+									<text class="introduction">{{itemSon.introduction}}</text>
+								</view>
+							</view>
+							<text class="btn">立即充值</text>
+						</view>
+					</view>
+				</view>
+			</scroll-view>
+		</loadSke>
+	</view>
+
+</template>
+
+<script>
+	export default {
+		data: () => ({
+			active: 0,
+			typeList: [],
+			loading: true,
+			scrollId: 'scroll0'
+		}),
+		async mounted() {
+			this.loading = true
+			let res = await this.$api.fulu.goods.getTypeList()
+			console.log(res)
+			this.typeList = res.data
+			this.$nextTick(() => {
+				this.loading = false
+			})
+		},
+		methods: {
+			tabClick(index) {
+				this.active = index
+				this.scrollId = 'scroll' + index
+			},
+			scrollChange(e){
+				console.log(e)
+			}
+		}
+	}
+</script>
+
+<style lang="scss" scoped>
+	.page {
+		.tabs {
+			display: flex;
+			justify-content: space-around;
+			align-items: center;
+			background-color: #FFFFFF;
+			padding: 0 20rpx;
+			position: sticky;
+			top: 0;
+			left: 0;
+			z-index: 1;
+			overflow-x: auto;
+
+			.tab {
+				text-align: center;
+				flex-shrink: 0;
+				width: 250rpx;
+				padding: 20rpx 0;
+				height: 80rpx;
+				box-sizing: border-box;
+			}
+
+			.selected {
+				position: relative;
+
+				&::after {
+					content: '';
+					width: 80rpx;
+					height: 6rpx;
+					background-color: red;
+					position: absolute;
+					bottom: 0;
+					left: 50%;
+					transform: translateX(-50%);
+				}
+			}
+		}
+		
+		.scroll-view{
+			height: calc(100vh - 100rpx);
+		}
+
+		.box {
+			margin-top: 20rpx;
+			background-color: #FFFFFF;
+
+			&:nth-last-of-type(1) {
+				height: calc(100vh - 100rpx);
+			}
+
+			.type_name {
+				display: flex;
+				justify-content: center;
+				align-items: center;
+				padding: 20rpx;
+			}
+
+			.type-box {
+				display: flex;
+				justify-content: flex-start;
+				align-items: center;
+				flex-wrap: wrap;
+				padding-left: 20rpx;
+
+				.type {
+					width: 345rpx;
+					background: linear-gradient(0deg, #FDDEAF, #FDF3D8);
+					margin-right: auto;
+					margin-bottom: 20rpx;
+					border-radius: 20rpx;
+					padding: 30rpx;
+					box-sizing: border-box;
+					display: flex;
+					flex-direction: column;
+					justify-content: center;
+					align-items: center;
+
+					.top-des {
+						width: 100%;
+						display: flex;
+						justify-content: flex-start;
+						align-items: center;
+
+						.icon {
+							width: 91rpx;
+							height: 75rpx;
+							margin-right: 20rpx;
+						}
+
+						.right {
+							display: flex;
+							flex-direction: column;
+							align-items: center;
+
+							.name {
+								color: #744520;
+								font-size: 30rpx;
+								font-weight: 500;
+							}
+
+							.introduction {
+								margin-top: 15rpx;
+								font-weight: 400;
+								color: #744520;
+								font-size: 26rpx;
+								white-space: nowrap;
+							}
+						}
+					}
+
+					.btn {
+						margin-top: 30rpx;
+						width: 166rpx;
+						height: 60rpx;
+						background: linear-gradient(90deg, #E31818, #ED3E24, #ED4F24);
+						border-radius: 30px;
+						padding: 18rpx;
+						box-sizing: border-box;
+						font-size: 26rpx;
+						font-weight: 400;
+						color: #FFFFFF;
+						display: flex;
+						justify-content: center;
+						align-items: center;
+					}
+				}
+			}
+		}
+	}
+</style>

+ 307 - 0
src/pages/fulu/orderdes.vue

@@ -0,0 +1,307 @@
+<template>
+	<view class="page">
+		<loadSke :loading='loading'>
+			<view class="remind-top">首页->我的->我的订单</view>
+			<view class="des-box">
+				<view>
+					<view v-if="true" class="code-box">
+						<image class="qrcode" :src="orderDes.goodsPictureUrl" mode="widthFix"></image>
+						<view class="code">
+							<text>充值用户</text>
+							<text>{{orderDes.charge_account}}</text>
+						</view>
+					</view>
+				</view>
+				<view class="order-num">
+					<text>订单号:{{outTradeNo}}</text>
+					<text>{{orderDes.orderStatusDesc}}</text>
+					<text v-if="orderDes.orderStatus==3">{{orderDes.recharge_description}}</text>
+				</view>
+				<view class="des">
+					<text class="film-name">充值商品</text>
+					<view class="film-time">
+						<text>购买时间</text>
+						<text>{{orderDes.create_time}}</text>
+					</view>
+					<view class="film-address">
+						<text>购买商品</text>
+						<text>{{orderDes.product_name}}</text>
+					</view>
+					<view class="film-video">
+						<text>购买数量</text>
+						<text>{{orderDes.buy_num}}</text>
+					</view>
+					<view class="film-seat">
+						<text>购买价格</text>
+						<text>{{orderDes.total}}</text>
+					</view>
+				</view>
+			</view>
+		</loadSke>
+	</view>
+</template>
+
+<script>
+	export default {
+		data: () => ({
+			orderDes: {},
+			loading: true,
+			outTradeNo: null,
+			pollingTiemId: null
+		}),
+		onLoad: function(option) {
+			this.outTradeNo = option.outTradeNo
+		},
+		mounted() {
+			this.init()
+		},
+		methods: {
+			async init() {
+				let orderRes = await this.$api.order.getWxOrder(this.outTradeNo)
+				this.orderDes = orderRes.data
+				// 直接查询的接口
+				// await this.$api.fulu.orderInfoGet({
+				// 	customer_order_no: this.outTradeNo
+				// })
+				this.loading = false
+				if (this.orderDes.orderStatus == 1) {
+					this.polling()
+				}
+			},
+			polling() {
+				this.pollingTiemId = setInterval(async () => {
+					let orderRes = await this.$api.order.getWxOrder(this.outTradeNo)
+					this.orderDes = orderRes.data
+					if (this.orderDes.orderStatus != 1) {
+						clearInterval(this.pollingTiemId)
+					}
+				}, 3000)
+			}
+		},
+		beforeDestroy() {
+			clearInterval(this.pollingTiemId)
+		}
+	}
+</script>
+
+<style lang="scss">
+	.page {
+		padding-bottom: 20rpx;
+	}
+
+	.remind {
+		padding-top: 36rpx;
+		font-size: 26rpx;
+		font-weight: 400;
+		color: #0F0404;
+		text-align: center;
+	}
+
+	.remind-top {
+		margin-top: 36rpx;
+		font-size: 26rpx;
+		font-weight: 400;
+		color: #ff0000;
+		text-align: center;
+	}
+
+	.des-box {
+		width: 564rpx;
+		background: #FFFFFF;
+		border-radius: 20rpx;
+		margin: auto;
+		margin-top: 30rpx;
+
+		.code-box {
+			display: flex;
+			flex-direction: column;
+			align-items: center;
+			padding-bottom: 38rpx;
+
+			.code {
+				margin-top: 43rpx;
+
+				text {
+					font-size: 26rpx;
+					font-weight: 400;
+					color: #666666;
+					margin-right: 20rpx;
+
+					&:nth-child(2) {
+						color: #0F0404;
+					}
+				}
+			}
+
+			.qrcode {
+				margin-top: 43rpx;
+				width: 360rpx;
+				height: 360rpx;
+			}
+
+			.qrcode-loading {
+				margin-top: 43rpx;
+				width: 100%;
+			}
+		}
+
+		.order-num {
+			display: flex;
+			flex-direction: column;
+			justify-content: space-between;
+			align-items: center;
+			padding: 34rpx 31rpx;
+			border-top: 1rpx dashed #D9D9D9;
+			border-bottom: 1rpx dashed #D9D9D9;
+			position: relative;
+
+			&::after {
+				content: '';
+				width: 24rpx;
+				height: 24rpx;
+				border-radius: 50%;
+				background-color: #F1F1F1;
+				position: absolute;
+				top: 0;
+				left: 0;
+				transform: translate(-50%, -50%);
+			}
+
+			&::before {
+				content: '';
+				width: 24rpx;
+				height: 24rpx;
+				border-radius: 50%;
+				background-color: #F1F1F1;
+				position: absolute;
+				top: 0;
+				right: 0;
+				transform: translate(50%, -50%);
+			}
+
+			text {
+				&:nth-child(1) {
+					margin-top: 60rpx;
+					word-break: break-all;
+					font-size: 22rpx;
+					font-weight: 400;
+					color: #666666;
+				}
+
+				&:nth-child(2) {
+					margin-top: 10rpx;
+					padding: 10rpx;
+					display: flex;
+					justify-content: center;
+					align-items: center;
+					background: #FFE5E5;
+					border-radius: 20rpx;
+					border-top-left-radius: 0;
+					border-bottom-left-radius: 0;
+					font-size: 20rpx;
+					font-weight: 400;
+					color: #E31818;
+					position: absolute;
+					left: 0;
+					top: 20rpx;
+				}
+
+				&:nth-child(3) {
+					margin-top: 10rpx;
+					padding: 10rpx;
+					display: flex;
+					justify-content: center;
+					align-items: center;
+					font-size: 20rpx;
+					font-weight: 400;
+					color: #E31818;
+				}
+			}
+		}
+
+		.des {
+			padding: 45rpx 30rpx;
+			border-bottom: 1rpx dashed #D9D9D9;
+			display: flex;
+			flex-direction: column;
+
+			.film-name {
+				font-size: 30rpx;
+				font-weight: 400;
+				color: #0F0404;
+			}
+
+			text {
+				font-size: 26rpx;
+				font-weight: 400;
+				color: #666666;
+				margin-right: 20rpx;
+				white-space: nowrap;
+			}
+
+			.film-time {
+				text:nth-child(2) {
+					color: #999999;
+				}
+			}
+
+			.film-address {
+				display: flex;
+				justify-content: flex-start;
+				align-items: stretch;
+
+				text:nth-child(2) {
+					color: #999999;
+					white-space: pre-wrap;
+				}
+			}
+
+			.film-video {
+				display: flex;
+				justify-content: flex-start;
+				align-items: stretch;
+
+				text:nth-child(2) {
+					color: #999999;
+					white-space: pre-wrap;
+				}
+			}
+
+			.film-seat {
+				display: flex;
+				justify-content: flex-start;
+				align-items: stretch;
+				margin-top: 10rpx;
+
+				.seat-box {
+					display: flex;
+					flex-wrap: wrap;
+
+					text {
+						height: 40rpx;
+						padding: 4rpx 15rpx;
+						margin-bottom: 10rpx;
+						background: #EBEBEB;
+						border-radius: 4rpx;
+						color: #999999;
+					}
+				}
+			}
+		}
+
+		.price {
+			padding: 40rpx 30rpx;
+
+			text {
+				font-size: 26rpx;
+				font-weight: 400;
+				color: #666666;
+				margin-right: 20rpx;
+
+				&:nth-child(2) {
+					color: #E31818;
+				}
+			}
+		}
+	}
+</style>

+ 277 - 0
src/pages/fulu/placeorder.vue

@@ -0,0 +1,277 @@
+<template>
+	<loading v-if="loading"></loading>
+	<view v-else>
+		<view class="top">
+			<image class="left-icon" :src="icon" mode="scaleToFill"></image>
+			<text class="tit">{{goodsInfoList[current].product_name.split('-')[1]}}</text>
+		</view>
+		<view class="user-data">
+			<van-cell-group>
+				<van-field v-for="(item,index) in goodsTemplate.ElementInfo.Inputs" :key='item.SortId'
+					:value="charge_account" @change='fieldChange' required clearable :label="item.Name"
+					icon="question-o" :placeholder="'请输入'+item.Name" @click-icon="onClickIcon('请输入'+item.Name)" />
+				<van-cell :title="goodsTemplate.ElementInfo.ChargeNum.Name">
+					<van-stepper slot="right-icon" :value="buy_num" integer @change="stepperChange" :min="1" />
+				</van-cell>
+			</van-cell-group>
+		</view>
+
+		<view class="prompt">
+			<text class="top-tit">购买须知</text>
+			<view class="dex-box">
+				<text v-for="(item,index) in remark" :key='index'>{{index+1}}、{{item}}</text>
+			</view>
+		</view>
+
+		<view class="commodity-selection">
+			<text class="top-tit">充值类型</text>
+			<view class="selection-box">
+				<view class="commodity" :class="{selected:current==index}" @click="current=index"
+					v-for="(item,index) in goodsInfoList" :key='item.product_id'>
+					<text>{{item.product_name.split('-')[1]}}</text>
+					<text>{{item.product_name.split('-')[2]}}</text>
+					<text>¥{{item.purchase_price*fulu_vip_discount}}</text>
+					<text>¥{{item.face_value}}</text>
+					<m-icon v-if="current==index" class="xuanzhong-icon" type="xuanzhong" color="#47CB79"></m-icon>
+				</view>
+			</view>
+		</view>
+
+		<view class="buy-btn-box"></view>
+		<view class="buy-btn" @click="buy">
+			立即充值
+		</view>
+	</view>
+</template>
+
+<script>
+	export default {
+		data: () => ({
+			current: 0,
+			goodsInfoList: [],
+			goodsTemplate: {},
+			product_ids: [],
+			icon: null,
+			remark: [],
+			loading: true,
+			buy_num: 1,
+			charge_account: null,
+			fulu_vip_discount: 1,
+		}),
+		onLoad: async function(option) {
+			let data = await this.goPageGetData()
+			this.product_ids = data.product_ids
+			this.icon = data.icon
+			this.remark = data.remark
+		},
+		async mounted() {
+			let keywordRes = await this.$api.fulu.getPriceKeyword()
+			if(keywordRes.code == 200){
+				this.fulu_vip_discount = keywordRes.data
+			}
+			this.loading = true
+			let arr = []
+			this.product_ids.forEach(id => {
+				arr.push(this.$api.fulu.goods.infoGet({
+					product_id: id
+				}))
+			})
+			await Promise.all(arr).then(res => {
+				res.forEach(resObj => {
+					if (resObj.code == 200)
+						resObj.data.code == 0 && this.goodsInfoList.push(JSON.parse(resObj.data
+							.result))
+				})
+			})
+			let tempRes = await this.$api.fulu.goods.templateGet({
+				template_id: this.goodsInfoList[this.current].template_id
+			})
+			this.goodsTemplate = JSON.parse(tempRes.data.result)
+			this.$nextTick(() => {
+				this.loading = false
+			})
+		},
+		methods: {
+			async buy() {
+				this.$utils.wxUtils.subscribeToNews().then(async res => {
+					let orderRes = await this.$api.fulu.prepareOrder({
+						buy_num: this.buy_num,
+						charge_account: this.charge_account,
+						goodsPictureUrl: this.icon,
+						product_id: this.goodsInfoList[this.current].product_id
+					})
+					let payRes = await wx.requestPayment(orderRes.data)
+					if (payRes.errMsg == 'requestPayment:ok') {
+						this.$utils.goPage(
+							`/pages/fulu/orderdes?outTradeNo=${orderRes.data.outTradeNo}`,
+							'reLaunch')
+					}
+				})
+			},
+			stepperChange(e) {
+				this.buy_num = e.detail
+			},
+			fieldChange(e) {
+				this.charge_account = e.detail
+			},
+			onClickIcon(msg) {
+				wx.showToast({
+					title: msg,
+					icon: 'none'
+				})
+			}
+		}
+	}
+</script>
+
+<style lang="scss" scoped>
+	.top {
+		margin-top: 20rpx;
+		display: flex;
+		justify-content: center;
+		align-items: center;
+		background-color: #FFFFFF;
+		padding: 23rpx;
+
+		.left-icon {
+			width: 87rpx;
+			height: 79rpx;
+			margin-right: 22rpx;
+		}
+
+		.tit {
+			white-space: nowrap;
+			font-size: 30rpx;
+			font-weight: 400;
+			color: #0F0404;
+		}
+	}
+
+	.user-data {
+		background-color: #FFFFFF;
+		display: flex;
+		flex-direction: column;
+	}
+
+	.commodity-selection {
+		margin-top: 20rpx;
+		background-color: #FFFFFF;
+		display: flex;
+		flex-direction: column;
+
+		.top-tit {
+			font-size: 26rpx;
+			font-weight: 400;
+			color: #666666;
+			line-height: 39rpx;
+			border-bottom: 1rpx solid #e8e8e8;
+			padding: 28rpx;
+		}
+
+		.selection-box {
+			margin-top: 30rpx;
+			display: flex;
+			flex-wrap: wrap;
+			justify-content: flex-start;
+			padding-left: 15rpx;
+
+			.selected {
+				border: 1rpx solid #ECBF7A !important;
+				background-color: #FDF3D7;
+			}
+
+			.commodity {
+				margin-bottom: 15rpx;
+				margin-right: 15rpx;
+				width: 230rpx;
+				display: flex;
+				flex-direction: column;
+				align-items: center;
+				border: 1rpx solid #E8E8E8;
+				box-sizing: border-box;
+				padding: 30rpx 20rpx;
+				border-radius: 6rpx;
+				position: relative;
+
+				.xuanzhong-icon {
+					position: absolute;
+					right: 0;
+					bottom: 0;
+				}
+
+				text {
+					&:nth-child(1) {
+						color: #999999;
+						font-size: 26rpx;
+					}
+
+					&:nth-child(2) {
+						color: #999999;
+						font-size: 26rpx;
+					}
+
+					&:nth-child(3) {
+						color: #E31818;
+						font-size: 40rpx;
+					}
+
+					&:nth-child(4) {
+						color: #999999;
+						font-size: 26rpx;
+						text-decoration: line-through;
+					}
+				}
+			}
+		}
+	}
+
+	.prompt {
+		margin-top: 20rpx;
+		background-color: #FFFFFF;
+		display: flex;
+		flex-direction: column;
+
+		.top-tit {
+			font-size: 26rpx;
+			font-weight: 400;
+			color: #666666;
+			line-height: 39rpx;
+			border-bottom: 1rpx solid #e8e8e8;
+			padding: 28rpx;
+		}
+
+		.dex-box {
+			padding: 28rpx;
+			display: flex;
+			flex-direction: column;
+			font-size: 26rpx;
+			font-weight: 400;
+			color: #666666;
+			line-height: 39rpx;
+		}
+	}
+
+	.buy-btn-box {
+		margin-top: 30rpx;
+		width: 600rpx;
+		height: 80rpx;
+		opacity: 0;
+	}
+
+	.buy-btn {
+		position: fixed;
+		bottom: 30rpx;
+		left: 50%;
+		transform: translateX(-50%);
+		width: 600rpx;
+		height: 80rpx;
+		background: linear-gradient(90deg, #E31818, #ED3E24, #ED4F24);
+		border-radius: 40rpx;
+		font-size: 30rpx;
+		font-weight: 400;
+		color: #FFFFFF;
+		display: flex;
+		justify-content: center;
+		align-items: center;
+	}
+</style>

+ 101 - 0
src/pages/home/index.vue

@@ -0,0 +1,101 @@
+<template>
+	<view class="home">
+		<view class="top-list">
+			<image class="background-img" style="width: 100vw;"
+				src="https://t1-1305573081.cos.ap-shanghai.myqcloud.com/wxapp/static/imgs/%E9%A1%B6%E9%83%A8%E8%83%8C%E6%99%AF3.png"
+				mode="widthFix"></image>
+			<topbar class="topbar-slot">
+				<view>
+					<text style="color: #FFFFFF;">极速生活圈</text>
+				</view>
+			</topbar>
+
+			<loadSke :loading='topLoading' :list='bannerList'>
+				<m-banner :bannerList="bannerList"></m-banner>
+				<m-home-coupon :couponList="couponList"></m-home-coupon>
+				<m-home-menu :menuList="menuList"></m-home-menu>
+			</loadSke>
+		</view>
+		
+		<m-home-bottomad :bottomAD="bottomAD"></m-home-bottomad>
+
+		<m-home-pdd ref="pdd"></m-home-pdd>
+	</view>
+</template>
+
+<script>
+	import utils from '@/utils'
+	export default {
+		data: () => ({
+			bannerList: [],
+			couponList: [],
+			menuList: [],
+			bottomAD: [],
+			topLoading: true,
+		}),
+		mounted() {
+			this.init()
+		},
+		onReachBottom(){
+			this.onBottom()
+		},
+		methods: {
+			onBottom() {
+				this.$refs.pdd.onBottom()
+			},
+			init() {
+				this.$api.home.getHomePageDataList(['bottomAD','menu','coupon','carouselChart']).then(res => {
+					this.bannerList = res.data.carouselChart
+					this.couponList = res.data.coupon.slice(0, 4)
+					this.menuList = res.data.menu
+					this.bottomAD = res.data.bottomAD
+					this.$nextTick(() => {
+						this.topLoading = false
+					})
+				})
+			}
+		}
+	}
+</script>
+
+<style scoped lang="scss">
+	.home {
+		height: 100%;
+	}
+
+	.top-list {
+		padding: 30rpx;
+		padding-top: 0;
+		box-sizing: border-box;
+		width: 100%;
+		background-color: #FFFFFF;
+		position: relative;
+
+		.topbar-slot {
+			z-index: 1;
+			align-self: center;
+			display: flex;
+			justify-content: center;
+		}
+
+		.background-img {
+			position: absolute;
+			top: 0;
+			left: 0;
+		}
+
+		.swiper-box {
+			width: 690rpx;
+			height: 342rpx;
+			overflow: hidden;
+
+			.image {
+				width: 100%;
+				height: 100%;
+				border-radius: 10px;
+			}
+		}
+
+
+	}
+</style>

+ 439 - 0
src/pages/index/components/applist.vue

@@ -0,0 +1,439 @@
+<template>
+	<scroll-view scroll-y class="content" @scrolltolower='onBottom'>
+		<topbar />
+		<view class="back">
+			<view class="sticky">
+				<van-search class='top-search' shape="round" background="#fff" placeholder="请输入搜索关键词" @search="onSearch" @change='onSearchChange' />
+				<view class="grid">
+					<view class="grid-item" :class="{border:listType==0}" @click="listType=0">
+						<van-icon name="/static/imgs/jx.png" size="30px" />
+						<text class="text">精选</text>
+					</view>
+					<view class="grid-item" :class="{border:listType==item.id}" @click="listType=item.id" v-for="(item,index) in typeList"
+					 :key='index'>
+						<van-icon :name="item.fileUrl || '/static/imgs/wxtb.png'" size="30px" />
+						<text class="text">{{item.productName}}</text>
+					</view>
+					<view class="grid-item" :class="{border:listType==5}" @click="moreShow=!moreShow,typeMore()">
+						<van-icon v-if='moreShow' name="/static/imgs/sq.png" size="30px" />
+						<van-icon v-else name="/static/imgs/gd.png" size="30px" />
+						<text class="text">{{moreShow?'收起':'更多'}}</text>
+					</view>
+				</view>
+			</view>
+
+			<loadSke :loading='loading' :list='applist'>
+				<view class='list-item' v-for="(item, index) in applist" :key="index" @click="$utils.clickJumpType(item)">
+					<image class="avatar" mode="aspectFit" :src="item.appletLogoFileUrl || '/static/imgs/shmr.png'" />
+					<view class="top">
+						<van-icon class="icon" v-if="item.collectionStatus=='0'" @tap.stop='addSc(index)' name="star-o" color='#999999' />
+						<van-icon class="icon" v-else @tap.stop='delSc(index)' name="star" color='#dfdf00' />
+						<van-icon class="icon" name="ellipsis" size='20' color='#999999' @tap.stop='showShare=true' />
+					</view>
+					<view class="item-right">
+						<view class="bottom">
+							<text class="title">{{item.corporateName}}</text>
+							<text class="type">{{itemType(item)}}</text>
+							<view class="right" v-if="false">
+								<view class="flex">
+									<van-icon class="icon" name="/static/imgs/评论.png" size='15' />
+									<text>54</text>
+								</view>
+								<view class="flex">
+									<van-icon class="icon" name="/static/imgs/好评率.png" size='15' />
+									<text>99%</text>
+								</view>
+							</view>
+						</view>
+						<view class="center" v-if="item.appletIntroduce">
+							<text class="details">{{item.appletIntroduce || `Appid: ${item.appletAddress}`}}</text>
+						</view>
+
+					</view>
+				</view>
+				<loading v-if="bottomLoading" class="bottom-loading" />
+				<view class="ad-box list-item">
+					<ad unit-id="adunit-d8c1548cc9663765"></ad>
+				</view>
+				<view class="ad-box list-item">
+					<ad-custom unit-id="adunit-66504f2e91ee7be4"></ad-custom>
+				</view>
+			</loadSke>
+
+
+
+		</view>
+
+
+
+		<van-share-sheet :show="showShare" :options="options" @select="onSelect" @close='shareClose' />
+	</scroll-view>
+
+</template>
+
+<script>
+	import {
+		debounce
+	} from '@/utils'
+	export default {
+		data() {
+			return {
+				comname: 'xueche',
+				active: 0,
+				tabActive: 0,
+				info: [{
+					"id": 12,
+					"pictureName": "山泉心品",
+					"fileId": "77",
+					"fileUrl": "http://image.jppt.com.cn/zzjs/2021-04-09/others/1617954376809.jpg",
+					"jumpUrl": "{\"appId\":\"wxb47185e82704dda8\"}",
+					"jumpUrlType": "goMiniApp",
+					"status": 0
+				}],
+				current: 0,
+				mode: 'round',
+				applist: [],
+				typeList: {},
+				listType: 0,
+				loading: true,
+				showShare: false,
+				moreShow: false,
+				options: [{
+					name: '微信',
+					icon: 'wechat',
+					openType: 'share'
+				}],
+				pageNum: 1,
+				pageSize: 10,
+				total: 1,
+				customerName: '',
+				bottomLoading: false
+			}
+		},
+		mounted() {
+			this.initAppList()
+		},
+		watch: {
+			listType(val) {
+				this.customerName = ''
+				this.pageNum = 1
+				this.loading = true
+				this.$api.applist.getTypeAppList(val, {
+					pageNum: this.pageNum,
+					pageSize: this.pageSize
+				}).then(res => {
+					this.applist = res.rows
+					this.total = res.total
+					this.$nextTick(() => {
+						this.loading = false
+					})
+				})
+			}
+		},
+		methods: {
+			itemType(item) {
+				if (item.jumpUrlType == 'goMiniApp') {
+					return '小程序'
+				}
+				if (item.jumpUrlType == 'goPage') {
+					return '子页面'
+				}
+				if (item.jumpUrlType == 'goWebView') {
+					return 'WEB'
+				}
+			},
+			onSearchChange(e) {
+				this.customerName = e.detail
+			},
+			onSearch(e) {
+				this.pageNum = 1
+				this.loading = true
+				this.$api.applist.getTypeAppList(this.listType, {
+					pageNum: this.pageNum,
+					pageSize: this.pageSize,
+					customerName: e.detail
+				}).then(res => {
+					this.applist = res.rows
+					this.total = res.total
+					this.$nextTick(() => {
+						this.loading = false
+					})
+				})
+			},
+			initAppList() {
+				this.$api.applist.typeList({
+					pid: 0
+				}).then(res => {
+					this.typeList = res.rows.slice(0, 8)
+				})
+				this.$api.applist.getTypeAppList(0, {
+					pageNum: 1,
+					pageSize: 10
+				}).then(res => {
+					this.applist = res.rows
+					this.total = res.total
+					this.$nextTick(() => {
+						this.loading = false
+					})
+				})
+			},
+			onBottom() {
+				if(this.bottomLoading) return
+				if (this.total - this.pageNum * this.pageSize <= 0) {
+					return
+				}
+				this.bottomLoading=true
+				this.pageNum++
+				this.$api.applist.getTypeAppList(this.listType, {
+					pageNum: this.pageNum,
+					pageSize: this.pageSize,
+					customerName: this.customerName
+				}).then(res => {
+					this.applist = this.applist.concat(res.rows)
+					this.$nextTick(()=>{
+						this.bottomLoading=false
+					})
+				})
+			},
+			typeMore() {
+				if (this.moreShow) {
+					typeList({
+						pid: 0
+					}).then(res => {
+						this.typeList = res.rows
+					})
+				} else {
+					this.typeList = this.typeList.slice(0, 8)
+				}
+			},
+			addSc(index) {
+				this.$api.applist.addFavorites(this.applist[index].id).then(res => {
+					if (res.code == 200) {
+						this.$set(this.applist[index], 'collectionStatus', '1')
+						this.$utils.Toast('收藏成功!');
+					}
+				})
+			},
+			delSc(index) {
+				this.$api.applist.delFavorites(this.applist[index].id).then(res => {
+					if (res.code == 200) {
+						this.$set(this.applist[index], 'collectionStatus', '0')
+						this.$utils.Toast('取消收藏成功!');
+					}
+				})
+			},
+			shareClose() {
+				this.showShare = false;
+			},
+			onSelect(event) {
+				this.$utils.Toast(event.detail.name);
+				this.onClose();
+			},
+			getAppList() {
+				this.$api.applist.featuredAppList({
+					pageNum: 1,
+					pageSize: 10
+				}).then(res => {
+					console.log(res)
+					this.applist = res.rows
+					this.$nextTick(() => {
+						this.loading = false
+					})
+				})
+			}
+		}
+	}
+</script>
+
+<style lang="scss" scoped>
+	.bottom-loading {
+		text-align: center;
+		padding: 10rpx;
+	}
+
+	.ad-box {
+		margin: 40rpx;
+		box-sizing: border-box;
+		display: flex;
+		justify-content: center !important;
+		align-items: center;
+	}
+
+	.content {
+		padding-bottom: 1rpx;
+		height: 100%;
+	}
+
+	.swiper-box {
+		width: 100vw;
+		height: 56.25vw;
+
+		.image {
+			width: 100%;
+			height: 100%;
+		}
+	}
+
+	.sticky {
+		position: sticky;
+		top: 0rpx;
+		left: 0;
+		background-color: #fff;
+		z-index: 9;
+		margin-bottom: 20rpx;
+
+		.grid {
+			display: flex;
+			flex-wrap: wrap;
+			justify-content: flex-start;
+			overflow: auto;
+
+			.grid-item {
+				flex-shrink: 0;
+				width: 20%;
+				height: 130rpx;
+				display: flex;
+				justify-content: center;
+				flex-direction: column;
+				align-items: center;
+				text-align: center;
+				font-size: 34rpx;
+				padding: 10rpx;
+				box-sizing: border-box;
+				position: relative;
+
+				.text {
+					font-size: .8em;
+					margin-top: 5rpx;
+					color: #999999;
+					font-weight: 400;
+				}
+			}
+
+			.border::after {
+				content: '';
+				position: absolute;
+				bottom: 5rpx;
+				width: 30rpx;
+				height: 5rpx;
+				background-color: red;
+			}
+		}
+	}
+
+	.list-item {
+		display: flex;
+		align-items: center;
+		justify-content: space-between;
+		background-color: #FFFFFF;
+		padding: 20rpx;
+		margin: 2rpx 0rpx;
+		position: relative;
+
+		.avatar {
+			flex-shrink: 0;
+			width: 100rpx;
+			height: 100rpx;
+			border-radius: 50%;
+			border: 1px solid #1989FA;
+			margin-right: 16rpx;
+		}
+
+		.top {
+			display: flex;
+			justify-content: flex-end;
+			position: absolute;
+			top: 10rpx;
+			right: 0;
+
+			.icon {
+				margin-top: -20rpx;
+				padding: 20rpx;
+			}
+		}
+
+		.item-right {
+			flex: 1;
+			display: flex;
+			flex-direction: column;
+			justify-content: space-between;
+			// height: 200rpx;
+
+
+
+			.center {
+				align-self: flex-start;
+
+				.details {
+					width: 436rpx;
+					// height: 70rpx;
+					font-size: 26rpx;
+					font-family: PingFang SC;
+					font-weight: 400;
+					color: #999999;
+					display: -webkit-box;
+					margin-bottom: 20rpx;
+					overflow: hidden;
+					text-overflow: ellipsis;
+					word-wrap: break-word;
+					white-space: normal !important;
+					-webkit-line-clamp: 2;
+					-webkit-box-orient: vertical;
+				}
+			}
+
+
+			.bottom {
+				display: flex;
+				justify-content: flex-start;
+				align-items: center;
+				margin: 20rpx 0;
+
+				.title {
+					max-width: 300rpx;
+					white-space: nowrap;
+					text-overflow: ellipsis;
+					overflow: hidden;
+					word-break: break-all;
+					font-family: PingFang SC;
+					font-weight: 400;
+				}
+
+				.type {
+					margin-left: 10rpx;
+					padding: 3rpx 12rpx;
+					height: 30rpx;
+					border: 2rpx solid #999999;
+					border-radius: 20rpx;
+					font-size: 20rpx;
+					color: #999999;
+					line-height: 20rpx;
+					display: flex;
+					justify-content: center;
+					align-items: center;
+				}
+
+				.right {
+					width: 170rpx;
+					display: flex;
+					justify-content: space-between;
+					align-items: center;
+					font-size: 22rpx;
+					font-family: PingFang SC;
+					font-weight: 400;
+					color: #999999;
+					line-height: 35rpx;
+
+					.flex {
+						display: flex;
+						justify-content: center;
+
+						.icon {
+							margin-right: 5rpx;
+						}
+					}
+				}
+			}
+		}
+	}
+</style>

+ 52 - 0
src/pages/index/components/login.vue

@@ -0,0 +1,52 @@
+<template>
+  <view class="login">
+    <loading />
+  </view>
+</template>
+
+<script>
+export default {
+  props: ["login"],
+  created() {
+    this.init();
+  },
+  methods: {
+    async init() {
+      let loginRes = await this.$store.dispatch("Login");
+      if (loginRes.code == 200) {
+        this.$emit("update:login", true);
+      } else {
+        
+      }
+    },
+  },
+};
+</script>
+
+<style lang="scss" scoped>
+.login {
+  width: 100vw;
+  height: 80vh;
+  display: flex;
+  justify-content: center;
+  align-items: center;
+
+  .user-info {
+    display: flex;
+    flex-direction: column;
+    justify-content: center;
+    align-items: center;
+
+    .avatar {
+      border-radius: 50%;
+      width: 100px;
+      height: 100px;
+      overflow: hidden;
+    }
+
+    .nickname {
+      text-align: center;
+    }
+  }
+}
+</style>

+ 112 - 0
src/pages/index/index.vue

@@ -0,0 +1,112 @@
+<template>
+	<view>
+		<login v-if="!login" :login.sync="login" />
+		<view v-else>
+			<!-- <swiper circular class="swiper-box" :current-item-id="active" @change="swiperChange" easing-function="default">
+				<swiper-item class="swiper-item" item-id="home" @touchmove.stop="stopMove">
+					<home v-if="activeObj.home" ref="home" />
+				</swiper-item>
+				<swiper-item class="swiper-item" item-id="cinema" @touchmove.stop="stopMove">
+					<cinema v-if="activeObj.cinema" ref="cinema" />
+				</swiper-item>
+				<swiper-item class="swiper-item" item-id="applist" @touchmove.stop="stopMove">
+					<applist v-if="activeObj.applist" ref="applist" />
+				</swiper-item>
+				<swiper-item class="swiper-item" item-id="user" @touchmove.stop="stopMove">
+					<user v-if="activeObj.user" ref="user" />
+				</swiper-item>
+			</swiper> -->
+			<home v-if="activeObj.home" v-show="active==='home'" ref="home" />
+			<cinema v-if="activeObj.cinema" v-show="active==='cinema'" ref="cinema" />
+			<applist v-if="activeObj.applist" v-show="active==='applist'" ref="applist" />
+			<user v-if="activeObj.user" v-show="active==='user'" ref="user" />
+
+			<van-tabbar :active="active" @change="onChange" :placeholder="true" active-color="#E31818" inactive-color="#999999">
+				<van-tabbar-item name="home">
+					<m-icon slot="icon" type="shouye" size="24px"></m-icon>
+					<m-icon slot="icon-active" type="shouye" size="34px"></m-icon>
+					首页
+				</van-tabbar-item>
+				<van-tabbar-item name="cinema">
+					<m-icon slot="icon" type="dianying" size="24px"></m-icon>
+					<m-icon slot="icon-active" type="dianying" size="34px"></m-icon>
+					电影
+				</van-tabbar-item>
+				<van-tabbar-item name="applist">
+					<m-icon slot="icon" type="ddwl" size="24px"></m-icon>
+					<m-icon slot="icon-active" type="ddwl" size="34px"></m-icon>
+					发现
+				</van-tabbar-item>
+				<van-tabbar-item name="user">
+					<m-icon slot="icon" type="wode" size="24px"></m-icon>
+					<m-icon slot="icon-active" type="wode" size="34px"></m-icon>
+					我的
+				</van-tabbar-item>
+			</van-tabbar>
+		</view>
+	</view>
+</template>
+
+<script>
+	import applist from "./components/applist.vue";
+	import user from "@/pages/user/index.vue";
+	import login from "./components/login.vue";
+	import home from "@/pages/home/index.vue";
+	import cinema from "@/pages/cinema/index.vue";
+	export default {
+		components: {
+			applist,
+			user,
+			login,
+			home,
+			cinema,
+		},
+		data() {
+			return {
+				login: false,
+				active: "home",
+				activeObj: {},
+			};
+		},
+		mounted() {
+
+		},
+		onReachBottom() {
+			this.$refs[this.active].onBottom && this.$refs[this.active].onBottom()
+		},
+		onLoad: function(option) {
+			if (option.active) {
+				this.active = option.active;
+			}
+			this.activeObj[this.active] = true;
+		},
+		onShareAppMessage: function() {},
+		methods: {
+			stopMove() {
+				return true
+			},
+			onChange(event) {
+				// event.detail 的值为当前选中项的索引
+				this.active = event.detail;
+				this.activeObj[this.active] = true;
+				uni.pageScrollTo({
+					scrollTop: 0
+				})
+			},
+			swiperChange(event) {
+				this.active = event.detail.currentItemId;
+				this.activeObj[this.active] = true;
+			},
+		},
+	};
+</script>
+
+<style lang="scss">
+	.swiper-box {
+		height: calc(100vh - 100rpx - env(safe-area-inset-bottom));
+
+		.swiper-item {
+			// overflow: auto;
+		}
+	}
+</style>

+ 241 - 0
src/pages/phoneBill/index.vue

@@ -0,0 +1,241 @@
+<template>
+	<view>
+		<view class="top">
+			<image class="left-icon" :src="icon" mode="scaleToFill"></image>
+			<text class="tit">100元话费,限时{{price}}元</text>
+		</view>
+		<view class="user-data">
+			<van-cell-group>
+				<van-field :value="tmallNo" @change='tmallNo_fieldChange' type="text" required clearable label="天猫订单号"
+					icon="question-o" placeholder="请输入天猫订单号" @click-icon="onClickIcon('买了山泉心品才有的单号')" />
+				<van-field :value="rechargePhoneNo" @change='rechargePhoneNo_fieldChange' type="number" label="手机号码"
+					placeholder="请输入手机号码" required />
+			</van-cell-group>
+		</view>
+
+		<view class="commodity-selection">
+			<text class="top-tit">充值运营商类型</text>
+			<view class="selection-box">
+				<view class="commodity" :class="{selected:current==index}" @click="current=index"
+					v-for="(item,index) in goodsInfoList" :key='index'>
+					<text>{{item}}</text>
+					<m-icon v-if="current==index" class="xuanzhong-icon" type="xuanzhong" color="#47CB79"></m-icon>
+				</view>
+			</view>
+		</view>
+
+		<view class="prompt">
+			<text class="top-tit">购买须知</text>
+			<view class="dex-box">
+				<text v-for="(item,index) in remark" :key='index'>{{index+1}}、{{item}}</text>
+			</view>
+		</view>
+
+		<view class="buy-btn-box"></view>
+		<view class="buy-btn" @click="buy">
+			立即充值
+		</view>
+	</view>
+</template>
+
+<script>
+	export default {
+		data: () => ({
+			current: 0,
+			goodsInfoList: ['移动', '联通', '电信'],
+			remark: ['请注意,买了就不给退钱'],
+			tmallNo: null,
+			rechargePhoneNo: null,
+			icon: 'https://t1-1305573081.cos.ap-shanghai.myqcloud.com/wxapp/static/imgs/%E5%A4%A9%E7%8C%AB%E6%B4%BB%E5%8A%A8%E8%AF%9D%E8%B4%B9.png',
+			price: null
+		}),
+		async mounted() {
+			let {
+				data
+			} = await this.$api.phoneBill.getPriceKeyword()
+			this.price = data
+		},
+		methods: {
+			async buy() {
+				this.$utils.wxUtils.subscribeToNews().then(async res => {
+					let orderRes = await this.$api.phoneBill.prepareOrder({
+						tmallNo: this.tmallNo,
+						rechargePhoneNo: this.rechargePhoneNo,
+						operators: this.current + 1,
+						goodsPictureUrl: this.icon,
+					})
+					let payRes = await wx.requestPayment(orderRes.data)
+					if (payRes.errMsg == 'requestPayment:ok') {
+						this.$utils.goPage(
+							`/pages/phoneBill/orderdes?outTradeNo=${orderRes.data.outTradeNo}`,
+							'reLaunch')
+					}
+				})
+			},
+			tmallNo_fieldChange(e) {
+				this.tmallNo = e.detail
+			},
+			rechargePhoneNo_fieldChange(e) {
+				this.rechargePhoneNo = e.detail
+			},
+			onClickIcon(msg) {
+				wx.showToast({
+					title: msg,
+					icon: 'none'
+				})
+			}
+		}
+	}
+</script>
+
+<style lang="scss" scoped>
+	.top {
+		margin-top: 20rpx;
+		display: flex;
+		justify-content: center;
+		align-items: center;
+		background-color: #FFFFFF;
+		padding: 23rpx;
+
+		.left-icon {
+			width: 87rpx;
+			height: 79rpx;
+			margin-right: 22rpx;
+		}
+
+		.tit {
+			white-space: nowrap;
+			font-size: 30rpx;
+			font-weight: 400;
+			color: #0F0404;
+		}
+	}
+
+	.user-data {
+		background-color: #FFFFFF;
+		display: flex;
+		flex-direction: column;
+	}
+
+	.commodity-selection {
+		margin-top: 20rpx;
+		background-color: #FFFFFF;
+		display: flex;
+		flex-direction: column;
+
+		.top-tit {
+			font-size: 26rpx;
+			font-weight: 400;
+			color: #666666;
+			line-height: 39rpx;
+			border-bottom: 1rpx solid #e8e8e8;
+			padding: 28rpx;
+		}
+
+		.selection-box {
+			margin-top: 30rpx;
+			display: flex;
+			flex-wrap: wrap;
+			justify-content: flex-start;
+			padding-left: 15rpx;
+
+			.selected {
+				border: 1rpx solid #ECBF7A !important;
+				background-color: #FDF3D7;
+			}
+
+			.commodity {
+				margin-bottom: 15rpx;
+				margin-right: 15rpx;
+				width: 230rpx;
+				display: flex;
+				flex-direction: column;
+				align-items: center;
+				border: 1rpx solid #E8E8E8;
+				box-sizing: border-box;
+				padding: 30rpx 20rpx;
+				border-radius: 6rpx;
+				position: relative;
+
+				.xuanzhong-icon {
+					position: absolute;
+					right: 0;
+					bottom: 0;
+				}
+
+				text {
+					&:nth-child(1) {
+						color: #999999;
+						font-size: 26rpx;
+					}
+
+					&:nth-child(2) {
+						color: #999999;
+						font-size: 26rpx;
+					}
+
+					&:nth-child(3) {
+						color: #E31818;
+						font-size: 40rpx;
+					}
+
+					&:nth-child(4) {
+						color: #999999;
+						font-size: 26rpx;
+						text-decoration: line-through;
+					}
+				}
+			}
+		}
+	}
+
+	.prompt {
+		margin-top: 20rpx;
+		background-color: #FFFFFF;
+		display: flex;
+		flex-direction: column;
+
+		.top-tit {
+			font-size: 26rpx;
+			font-weight: 400;
+			color: #666666;
+			line-height: 39rpx;
+			border-bottom: 1rpx solid #e8e8e8;
+			padding: 28rpx;
+		}
+
+		.dex-box {
+			padding: 28rpx;
+			display: flex;
+			flex-direction: column;
+			font-size: 26rpx;
+			font-weight: 400;
+			color: #666666;
+			line-height: 39rpx;
+		}
+	}
+
+	.buy-btn-box {
+		margin-top: 30rpx;
+		width: 600rpx;
+		height: 80rpx;
+		opacity: 0;
+	}
+
+	.buy-btn {
+		position: fixed;
+		bottom: 30rpx;
+		left: 50%;
+		transform: translateX(-50%);
+		width: 600rpx;
+		height: 80rpx;
+		background: linear-gradient(90deg, #E31818, #ED3E24, #ED4F24);
+		border-radius: 40rpx;
+		font-size: 30rpx;
+		font-weight: 400;
+		color: #FFFFFF;
+		display: flex;
+		justify-content: center;
+		align-items: center;
+	}
+</style>

+ 300 - 0
src/pages/phoneBill/orderdes.vue

@@ -0,0 +1,300 @@
+<template>
+	<view class="page">
+		<loadSke :loading='loading'>
+			<view class="remind-top">首页->我的->我的订单</view>
+			<view class="des-box">
+				<view>
+					<view v-if="true" class="code-box">
+						<image class="qrcode" :src="orderDes.goodsPictureUrl" mode="widthFix"></image>
+						<view class="code">
+							<text>充值号码</text>
+							<text>{{orderDes.rechargePhoneNo}}</text>
+						</view>
+					</view>
+				</view>
+				<view class="order-num">
+					<text>订单号:{{outTradeNo}}</text>
+					<text>{{orderDes.orderStatusDesc}}</text>
+					<text>天猫单号:{{orderDes.tmallNo}}</text>
+				</view>
+				<view class="des">
+					<text class="film-name">充值商品</text>
+					<view class="film-time">
+						<text>购买时间</text>
+						<text>{{orderDes.create_time}}</text>
+					</view>
+					<view class="film-address">
+						<text>充值号码</text>
+						<text>{{orderDes.rechargePhoneNo}}</text>
+					</view>
+					<view class="film-video">
+						<text>运营商型</text>
+						<text>{{orderDes.operators}}</text>
+					</view>
+					<view class="film-seat">
+						<text>购买价格</text>
+						<text>{{orderDes.total}}</text>
+					</view>
+				</view>
+			</view>
+		</loadSke>
+	</view>
+</template>
+
+<script>
+	export default {
+		data: () => ({
+			orderDes: {},
+			loading: true,
+			outTradeNo: null,
+			pollingTiemId: null
+		}),
+		onLoad: function(option) {
+			this.outTradeNo = option.outTradeNo
+		},
+		mounted() {
+			this.init()
+		},
+		methods: {
+			async init() {
+				let orderRes = await this.$api.order.getWxOrder(this.outTradeNo)
+				this.orderDes = orderRes.data
+				this.loading = false
+				if (this.orderDes.orderStatus == 1) {
+					this.polling()
+				}
+			},
+			polling() {
+				this.pollingTiemId = setInterval(async () => {
+					let orderRes = await this.$api.order.getWxOrder(this.outTradeNo)
+					this.orderDes = orderRes.data
+					if (this.orderDes.orderStatus != 1) {
+						clearInterval(this.pollingTiemId)
+					}
+				}, 30000)
+			}
+		},
+		beforeDestroy() {
+			clearInterval(this.pollingTiemId)
+		}
+	}
+</script>
+
+<style lang="scss">
+	.page {
+		padding-bottom: 20rpx;
+	}
+
+	.remind {
+		padding-top: 36rpx;
+		font-size: 26rpx;
+		font-weight: 400;
+		color: #0F0404;
+		text-align: center;
+	}
+
+	.remind-top {
+		margin-top: 36rpx;
+		font-size: 26rpx;
+		font-weight: 400;
+		color: #ff0000;
+		text-align: center;
+	}
+
+	.des-box {
+		width: 564rpx;
+		background: #FFFFFF;
+		border-radius: 20rpx;
+		margin: auto;
+		margin-top: 30rpx;
+
+		.code-box {
+			display: flex;
+			flex-direction: column;
+			align-items: center;
+			padding-bottom: 38rpx;
+
+			.code {
+				margin-top: 43rpx;
+
+				text {
+					font-size: 26rpx;
+					font-weight: 400;
+					color: #666666;
+					margin-right: 20rpx;
+
+					&:nth-child(2) {
+						color: #0F0404;
+					}
+				}
+			}
+
+			.qrcode {
+				margin-top: 43rpx;
+				width: 360rpx;
+				height: 360rpx;
+			}
+
+			.qrcode-loading {
+				margin-top: 43rpx;
+				width: 100%;
+			}
+		}
+
+		.order-num {
+			display: flex;
+			flex-direction: column;
+			justify-content: space-between;
+			align-items: center;
+			padding: 34rpx 31rpx;
+			border-top: 1rpx dashed #D9D9D9;
+			border-bottom: 1rpx dashed #D9D9D9;
+			position: relative;
+
+			&::after {
+				content: '';
+				width: 24rpx;
+				height: 24rpx;
+				border-radius: 50%;
+				background-color: #F1F1F1;
+				position: absolute;
+				top: 0;
+				left: 0;
+				transform: translate(-50%, -50%);
+			}
+
+			&::before {
+				content: '';
+				width: 24rpx;
+				height: 24rpx;
+				border-radius: 50%;
+				background-color: #F1F1F1;
+				position: absolute;
+				top: 0;
+				right: 0;
+				transform: translate(50%, -50%);
+			}
+
+			text {
+				&:nth-child(1) {
+					margin-top: 60rpx;
+					word-break: break-all;
+					font-size: 22rpx;
+					font-weight: 400;
+					color: #666666;
+				}
+
+				&:nth-child(2) {
+					margin-top: 10rpx;
+					padding: 10rpx;
+					display: flex;
+					justify-content: center;
+					align-items: center;
+					background: #FFE5E5;
+					border-radius: 20rpx;
+					border-top-left-radius: 0;
+					border-bottom-left-radius: 0;
+					font-size: 20rpx;
+					font-weight: 400;
+					color: #E31818;
+					position: absolute;
+					left: 0;
+					top: 20rpx;
+				}
+
+				&:nth-child(3) {
+					margin-top: 10rpx;
+					word-break: break-all;
+					font-size: 22rpx;
+					font-weight: 400;
+					color: #666666;
+				}
+			}
+		}
+
+		.des {
+			padding: 45rpx 30rpx;
+			border-bottom: 1rpx dashed #D9D9D9;
+			display: flex;
+			flex-direction: column;
+
+			.film-name {
+				font-size: 30rpx;
+				font-weight: 400;
+				color: #0F0404;
+			}
+
+			text {
+				font-size: 26rpx;
+				font-weight: 400;
+				color: #666666;
+				margin-right: 20rpx;
+				white-space: nowrap;
+			}
+
+			.film-time {
+				text:nth-child(2) {
+					color: #999999;
+				}
+			}
+
+			.film-address {
+				display: flex;
+				justify-content: flex-start;
+				align-items: stretch;
+
+				text:nth-child(2) {
+					color: #999999;
+					white-space: pre-wrap;
+				}
+			}
+
+			.film-video {
+				display: flex;
+				justify-content: flex-start;
+				align-items: stretch;
+
+				text:nth-child(2) {
+					color: #999999;
+					white-space: pre-wrap;
+				}
+			}
+
+			.film-seat {
+				display: flex;
+				justify-content: flex-start;
+				align-items: stretch;
+				margin-top: 10rpx;
+
+				.seat-box {
+					display: flex;
+					flex-wrap: wrap;
+
+					text {
+						height: 40rpx;
+						padding: 4rpx 15rpx;
+						margin-bottom: 10rpx;
+						background: #EBEBEB;
+						border-radius: 4rpx;
+						color: #999999;
+					}
+				}
+			}
+		}
+
+		.price {
+			padding: 40rpx 30rpx;
+
+			text {
+				font-size: 26rpx;
+				font-weight: 400;
+				color: #666666;
+				margin-right: 20rpx;
+
+				&:nth-child(2) {
+					color: #E31818;
+				}
+			}
+		}
+	}
+</style>

+ 242 - 0
src/pages/user/browserecord.vue

@@ -0,0 +1,242 @@
+<template>
+	<view class="content">
+		<loadSke :loading='loading' :list='applist'>
+			<view class='list-item' v-for="(item, index) in applist" :key="index" @click="$utils.goMiniApp({appId:item.appletAddress},item)">
+				<image class="avatar" mode="aspectFill" :src="item.appletLogoFileUrl || '/static/imgs/shmr.png'">
+					<view class="item-right">
+						<view class="top">
+							<van-icon class="icon" name="/static/imgs/zf.png" size='14' />
+							<van-icon class="icon" name="/static/imgs/bxh.png" @tap.stop='delSc(index)' size='12' />
+						</view>
+						<view class="center">
+							<text class="details">{{item.appletIntroduce || '该商家暂无描述,敬请期待!'}}</text>
+						</view>
+						<view class="bottom">
+							<text class="title">{{item.corporateName}}</text>
+						</view>
+					</view>
+			</view>
+		</loadSke>
+	</view>
+
+</template>
+
+<script>
+	export default {
+		data() {
+			return {
+				active: 0,
+				current: 0,
+				mode: 'round',
+				applist: {},
+				loading:true,
+				pageNum: 1,
+				pageSize: 10,
+				total: 1,
+			}
+		},
+		mounted() {
+			this.initAppList()
+		},
+		onReachBottom(){
+			if(this.total-this.pageNum*this.pageSize<=0){
+				return
+			}
+			this.pageNum++
+			this.$api.applist.getBrowseRecordInfoList({
+				pageNum: this.pageNum,
+				pageSize: this.pageSize
+			}).then(res => {
+				this.applist = this.applist.concat(res.rows)
+			})
+		},
+		methods: {
+			initAppList() {
+				this.$api.applist.getBrowseRecordInfoList({
+					pageNum: this.pageNum,
+					pageSize: this.pageSize
+				}).then(res => {
+					this.applist = res.rows
+					this.total = res.total
+					this.$nextTick(()=>{
+						this.loading=false
+					})
+				})
+			},
+			delSc(index) {
+				this.$api.applist.BrowseRecordDel(this.applist[index].id).then(res => {
+					if (res.code == 200) {
+						this.$set(this.applist[index], 'collectionStatus', '0')
+						this.$utils.Toast('取消收藏成功!');
+						delete this.applist.splice(index, 1)
+					}
+				})
+			}
+		}
+	}
+</script>
+
+<style lang="scss" scoped>
+	.content {
+		padding-bottom: 1rpx;
+	}
+
+	.swiper-box {
+		position: sticky;
+		top: 0px;
+		left: 0;
+		height: 422rpx;
+		z-index: 9;
+	}
+
+	.sticky-top {
+		position: sticky;
+		top: 192rpx;
+		left: 0;
+		margin: 30rpx 30rpx;
+		border-radius: 20rpx;
+		overflow: hidden;
+		background-color: #4fc08d;
+		z-index: 10;
+		display: flex;
+		justify-content: center;
+		align-items: center;
+		// border-top-left-radius: 14px;
+		// border-top-right-radius: 14px;
+		padding-right: 3%;
+
+		.top-search {
+			flex: 1;
+		}
+	}
+
+	.sticky {
+		position: sticky;
+		top: 295rpx;
+		left: 0;
+		background-color: #fff;
+		z-index: 9;
+		margin: 30rpx 30rpx;
+		border-radius: 20rpx;
+
+		.grid {
+			display: flex;
+			justify-content: space-between;
+			padding: 1% 2%;
+			margin-bottom: 2%;
+			border-bottom-left-radius: 10px;
+			border-bottom-right-radius: 10px;
+
+			.grid-item {
+				width: 50px;
+				height: 60px;
+				display: flex;
+				justify-content: center;
+				flex-direction: column;
+				align-items: center;
+				font-size: 12px;
+			}
+		}
+	}
+
+	.list-item {
+		display: flex;
+		align-items: center;
+		justify-content: space-between;
+		background-color: #FFFFFF;
+		height: 170rpx;
+		padding: 34rpx 20rpx;
+		margin: 24rpx 30rpx;
+		border-radius: 20rpx;
+
+		.avatar {
+			flex-shrink: 0;
+			width: 161rpx;
+			height: 161rpx;
+			margin-right: 16rpx;
+		}
+
+		.item-right {
+			flex: 1;
+			display: flex;
+			flex-direction: column;
+			justify-content: space-between;
+			height: 200rpx;
+
+			.top {
+				.icon {
+					margin-top: -20rpx;
+					padding: 20rpx;
+				}
+
+				display: flex;
+				justify-content: flex-end;
+			}
+
+			.center {
+				align-self: flex-start;
+
+				.details {
+					width: 436rpx;
+					height: 70rpx;
+					font-size: 26rpx;
+					font-family: PingFang SC;
+					font-weight: 400;
+					color: #0F0404;
+					display: -webkit-box;
+					margin-bottom: 20rpx;
+					overflow: hidden;
+					text-overflow: ellipsis;
+					word-wrap: break-word;
+					white-space: normal !important;
+					-webkit-line-clamp: 2;
+					-webkit-box-orient: vertical;
+				}
+			}
+
+
+			.bottom {
+				display: flex;
+				justify-content: space-between;
+				align-items: center;
+
+				.title {
+					padding: 3rpx 12rpx;
+					height: 30rpx;
+					background: #FFE6E6;
+					border: 1rpx solid #E31818;
+					border-radius: 2rpx;
+					font-size: 20rpx;
+					font-family: PingFang SC;
+					font-weight: 400;
+					color: #E31818;
+					line-height: 20rpx;
+					display: flex;
+					justify-content: center;
+					align-items: center;
+				}
+
+				.right {
+					width: 170rpx;
+					display: flex;
+					justify-content: space-between;
+					align-items: center;
+					font-size: 22rpx;
+					font-family: PingFang SC;
+					font-weight: 400;
+					color: #999999;
+					line-height: 35rpx;
+
+					.flex {
+						display: flex;
+						justify-content: center;
+
+						.icon {
+							margin-right: 5rpx;
+						}
+					}
+				}
+			}
+		}
+	}
+</style>

+ 242 - 0
src/pages/user/collectionList.vue

@@ -0,0 +1,242 @@
+<template>
+	<view class="content">
+		<loadSke :loading='loading' :list='applist'>
+			<view class='list-item' v-for="(item, index) in applist" :key="index" @click="$utils.goMiniApp({appId:item.appletAddress},item)">
+				<image class="avatar" mode="aspectFill" :src="item.appletLogoFileUrl || '/static/imgs/shmr.png'">
+					<view class="item-right">
+						<view class="top">
+							<van-icon class="icon" name="/static/imgs/zf.png" size='14' />
+							<van-icon class="icon" name="/static/imgs/bxh.png" @tap.stop='delSc(index)' size='12' />
+						</view>
+						<view class="center">
+							<text class="details">{{item.appletIntroduce || '该商家暂无描述,敬请期待!'}}</text>
+						</view>
+						<view class="bottom">
+							<text class="title">{{item.corporateName}}</text>
+						</view>
+					</view>
+			</view>
+		</loadSke>
+	</view>
+
+</template>
+
+<script>
+	export default {
+		data() {
+			return {
+				active: 0,
+				current: 0,
+				mode: 'round',
+				applist: {},
+				loading: true,
+				pageNum: 1,
+				pageSize: 10,
+				total: 1,
+			}
+		},
+		mounted() {
+			this.initAppList()
+		},
+		onReachBottom(){
+			if(this.total-this.pageNum*this.pageSize<=0){
+				return
+			}
+			this.pageNum++
+			this.$api.applist.collectionList({
+				pageNum: this.pageNum,
+				pageSize: this.pageSize
+			}).then(res => {
+				this.applist = this.applist.concat(res.rows)
+			})
+		},
+		methods: {
+			initAppList() {
+				this.$api.applist.collectionList({
+					pageNum: this.pageNum,
+					pageSize: this.pageSize
+				}).then(res => {
+					this.applist = res.rows
+					this.total = res.total
+					this.$nextTick(() => {
+						this.loading = false
+					})
+				})
+			},
+			delSc(index) {
+				this.$api.applist.delFavorites(this.applist[index].customerId).then(res => {
+					if (res.code == 200) {
+						this.$set(this.applist[index], 'collectionStatus', '0')
+						this.$utils.Toast('取消收藏成功!');
+						delete this.applist.splice(index, 1)
+					}
+				})
+			}
+		}
+	}
+</script>
+
+<style lang="scss" scoped>
+	.content {
+		padding-bottom: 1rpx;
+	}
+
+	.swiper-box {
+		position: sticky;
+		top: 0px;
+		left: 0;
+		height: 422rpx;
+		z-index: 9;
+	}
+
+	.sticky-top {
+		position: sticky;
+		top: 192rpx;
+		left: 0;
+		margin: 30rpx 30rpx;
+		border-radius: 20rpx;
+		overflow: hidden;
+		background-color: #4fc08d;
+		z-index: 10;
+		display: flex;
+		justify-content: center;
+		align-items: center;
+		// border-top-left-radius: 14px;
+		// border-top-right-radius: 14px;
+		padding-right: 3%;
+
+		.top-search {
+			flex: 1;
+		}
+	}
+
+	.sticky {
+		position: sticky;
+		top: 295rpx;
+		left: 0;
+		background-color: #fff;
+		z-index: 9;
+		margin: 30rpx 30rpx;
+		border-radius: 20rpx;
+
+		.grid {
+			display: flex;
+			justify-content: space-between;
+			padding: 1% 2%;
+			margin-bottom: 2%;
+			border-bottom-left-radius: 10px;
+			border-bottom-right-radius: 10px;
+
+			.grid-item {
+				width: 50px;
+				height: 60px;
+				display: flex;
+				justify-content: center;
+				flex-direction: column;
+				align-items: center;
+				font-size: 12px;
+			}
+		}
+	}
+
+	.list-item {
+		display: flex;
+		align-items: center;
+		justify-content: space-between;
+		background-color: #FFFFFF;
+		height: 170rpx;
+		padding: 34rpx 20rpx;
+		margin: 24rpx 30rpx;
+		border-radius: 20rpx;
+
+		.avatar {
+			flex-shrink: 0;
+			width: 161rpx;
+			height: 161rpx;
+			margin-right: 16rpx;
+		}
+
+		.item-right {
+			flex: 1;
+			display: flex;
+			flex-direction: column;
+			justify-content: space-between;
+			height: 200rpx;
+
+			.top {
+				.icon {
+					margin-top: -20rpx;
+					padding: 20rpx;
+				}
+
+				display: flex;
+				justify-content: flex-end;
+			}
+
+			.center {
+				align-self: flex-start;
+
+				.details {
+					width: 436rpx;
+					height: 70rpx;
+					font-size: 26rpx;
+					font-family: PingFang SC;
+					font-weight: 400;
+					color: #0F0404;
+					display: -webkit-box;
+					margin-bottom: 20rpx;
+					overflow: hidden;
+					text-overflow: ellipsis;
+					word-wrap: break-word;
+					white-space: normal !important;
+					-webkit-line-clamp: 2;
+					-webkit-box-orient: vertical;
+				}
+			}
+
+
+			.bottom {
+				display: flex;
+				justify-content: space-between;
+				align-items: center;
+
+				.title {
+					padding: 3rpx 12rpx;
+					height: 30rpx;
+					background: #FFE6E6;
+					border: 1rpx solid #E31818;
+					border-radius: 2rpx;
+					font-size: 20rpx;
+					font-family: PingFang SC;
+					font-weight: 400;
+					color: #E31818;
+					line-height: 20rpx;
+					display: flex;
+					justify-content: center;
+					align-items: center;
+				}
+
+				.right {
+					width: 170rpx;
+					display: flex;
+					justify-content: space-between;
+					align-items: center;
+					font-size: 22rpx;
+					font-family: PingFang SC;
+					font-weight: 400;
+					color: #999999;
+					line-height: 35rpx;
+
+					.flex {
+						display: flex;
+						justify-content: center;
+
+						.icon {
+							margin-right: 5rpx;
+						}
+					}
+				}
+			}
+		}
+	}
+</style>

+ 177 - 0
src/pages/user/index.vue

@@ -0,0 +1,177 @@
+<template>
+	<scroll-view scroll-y class="content">
+		<view class="top">
+			<view class="avabox">
+				<van-image round class="img" width="200rpx" height="200rpx" :src="userData.headImage" />
+				<view class="avatitbox">
+					<text>{{ userData.nickName }}</text>
+					<text v-if="userData.gzptUserId">{{ studentInfo.logincode }}</text>
+					<view class="sync-btn" @tap="getUserProfile">点击同步用户头像昵称</view>
+				</view>
+			</view>
+		</view>
+
+		<view class="serviceBox">
+			<view class="tit">
+				<text>我的订单</text>
+			</view>
+			<view class="btnBox">
+				<view class="item-box" :plain="true" @click="$utils.goPage('/pages/user/order?active=0')">
+					<m-icon type="qbdd" font-size='22px' />
+					<text class="text">全部订单</text>
+				</view>
+				<view class="item-box" :plain="true" @click="$utils.goPage('/pages/user/order?active=1')">
+					<m-icon type="dfh" font-size='22px' />
+					<text class="text">等待发货</text>
+				</view>
+				<view class="item-box" :plain="true" @click="$utils.goPage('/pages/user/order?active=2')">
+					<m-icon type="jywc" font-size='22px' />
+					<text class="text">交易完成</text>
+				</view>
+				<view class="item-box" :plain="true" @click="$utils.goPage('/pages/user/order?active=3')">
+					<m-icon type="tksh" font-size='22px' />
+					<text class="text">退款/售后</text>
+				</view>
+			</view>
+		</view>
+
+		<view class="serviceBox">
+			<view class="tit">
+				<text>我的信息</text>
+			</view>
+			<van-cell title="我的设置" is-link @tap="$utils.goPage('/pages/user/set')">
+				<m-icon slot="icon" type="shezhi" color="#d81e06"/>
+			</van-cell>
+			<button class="server" open-type="feedback" :plain="true">
+				<van-cell title="意见反馈" is-link>
+					<m-icon slot="icon" type="yjfk" color="#d81e06"/>
+				</van-cell>
+			</button>
+			<button class="server" open-type="contact" :plain="true">
+				<van-cell title="联系客服" is-link>
+					<m-icon slot="icon" type="lxkf" color="#d81e06"/>
+				</van-cell>
+			</button>
+		</view>
+
+		<!-- <view class="ad-box serviceBox">
+			<ad unit-id="adunit-d8c1548cc9663765"></ad>
+		</view> -->
+		
+	</scroll-view>
+</template>
+
+<script>
+	export default {
+		computed: {
+			userData() {
+				return this.$store.state.user.userInfo;
+			},
+		},
+		mounted() {
+			this.$store.dispatch("GetInfo");
+		},
+		methods: {
+			async getUserProfile(e) {
+				let userInfo = await wx.getUserProfile({
+					desc: "业务需要",
+				});
+				let updateRes = await this.$api.user.updateUserInfo({
+					headImage: userInfo.userInfo.avatarUrl,
+					nickName: userInfo.userInfo.nickName,
+				});
+				if (updateRes.code == 200) {
+					this.$store.state.user.userInfo.headImage = userInfo.userInfo.avatarUrl;
+					this.$store.state.user.userInfo.nickName = userInfo.userInfo.nickName;
+				}
+			},
+		},
+	};
+</script>
+
+<style lang="scss" scoped>
+	.content {
+		height: 100%;
+		background-image: url("https://t1-1305573081.cos.ap-shanghai.myqcloud.com/wxapp/static/imgs/%E9%A1%B6%E9%83%A8%E8%83%8C%E6%99%AF3.png");
+		background-repeat: no-repeat;
+		background-size: 100% 90%;
+	}
+
+	.ad-box {
+		margin: 40rpx;
+		padding: 20rpx;
+		display: flex;
+		justify-content: center;
+		align-items: center;
+	}
+
+	.top {
+		padding-top: 100rpx;
+
+		.avabox {
+			display: flex;
+			padding: 10%;
+
+			.img {
+				border-radius: 50%;
+			}
+
+			.sync-btn {
+				margin-top: 20rpx;
+				height: 40rpx;
+			}
+
+			.avatitbox {
+				flex: 1;
+				display: flex;
+				flex-direction: column;
+				justify-content: space-between;
+				padding: 30rpx;
+				color: #ffffff;
+				height: 100rpx;
+			}
+		}
+	}
+
+	.serviceBox {
+		background-color: #fff;
+		margin: 30rpx;
+		border-radius: 10rpx;
+
+		.tit {
+			padding: 16rpx 26rpx;
+			border-bottom: 1rpx solid #e8e8e8;
+		}
+
+		.btnBox {
+			display: flex;
+			justify-content: space-around;
+			align-items: center;
+
+			.item-box {
+				display: flex;
+				flex-direction: column;
+				justify-content: space-around;
+				align-items: center;
+				padding: 20rpx;
+				border: none;
+
+				.text {
+					font-size: 26rpx;
+					font-family: PingFang SC;
+					font-weight: 400;
+					color: #666666;
+				}
+			}
+		}
+
+		.server {
+			border: none;
+			background-color: none;
+			margin: 0;
+			padding: 0;
+			text-align: left;
+			display: flexbox;
+		}
+	}
+</style>

+ 152 - 0
src/pages/user/order.vue

@@ -0,0 +1,152 @@
+<template>
+	<view>
+		<view class="tabs">
+			<view class="tab" :class="{selected:index==active}" @click="active=index" v-for="(item,index) in orderType"
+				:key='index'>
+				{{item}}
+			</view>
+		</view>
+		<loadSke :loading='orderLoading' :list="orderList">
+			<view class="order-item ios-bottom" v-for="(item,index) in orderList" :key='item.outTradeNo' @click="goOrderDes(item)">
+				<image class="img" :src="item.goodsPictureUrl" mode="aspectFit"></image>
+				<view class="des-box">
+					<text>订单名称:{{item.orderName}}</text>
+					<text>订单日期:{{item.createTime}}</text>
+					<text>订单状态:{{item.orderStatus}}</text>
+					<text>订单价格:{{item.total}}</text>
+				</view>
+				<m-icon class='icon' type="arrow-right"></m-icon>
+			</view>
+		</loadSke>
+	</view>
+</template>
+
+<script>
+	export default {
+		data: () => ({
+			active: null,
+			orderType: [
+				'全部订单',
+				'等待发货',
+				'交易完成',
+				'退款/售后'
+			],
+			orderLoading: true,
+			orderList: {},
+		}),
+		onLoad: function(option) {
+			this.active = option.active
+		},
+		watch: {
+			active() {
+				this.init()
+			}
+		},
+		methods: {
+			async init() {
+				this.orderLoading = true
+				let orderListRes = await this.$api.order.getOrderList({
+					orderStatus: this.active == 0 ? null : this.active,
+					pageNum: 1,
+					pageSize: 10
+				})
+				this.orderList = orderListRes.rows
+				this.orderLoading = false
+			},
+			goOrderDes(item) {
+				let pageMap = new Map([
+					['1', () => {
+						this.$utils.goPage(`/pages/cinema/orderdes?outTradeNo=${item.outTradeNo}`)
+					}],
+					['2', () => {
+						this.$utils.goPage(`/pages/fulu/orderdes?outTradeNo=${item.outTradeNo}`)
+					}],
+					['3', () => {
+						this.$utils.goPage(`/pages/phoneBill/orderdes?outTradeNo=${item.outTradeNo}`)
+					}],
+				])
+
+				pageMap.get(item.goodsType)()
+			}
+		}
+	}
+</script>
+
+<style lang="scss" scoped>
+	.tabs {
+		position: sticky;
+		top: 0;
+		z-index: 1;
+		display: flex;
+		justify-content: space-around;
+		align-items: center;
+		background-color: #FFFFFF;
+		padding: 0 20rpx;
+
+		.tab {
+			padding: 20rpx 0;
+		}
+
+		.selected {
+			position: relative;
+
+			&::after {
+				content: '';
+				width: 80rpx;
+				height: 6rpx;
+				background-color: red;
+				position: absolute;
+				bottom: 0;
+				left: 50%;
+				transform: translateX(-50%);
+			}
+		}
+	}
+
+	.ios-bottom {
+		padding-bottom: calc(10px + env(safe-area-inset-bottom)/2);
+	}
+
+	.order-item {
+		background-color: #FFFFFF;
+		margin-top: 10rpx;
+		padding: 30rpx;
+		display: flex;
+		justify-content: flex-start;
+		align-items: stretch;
+		position: relative;
+
+		&:nth-child(1) {
+			margin-top: 20rpx;
+		}
+
+		.img {
+			width: 112rpx;
+			height: 164rpx;
+			margin-right: 50rpx;
+		}
+
+		.des-box {
+			display: flex;
+			flex-direction: column;
+			justify-content: space-between;
+
+			text {
+				font-size: 26rpx;
+				font-weight: 400;
+				color: #666666;
+			}
+
+			text:nth-child(2) {
+				color: #0F0404 !important;
+			}
+		}
+
+		.icon {
+			position: absolute;
+			right: 30rpx;
+			top: 50%;
+			transform: translateY(-50%);
+		}
+	}
+</style>

+ 114 - 0
src/pages/user/set.vue

@@ -0,0 +1,114 @@
+<template>
+	<view class="">
+		<van-cell center title="我的昵称" :value="userData.nickName" />
+		<van-cell title="我的头像" center>
+			<image class="image-ava" slot="right-icon" :src="userData.headImage">
+		</van-cell>
+		<van-popup :show="idCardShow" round>
+			<view class="idCard">
+				<van-divider contentPosition="center">绑定身份证信息</van-divider>
+				<van-cell-group>
+					<van-field :value="idCard" @change='idCardput' label="身份证" maxlength='18' placeholder="请输入身份证号" />
+					<van-field :value="password" @change='passwordput' type="password" label="密码" placeholder="请输入密码" />
+					<van-cell title="归属驾校地区" :value="area" @click='popup=!popup' />
+				</van-cell-group>
+				<view class="btn-box">
+					<van-button @click='idCardShow=!idCardShow' type="default">取消绑定</van-button>
+					<van-button @click='submitBinding' type="info" :loading='loading' loading-text="绑定中..">确认绑定</van-button>
+				</view>
+			</view>
+		</van-popup>
+		<van-popup :show="popup" position="bottom">
+			<van-area :columns-placeholder="['请选择', '请选择']" value="35" @cancel='popup=!popup' @confirm='popup=!popup' :area-list="areaList"
+			 @change='regionSelection' columns-num='2' />
+		</van-popup>
+	</view>
+</template>
+
+<script>
+	import md5 from 'crypto-js/md5'
+	export default {
+		data() {
+			return {
+				loading: false,
+				idCardShow: false,
+				popup: false,
+				idCard: null,
+				password: null,
+				areaCode: null,
+				area: "请点击选择地区",
+				areaList: {
+					province_list: {
+						35: '福建省',
+					},
+					city_list: {
+						3501: '福州市',
+						3502: '厦门市',
+						3503: '莆田市',
+						3504: '三明市',
+						3505: '泉州市',
+						3506: '漳州市',
+						3507: '南平市',
+						3508: '龙岩市',
+						3509: '宁德市',
+					}
+				}
+			}
+		},
+		computed: {
+			userData() {
+				return this.$store.getters.userInfo;
+			}
+		},
+		methods: {
+			regionSelection(e) {
+				console.log(e)
+				this.area = `${e.detail.values[0].name}  ${e.detail.values[1].name}`
+				this.areaCode = e.detail.values[1].code
+			},
+			idCardput(e) {
+				this.idCard = e.detail
+			},
+			passwordput(e) {
+				this.password = e.detail
+			},
+			submitBinding() {
+				console.log(this.areaCode, this.idCard, this.password)
+				this.loading = true
+				this.$api.user.bindUserCard({
+					city: this.areaCode,
+					logincode: this.idCard,
+					password: md5(this.password).toString()
+				}).then((res) => {
+					if (res.code == 200) {
+						this.$utils.Toast('绑定成功');
+						this.idCardShow = false
+					} else if (res.code == 502) {
+						this.$utils.Toast(res.msg);
+					} else {
+						this.$utils.Toast('系统内部错误');
+					}
+					this.loading = false
+				})
+			},
+		}
+	}
+</script>
+
+<style>
+	.idCard {
+		width: 600rpx;
+		padding: 30rpx;
+		margin: auto;
+		display: flex;
+		flex-direction: column;
+		justify-content: center;
+		align-items: center;
+	}
+
+	.image-ava {
+		width: 100rpx;
+		height: 100rpx;
+		border-radius: 50%;
+	}
+</style>

+ 20 - 0
src/pages/webview/webview.vue

@@ -0,0 +1,20 @@
+<template>
+	<web-view class="webview" :src="decodeURIComponent(src)"></web-view>
+</template>
+
+<script>
+	export default {
+		data() {
+			return {
+				src: encodeURIComponent('')
+			};
+		},
+		onLoad: function (option) {
+		    this.src = option.src;
+		}
+	}
+</script>
+
+<style lang="scss">
+	.webview{}
+</style>

binární
src/static/imgs/home-avtive.png


binární
src/static/imgs/home.png


binární
src/static/imgs/shmr.png


binární
src/static/imgs/theFilm-avtive.png


binární
src/static/imgs/theFilm.png


binární
src/static/imgs/user-avtive.png


binární
src/static/imgs/user.png


binární
src/static/imgs/video-avtive.png


binární
src/static/imgs/video.png


binární
src/static/logo.png


+ 10 - 0
src/store/getters.js

@@ -0,0 +1,10 @@
+const getters = {
+  token: state => state.user.token,
+  userInfo: state => state.user.userInfo,
+  avatar: state => state.user.avatar,
+  name: state => state.user.name,
+  introduction: state => state.user.introduction,
+  roles: state => state.user.roles,
+  permissions: state => state.user.permissions
+}
+export default getters

+ 18 - 0
src/store/index.js

@@ -0,0 +1,18 @@
+import Vue from 'vue'
+import Vuex from 'vuex'
+Vue.use(Vuex)
+//自定义getters
+import getters from './getters'
+//批量引入modules下的js
+const modules = {}
+const modulesContext = require.context('./modules', false, /\.js$/)
+modulesContext.keys().forEach(key => {
+	modules[key.slice(2, -3)] = modulesContext(key).default
+})
+//初始化store
+const store = new Vuex.Store({
+	modules,
+	getters
+})
+
+export default store

+ 30 - 0
src/store/modules/cinema.js

@@ -0,0 +1,30 @@
+const cinema = {
+	state: {
+		filmList: null,
+		filmDiscount: 1,
+		discountRule: {},
+		cityId: null,
+		cityObj:{}
+	},
+
+	mutations: {
+		SET_FILMLIST: (state, filmList) => {
+			state.filmList = filmList
+		},
+		SET_FILMDISCOUNT: (state, filmDiscount) => {
+			state.filmDiscount = filmDiscount
+		},
+		SET_DISCOUNTRULE: (state, discountRule) => {
+			state.discountRule = discountRule
+		},
+		SET_CITYID: (state, cityId) => {
+			state.cityId = cityId
+		},
+		SET_CITYOBJ: (state, cityObj) => {
+			state.cityObj = cityObj
+		}
+	}
+
+}
+
+export default cinema

+ 81 - 0
src/store/modules/user.js

@@ -0,0 +1,81 @@
+import userApi from '@/api/modules/user.js'
+
+const user = {
+	state: {
+		tokenObj: {
+			token: '',
+			date: 0
+		},
+		userInfo: '',
+		name: '',
+		avatar: '',
+		roles: [],
+		permissions: []
+	},
+	mutations: {
+		SET_TOKENOBJ: (state, tokenObj) => {
+			state.tokenObj = tokenObj
+		},
+		REFRESH_TOKEN(state) {
+			if (state.tokenObj.token !== '')
+				state.tokenObj.date = new Date().getTime()
+		},
+		SET_USERINFO: (state, userInfo) => {
+			state.userInfo = userInfo
+		},
+		SET_NAME: (state, name) => {
+			state.name = name
+		},
+		SET_AVATAR: (state, avatar) => {
+			state.avatar = avatar
+		},
+		SET_ROLES: (state, roles) => {
+			state.roles = roles
+		},
+		SET_PERMISSIONS: (state, permissions) => {
+			state.permissions = permissions
+		}
+	},
+	actions: {
+		/**
+		 * 用户登录储存token
+		 * @param {Object} store
+		 */
+		async Login(store) {
+			wx.showLoading({
+			  title: '登陆中...',
+			})
+			let res = await userApi.login()
+			store.commit('SET_TOKENOBJ', {
+				token: res.data.token,
+				date: new Date().getTime()
+			})
+			wx.hideLoading()
+			return res
+		},
+		async getToken(store) {
+			let tokenObj = store.state.tokenObj
+			if (new Date().getTime() - tokenObj.date < 1000 * 60 * 28) {
+				return tokenObj.token
+			} else {
+				let res = await store.dispatch("Login")
+				store.commit('SET_TOKENOBJ', {
+					token: res.data.token,
+					date: new Date().getTime()
+				})
+				return res.data.token
+			}
+		},
+		/**
+		 * 获取用户信息
+		 * @param {Object} store
+		 */
+		async GetInfo(store) {
+			let res = await userApi.getInfo()
+			store.commit('SET_USERINFO', res.data.student)
+			return res
+		}
+	}
+}
+
+export default user

+ 76 - 0
src/uni.scss

@@ -0,0 +1,76 @@
+/**
+ * 这里是uni-app内置的常用样式变量
+ *
+ * uni-app 官方扩展插件及插件市场(https://ext.dcloud.net.cn)上很多三方插件均使用了这些样式变量
+ * 如果你是插件开发者,建议你使用scss预处理,并在插件代码中直接使用这些变量(无需 import 这个文件),方便用户通过搭积木的方式开发整体风格一致的App
+ *
+ */
+
+/**
+ * 如果你是App开发者(插件使用者),你可以通过修改这些变量来定制自己的插件主题,实现自定义主题功能
+ *
+ * 如果你的项目同样使用了scss预处理,你也可以直接在你的 scss 代码中使用如下变量,同时无需 import 这个文件
+ */
+
+/* 颜色变量 */
+
+/* 行为相关颜色 */
+$uni-color-primary: #007aff;
+$uni-color-success: #4cd964;
+$uni-color-warning: #f0ad4e;
+$uni-color-error: #dd524d;
+
+/* 文字基本颜色 */
+$uni-text-color:#333;//基本色
+$uni-text-color-inverse:#fff;//反色
+$uni-text-color-grey:#999;//辅助灰色,如加载更多的提示信息
+$uni-text-color-placeholder: #808080;
+$uni-text-color-disable:#c0c0c0;
+
+/* 背景颜色 */
+$uni-bg-color:#ffffff;
+$uni-bg-color-grey:#f8f8f8;
+$uni-bg-color-hover:#f1f1f1;//点击状态颜色
+$uni-bg-color-mask:rgba(0, 0, 0, 0.4);//遮罩颜色
+
+/* 边框颜色 */
+$uni-border-color:#c8c7cc;
+
+/* 尺寸变量 */
+
+/* 文字尺寸 */
+$uni-font-size-sm:24rpx;
+$uni-font-size-base:28rpx;
+$uni-font-size-lg:32rpx;
+
+/* 图片尺寸 */
+$uni-img-size-sm:40rpx;
+$uni-img-size-base:52rpx;
+$uni-img-size-lg:80rpx;
+
+/* Border Radius */
+$uni-border-radius-sm: 4rpx;
+$uni-border-radius-base: 6rpx;
+$uni-border-radius-lg: 12rpx;
+$uni-border-radius-circle: 50%;
+
+/* 水平间距 */
+$uni-spacing-row-sm: 10px;
+$uni-spacing-row-base: 20rpx;
+$uni-spacing-row-lg: 30rpx;
+
+/* 垂直间距 */
+$uni-spacing-col-sm: 8rpx;
+$uni-spacing-col-base: 16rpx;
+$uni-spacing-col-lg: 24rpx;
+
+/* 透明度 */
+$uni-opacity-disabled: 0.3; // 组件禁用态的透明度
+
+/* 文章场景相关 */
+$uni-color-title: #2C405A; // 文章标题颜色
+$uni-font-size-title:40rpx;
+$uni-color-subtitle: #555555; // 二级标题颜色
+$uni-font-size-subtitle:36rpx;
+$uni-color-paragraph: #3F536E; // 文章段落颜色
+$uni-font-size-paragraph:30rpx;

+ 145 - 0
src/utils/index.js

@@ -0,0 +1,145 @@
+import applist from '@/api/modules/applist.js'
+import sha256 from 'crypto-js/sha256'
+import request from '@/api/request'
+import QRCode from 'qrcode'
+import dayjs from 'dayjs'
+import wxUtils from './modules/wx.js'
+import route from './modules/route.js'
+dayjs.locale('zh-cn')
+
+let goMiniAppFlag = false
+
+const utils = {
+	//生成二维码图片
+	async qrcodeGenerate(data) {
+		let qrcodeRes = await QRCode.toString(data, {
+			margin: 0,
+			errorCorrectionLevel: 'H'
+		});
+		return 'data:image/svg+xml;base64,' + Buffer(qrcodeRes).toString('base64');
+	},
+	//引入路由相关函数
+	route,
+	//引入微信相关utils
+	wxUtils,
+	//引入moment模块
+	dayjs,
+	//临时测试接口请求
+	testReq(data) {
+		return request(data)
+	},
+	
+	//vant通知组件调用函数
+	Toast(title) {
+		wx.showToast({
+			title,
+			icon: 'none'
+		})
+	},
+	//防抖函数
+	debounce(func, fnThis, wait) {
+		var timer;
+		return () => {
+			timer && clearTimeout(timer);
+			timer = setTimeout(() => {
+				func.call(fnThis)
+				timer = null
+			}, wait);
+		};
+	},
+	//节流函数
+	throttling(func, fnThis, wait) {
+		var timer;
+		return () => {
+			clearTimeout(timer);
+			timer = setTimeout(func.bind(fnThis), wait);
+		};
+	},
+	//跳转小程序
+	goMiniApp(data, item) {
+
+		if (goMiniAppFlag) return
+		goMiniAppFlag = true
+
+		let myData = JSON.parse(data)
+		wx.navigateToMiniProgram({
+			...myData,
+			success: (res) => {
+				// 打开成功
+				goMiniAppFlag = false
+				item && applist.BrowseRecordAdd(item.id)
+			},
+			fail: () => {
+				goMiniAppFlag = false
+			}
+		})
+
+	},
+	//跳转页面
+	goPage(url, type, data) {
+		if (type == 'reLaunch') {
+			uni.reLaunch({
+				url
+			});
+			return
+		}
+		if (type == 'redirectTo') {
+			uni.redirectTo({
+				url
+			});
+			return
+		}
+		uni.navigateTo({
+			url,
+			success: function(res) {
+				// 通过eventChannel向被打开页面传送数据
+				res.eventChannel.emit('passParameters', data)
+			}
+		});
+	},
+	//页面接受参数
+	goPageGetData() {
+		return new Promise((res) => {
+			const eventChannel = this.getOpenerEventChannel()
+			eventChannel.on('passParameters', function(data) {
+				res(data)
+			})
+		})
+	},
+	//返回今天明天后天周几
+	getDay(date) {
+		let UTCDay = new Date(date).getUTCDay()
+		let jetLag = new Date(date).getTime() - new Date().getTime()
+		let dayDif = jetLag / (1000 * 60 * 60 * 24)
+		if (dayDif < 2) {
+			if (dayDif < 0) {
+				return '今天'
+			}
+			if (dayDif < 1) {
+				return '明天'
+			}
+			if (dayDif < 2) {
+				return '后天'
+			}
+		}
+		switch (UTCDay) {
+			case 0:
+				return '周天';
+			case 1:
+				return '周一';
+			case 2:
+				return '周二';
+			case 3:
+				return '周三';
+			case 4:
+				return '周四';
+			case 5:
+				return '周五';
+			case 6:
+				return '周六';
+		}
+	}
+}
+
+
+export default utils

+ 68 - 0
src/utils/modules/route.js

@@ -0,0 +1,68 @@
+let goMiniAppFlag = false
+
+const route = {
+	//跳转小程序
+	goMiniApp(data, item) {
+		if (goMiniAppFlag) return
+		goMiniAppFlag = true
+		let myData = JSON.parse(data)
+		wx.navigateToMiniProgram({
+			...myData,
+			success: (res) => {
+				// 打开成功
+				goMiniAppFlag = false
+				item && applist.BrowseRecordAdd(item.id)
+			},
+			fail: () => {
+				goMiniAppFlag = false
+			}
+		})
+
+	},
+	//跳转页面
+	goPage(url, type, data) {
+		if (type == 'reLaunch') {
+			uni.reLaunch({
+				url
+			});
+			return
+		}
+		if (type == 'redirectTo') {
+			uni.redirectTo({
+				url
+			});
+			return
+		}
+		uni.navigateTo({
+			url,
+			success: function(res) {
+				// 通过eventChannel向被打开页面传送数据
+				res.eventChannel.emit('passParameters', data)
+			}
+		});
+	},
+	//页面接受参数
+	goPageGetData() {
+		return new Promise((res) => {
+			const eventChannel = this.getOpenerEventChannel()
+			eventChannel.on('passParameters', function(data) {
+				res(data)
+			})
+		})
+	},
+	//根据类型跳转
+	clickJumpType(item) {
+		console.log(item)
+		if (item.jumpUrlType == 'goMiniApp') {
+			route.goMiniApp(item.jumpUrl)
+		}
+		if (item.jumpUrlType == 'goPage') {
+			route.goPage(item.jumpUrl)
+		}
+		if (item.jumpUrlType == 'goWebView') {
+			route.goPage(`/pages/webview/webview?src=${item.jumpUrl}`)
+		}
+	},
+}
+
+export default route

+ 43 - 0
src/utils/modules/wx.js

@@ -0,0 +1,43 @@
+const wxUtils={
+	//微信支付调起支付
+	wxPay(data) {
+		wx.requestPayment({
+			...data
+		})
+	},
+	//订阅消息
+	subscribeToNews() {
+		return wx.requestSubscribeMessage({
+			tmplIds: ['Q4-tQrDwtzFUSLt_PR2kuTxBJ3d62V4Yp2iwx4PAcIE']
+		})
+	},
+	//激励广告唤起函数
+	incentiveAd() {
+		// 在页面中定义激励视频广告
+		let videoAd = null
+	
+		// 在页面onLoad回调事件中创建激励视频广告实例
+		if (wx.createRewardedVideoAd) {
+			videoAd = wx.createRewardedVideoAd({
+				adUnitId: 'adunit-5be2b5bf54eae38e'
+			})
+			videoAd.onLoad(() => {})
+			videoAd.onError((err) => {})
+			videoAd.onClose((res) => {})
+		}
+	
+		// 用户触发广告后,显示激励视频广告
+		if (videoAd) {
+			videoAd.show().catch(() => {
+				// 失败重试
+				videoAd.load()
+					.then(() => videoAd.show())
+					.catch(err => {
+						console.log('激励视频 广告显示失败')
+					})
+			})
+		}
+	},
+}
+
+export default wxUtils

+ 1 - 0
src/wxcomponents/vant/action-sheet/index.d.ts

@@ -0,0 +1 @@
+export {};

+ 62 - 0
src/wxcomponents/vant/action-sheet/index.js

@@ -0,0 +1,62 @@
+import { VantComponent } from '../common/component';
+import { button } from '../mixins/button';
+import { openType } from '../mixins/open-type';
+VantComponent({
+  mixins: [button, openType],
+  props: {
+    show: Boolean,
+    title: String,
+    cancelText: String,
+    description: String,
+    round: {
+      type: Boolean,
+      value: true,
+    },
+    zIndex: {
+      type: Number,
+      value: 100,
+    },
+    actions: {
+      type: Array,
+      value: [],
+    },
+    overlay: {
+      type: Boolean,
+      value: true,
+    },
+    closeOnClickOverlay: {
+      type: Boolean,
+      value: true,
+    },
+    closeOnClickAction: {
+      type: Boolean,
+      value: true,
+    },
+    safeAreaInsetBottom: {
+      type: Boolean,
+      value: true,
+    },
+  },
+  methods: {
+    onSelect(event) {
+      const { index } = event.currentTarget.dataset;
+      const item = this.data.actions[index];
+      if (item && !item.disabled && !item.loading) {
+        this.$emit('select', item);
+        if (this.data.closeOnClickAction) {
+          this.onClose();
+        }
+      }
+    },
+    onCancel() {
+      this.$emit('cancel');
+    },
+    onClose() {
+      this.$emit('close');
+    },
+    onClickOverlay() {
+      this.$emit('click-overlay');
+      this.onClose();
+    },
+  },
+});

+ 8 - 0
src/wxcomponents/vant/action-sheet/index.json

@@ -0,0 +1,8 @@
+{
+  "component": true,
+  "usingComponents": {
+    "van-icon": "../icon/index",
+    "van-popup": "../popup/index",
+    "van-loading": "../loading/index"
+  }
+}

+ 69 - 0
src/wxcomponents/vant/action-sheet/index.wxml

@@ -0,0 +1,69 @@
+<wxs src="../wxs/utils.wxs" module="utils" />
+
+<van-popup
+  show="{{ show }}"
+  position="bottom"
+  round="{{ round }}"
+  z-index="{{ zIndex }}"
+  overlay="{{ overlay }}"
+  custom-class="van-action-sheet"
+  safe-area-inset-bottom="{{ safeAreaInsetBottom }}"
+  close-on-click-overlay="{{ closeOnClickOverlay }}"
+  bind:close="onClickOverlay"
+>
+  <view wx:if="{{ title }}" class="van-action-sheet__header">
+    {{ title }}
+    <van-icon
+      name="cross"
+      custom-class="van-action-sheet__close"
+      bind:click="onClose"
+    />
+  </view>
+  <view wx:if="{{ description }}" class="van-action-sheet__description van-hairline--bottom">
+    {{ description }}
+  </view>
+  <view wx:if="{{ actions && actions.length }}">
+    <!-- button外包一层view,防止actions动态变化,导致渲染时button被打散 -->
+    <button
+      wx:for="{{ actions }}"
+      wx:key="index"
+      open-type="{{ item.openType }}"
+      style="{{ item.color ? 'color: ' + item.color : '' }}"
+      class="{{ utils.bem('action-sheet__item', { disabled: item.disabled || item.loading }) }} {{ item.className || '' }}"
+      hover-class="van-action-sheet__item--hover"
+      data-index="{{ index }}"
+      bind:tap="onSelect"
+      bindgetuserinfo="bindGetUserInfo"
+      bindcontact="bindContact"
+      bindgetphonenumber="bindGetPhoneNumber"
+      binderror="bindError"
+      bindlaunchapp="bindLaunchApp"
+      bindopensetting="bindOpenSetting"
+      lang="{{ lang }}"
+      session-from="{{ sessionFrom }}"
+      send-message-title="{{ sendMessageTitle }}"
+      send-message-path="{{ sendMessagePath }}"
+      send-message-img="{{ sendMessageImg }}"
+      show-message-card="{{ showMessageCard }}"
+      app-parameter="{{ appParameter }}"
+    >
+      <block wx:if="{{ !item.loading }}">
+        {{ item.name }}
+        <view wx:if="{{ item.subname }}" class="van-action-sheet__subname" >{{ item.subname }}</view>
+      </block>
+      <van-loading wx:else custom-class="van-action-sheet__loading" size="22px" />
+    </button>
+  </view>
+  <slot />
+  <block wx:if="{{ cancelText }}">
+    <view class="van-action-sheet__gap" />
+    <view
+      class="van-action-sheet__cancel"
+      hover-class="van-action-sheet__cancel--hover"
+      hover-stay-time="70"
+      bind:tap="onCancel"
+    >
+      {{ cancelText }}
+    </view>
+  </block>
+</van-popup>

Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 0 - 0
src/wxcomponents/vant/action-sheet/index.wxss


+ 1 - 0
src/wxcomponents/vant/area/index.d.ts

@@ -0,0 +1 @@
+export {};

+ 232 - 0
src/wxcomponents/vant/area/index.js

@@ -0,0 +1,232 @@
+import { VantComponent } from '../common/component';
+import { pickerProps } from '../picker/shared';
+import { requestAnimationFrame } from '../common/utils';
+const EMPTY_CODE = '000000';
+VantComponent({
+  classes: ['active-class', 'toolbar-class', 'column-class'],
+  props: Object.assign(Object.assign({}, pickerProps), {
+    value: {
+      type: String,
+      observer(value) {
+        this.code = value;
+        this.setValues();
+      },
+    },
+    areaList: {
+      type: Object,
+      value: {},
+      observer: 'setValues',
+    },
+    columnsNum: {
+      type: null,
+      value: 3,
+    },
+    columnsPlaceholder: {
+      type: Array,
+      observer(val) {
+        this.setData({
+          typeToColumnsPlaceholder: {
+            province: val[0] || '',
+            city: val[1] || '',
+            county: val[2] || '',
+          },
+        });
+      },
+    },
+  }),
+  data: {
+    columns: [{ values: [] }, { values: [] }, { values: [] }],
+    typeToColumnsPlaceholder: {},
+  },
+  mounted() {
+    requestAnimationFrame(() => {
+      this.setValues();
+    });
+  },
+  methods: {
+    getPicker() {
+      if (this.picker == null) {
+        this.picker = this.selectComponent('.van-area__picker');
+      }
+      return this.picker;
+    },
+    onCancel(event) {
+      this.emit('cancel', event.detail);
+    },
+    onConfirm(event) {
+      const { index } = event.detail;
+      let { value } = event.detail;
+      value = this.parseValues(value);
+      this.emit('confirm', { value, index });
+    },
+    emit(type, detail) {
+      detail.values = detail.value;
+      delete detail.value;
+      this.$emit(type, detail);
+    },
+    parseValues(values) {
+      const { columnsPlaceholder } = this.data;
+      return values.map((value, index) => {
+        if (
+          value &&
+          (!value.code || value.name === columnsPlaceholder[index])
+        ) {
+          return Object.assign(Object.assign({}, value), {
+            code: '',
+            name: '',
+          });
+        }
+        return value;
+      });
+    },
+    onChange(event) {
+      const { index, picker, value } = event.detail;
+      this.code = value[index].code;
+      this.setValues().then(() => {
+        this.$emit('change', {
+          picker,
+          values: this.parseValues(picker.getValues()),
+          index,
+        });
+      });
+    },
+    getConfig(type) {
+      const { areaList } = this.data;
+      return (areaList && areaList[`${type}_list`]) || {};
+    },
+    getList(type, code) {
+      if (type !== 'province' && !code) {
+        return [];
+      }
+      const { typeToColumnsPlaceholder } = this.data;
+      const list = this.getConfig(type);
+      let result = Object.keys(list).map((code) => ({
+        code,
+        name: list[code],
+      }));
+      if (code != null) {
+        // oversea code
+        if (code[0] === '9' && type === 'city') {
+          code = '9';
+        }
+        result = result.filter((item) => item.code.indexOf(code) === 0);
+      }
+      if (typeToColumnsPlaceholder[type] && result.length) {
+        // set columns placeholder
+        const codeFill =
+          type === 'province'
+            ? ''
+            : type === 'city'
+            ? EMPTY_CODE.slice(2, 4)
+            : EMPTY_CODE.slice(4, 6);
+        result.unshift({
+          code: `${code}${codeFill}`,
+          name: typeToColumnsPlaceholder[type],
+        });
+      }
+      return result;
+    },
+    getIndex(type, code) {
+      let compareNum = type === 'province' ? 2 : type === 'city' ? 4 : 6;
+      const list = this.getList(type, code.slice(0, compareNum - 2));
+      // oversea code
+      if (code[0] === '9' && type === 'province') {
+        compareNum = 1;
+      }
+      code = code.slice(0, compareNum);
+      for (let i = 0; i < list.length; i++) {
+        if (list[i].code.slice(0, compareNum) === code) {
+          return i;
+        }
+      }
+      return 0;
+    },
+    setValues() {
+      const picker = this.getPicker();
+      if (!picker) {
+        return;
+      }
+      let code = this.code || this.getDefaultCode();
+      const provinceList = this.getList('province');
+      const cityList = this.getList('city', code.slice(0, 2));
+      const stack = [];
+      const indexes = [];
+      const { columnsNum } = this.data;
+      if (columnsNum >= 1) {
+        stack.push(picker.setColumnValues(0, provinceList, false));
+        indexes.push(this.getIndex('province', code));
+      }
+      if (columnsNum >= 2) {
+        stack.push(picker.setColumnValues(1, cityList, false));
+        indexes.push(this.getIndex('city', code));
+        if (cityList.length && code.slice(2, 4) === '00') {
+          [{ code }] = cityList;
+        }
+      }
+      if (columnsNum === 3) {
+        stack.push(
+          picker.setColumnValues(
+            2,
+            this.getList('county', code.slice(0, 4)),
+            false
+          )
+        );
+        indexes.push(this.getIndex('county', code));
+      }
+      return Promise.all(stack)
+        .catch(() => {})
+        .then(() => picker.setIndexes(indexes))
+        .catch(() => {});
+    },
+    getDefaultCode() {
+      const { columnsPlaceholder } = this.data;
+      if (columnsPlaceholder.length) {
+        return EMPTY_CODE;
+      }
+      const countyCodes = Object.keys(this.getConfig('county'));
+      if (countyCodes[0]) {
+        return countyCodes[0];
+      }
+      const cityCodes = Object.keys(this.getConfig('city'));
+      if (cityCodes[0]) {
+        return cityCodes[0];
+      }
+      return '';
+    },
+    getValues() {
+      const picker = this.getPicker();
+      if (!picker) {
+        return [];
+      }
+      return this.parseValues(picker.getValues().filter((value) => !!value));
+    },
+    getDetail() {
+      const values = this.getValues();
+      const area = {
+        code: '',
+        country: '',
+        province: '',
+        city: '',
+        county: '',
+      };
+      if (!values.length) {
+        return area;
+      }
+      const names = values.map((item) => item.name);
+      area.code = values[values.length - 1].code;
+      if (area.code[0] === '9') {
+        area.country = names[1] || '';
+        area.province = names[2] || '';
+      } else {
+        area.province = names[0] || '';
+        area.city = names[1] || '';
+        area.county = names[2] || '';
+      }
+      return area;
+    },
+    reset(code) {
+      this.code = code || '';
+      return this.setValues();
+    },
+  },
+});

+ 6 - 0
src/wxcomponents/vant/area/index.json

@@ -0,0 +1,6 @@
+{
+  "component": true,
+  "usingComponents": {
+    "van-picker": "../picker/index"
+  }
+}

+ 20 - 0
src/wxcomponents/vant/area/index.wxml

@@ -0,0 +1,20 @@
+<wxs src="./index.wxs" module="computed" />
+
+<van-picker
+  class="van-area__picker"
+  active-class="active-class"
+  toolbar-class="toolbar-class"
+  column-class="column-class"
+  show-toolbar
+  value-key="name"
+  title="{{ title }}"
+  loading="{{ loading }}"
+  columns="{{ computed.displayColumns(columns, columnsNum) }}"
+  item-height="{{ itemHeight }}"
+  visible-item-count="{{ visibleItemCount }}"
+  cancel-button-text="{{ cancelButtonText }}"
+  confirm-button-text="{{ confirmButtonText }}"
+  bind:change="onChange"
+  bind:confirm="onConfirm"
+  bind:cancel="onCancel"
+/>

+ 8 - 0
src/wxcomponents/vant/area/index.wxs

@@ -0,0 +1,8 @@
+/* eslint-disable */
+function displayColumns(columns, columnsNum) {
+  return columns.slice(0, +columnsNum);
+}
+
+module.exports = {
+  displayColumns: displayColumns,
+};

Některé soubory nejsou zobrazeny, neboť je v těchto rozdílových datech změněno mnoho souborů