zhuangyunsheng пре 1 месец
родитељ
комит
a7d4cc668a
100 измењених фајлова са 11461 додато и 0 уклоњено
  1. 65 0
      .gitignore
  2. 0 0
      README.md
  3. 56 0
      app.js
  4. 88 0
      app.json
  5. 200 0
      app.wxss
  6. 26 0
      config/api.js
  7. 10 0
      config/config.js
  8. 41 0
      lib/login-agreement/index.js
  9. 7 0
      lib/login-agreement/index.json
  10. 9 0
      lib/login-agreement/index.wxml
  11. 40 0
      lib/login-agreement/index.wxss
  12. 43 0
      lib/navbar/index.js
  13. 3 0
      lib/navbar/index.json
  14. 6 0
      lib/navbar/index.wxml
  15. 20 0
      lib/navbar/index.wxss
  16. 67 0
      lib/spec-popup/index.js
  17. 6 0
      lib/spec-popup/index.json
  18. 26 0
      lib/spec-popup/index.wxml
  19. 100 0
      lib/spec-popup/index.wxss
  20. 242 0
      lib/wxParse/html2json.js
  21. 182 0
      lib/wxParse/htmlparser.js
  22. 2529 0
      lib/wxParse/showdown.js
  23. 206 0
      lib/wxParse/wxDiscode.js
  24. 146 0
      lib/wxParse/wxParse.js
  25. 928 0
      lib/wxParse/wxParse.wxml
  26. 214 0
      lib/wxParse/wxParse.wxss
  27. 5 0
      package.json
  28. 157 0
      packageGoods/detail/detail.js
  29. 6 0
      packageGoods/detail/detail.json
  30. 58 0
      packageGoods/detail/detail.wxml
  31. 156 0
      packageGoods/detail/detail.wxss
  32. BIN
      packageGoods/detail/icon_share.png
  33. 47 0
      packageLogin/login/login.js
  34. 6 0
      packageLogin/login/login.json
  35. 9 0
      packageLogin/login/login.wxml
  36. 39 0
      packageLogin/login/login.wxss
  37. BIN
      packagePoster/images/bg.png
  38. BIN
      packagePoster/images/door-left.png
  39. BIN
      packagePoster/images/door-right.png
  40. 71 0
      packagePoster/index.js
  41. 4 0
      packagePoster/index.json
  42. 33 0
      packagePoster/index.wxml
  43. 183 0
      packagePoster/index.wxss
  44. BIN
      packagePosterImg/images/bg.png
  45. BIN
      packagePosterImg/images/door-left.png
  46. BIN
      packagePosterImg/images/door-right.png
  47. 12 0
      packagePosterImg/index.js
  48. 4 0
      packagePosterImg/index.json
  49. 12 0
      packagePosterImg/index.wxml
  50. 48 0
      packagePosterImg/index.wxss
  51. 84 0
      packageUser/collect/collect.js
  52. 7 0
      packageUser/collect/collect.json
  53. 30 0
      packageUser/collect/collect.wxml
  54. 94 0
      packageUser/collect/collect.wxss
  55. BIN
      packageUser/collect/empty_collect.png
  56. 85 0
      packageUser/footprint/footprint.js
  57. 7 0
      packageUser/footprint/footprint.json
  58. 33 0
      packageUser/footprint/footprint.wxml
  59. 95 0
      packageUser/footprint/footprint.wxss
  60. BIN
      packageUser/footprint/meizhuang.png
  61. 79 0
      packageUser/information/information.js
  62. 4 0
      packageUser/information/information.json
  63. 25 0
      packageUser/information/information.wxml
  64. 101 0
      packageUser/information/information.wxss
  65. 34 0
      packageUser/mobileModify/mobileModify.js
  66. 6 0
      packageUser/mobileModify/mobileModify.json
  67. 4 0
      packageUser/mobileModify/mobileModify.wxml
  68. 24 0
      packageUser/mobileModify/mobileModify.wxss
  69. 35 0
      packageUser/nickNameModify/nickNameModify.js
  70. 6 0
      packageUser/nickNameModify/nickNameModify.json
  71. 5 0
      packageUser/nickNameModify/nickNameModify.wxml
  72. 24 0
      packageUser/nickNameModify/nickNameModify.wxss
  73. 94 0
      pages/catalog/catalog.js
  74. 6 0
      pages/catalog/catalog.json
  75. 24 0
      pages/catalog/catalog.wxml
  76. 145 0
      pages/catalog/catalog.wxss
  77. 131 0
      pages/index/index.js
  78. 8 0
      pages/index/index.json
  79. 58 0
      pages/index/index.wxml
  80. 215 0
      pages/index/index.wxss
  81. 73 0
      pages/user/index.js
  82. 6 0
      pages/user/index.json
  83. 26 0
      pages/user/index.wxml
  84. 75 0
      pages/user/index.wxss
  85. 69 0
      project.config.json
  86. 25 0
      project.private.config.json
  87. 21 0
      sitemap.json
  88. 3512 0
      static/css/animate.wxss
  89. 16 0
      static/css/guildford.wxss
  90. 48 0
      static/css/login.wxss
  91. 17 0
      static/font/iconfont.wxss
  92. BIN
      static/images/avatar.png
  93. BIN
      static/images/category.png
  94. BIN
      static/images/category@selected.png
  95. BIN
      static/images/empty_goods.png
  96. BIN
      static/images/home.png
  97. BIN
      static/images/home@selected.png
  98. BIN
      static/images/icon_close.png
  99. BIN
      static/images/icon_search_black.png
  100. 0 0
      static/images/index_shangcheng.png

+ 65 - 0
.gitignore

@@ -0,0 +1,65 @@
+
+######################################################################
+# custom 
+crm-admin.jar
+
+######################################################################
+# Build Tools
+
+.gradle
+/build/
+!gradle/wrapper/gradle-wrapper.jar
+
+target/
+!.mvn/wrapper/maven-wrapper.jar
+
+######################################################################
+# IDE
+
+### STS ###
+.apt_generated
+.classpath
+.factorypath
+.project
+.settings
+.springBeans
+
+### IntelliJ IDEA ###
+.idea
+*.iws
+*.iml
+*.ipr
+
+### NetBeans ###
+nbproject/private/
+build/*
+nbbuild/
+dist/
+nbdist/
+.nb-gradle/
+
+######################################################################
+# Others
+*.log
+*.xml.versionsBackup
+*.zip
+
+!*/build/*.java
+!*/build/*.html
+!*/build/*.xml
+
+dist
+node_modules
+.DS_Store
+.java-version
+package-lock.json
+logs
+
+.vscode/
+
+dist
+dist.tar.gz
+dist.zip
+
+miniprogram_npm
+


+ 56 - 0
app.js

@@ -0,0 +1,56 @@
+let util = require('./utils/util')
+
+App({
+  globalData: {},
+
+  onLaunch: function() {
+		this.checkVersion()
+	},
+
+  onShow() {
+		this.getNavHeight()
+	},
+
+	checkVersion() {
+		if (!wx.canIUse('getUpdateManager')) return wx.showModal({ title: '提示', content: '当前微信版本过低,无法使用该功能,请升级到最新微信版本后重试' })
+		const updateManager = wx.getUpdateManager()
+		updateManager.onCheckForUpdate(res => {
+			if (res.hasUpdate) {
+				wx.showModal({
+					title: '更新提示',
+					content: '检测到新版本,是否下载新版本并重启小程序',
+					success: res => {
+						if (res.confirm) {
+							util.showLoad('下载中')
+							updateManager.onUpdateReady(() => {
+								util.hideLoad()
+								updateManager.applyUpdate()
+							})
+              updateManager.onUpdateFailed(() => {
+								util.hideLoad()
+                wx.showModal({ title: '已有新版本', content: '新版本已经上线了,请删除当前小程序,重新搜索打开' })
+              })
+						}
+					}
+				})
+			}
+		})
+	},
+
+  // 获取导航栏高度
+  getNavHeight() {
+    const menu_btn = wx.getMenuButtonBoundingClientRect()
+    wx.getSystemInfo({
+      success: res => {
+        const statusBar_h = res.statusBarHeight
+        const nav_top = menu_btn.top - statusBar_h
+        const nav_height = statusBar_h + menu_btn.height + nav_top * 2
+        this.globalData.menuBtnHeight = menu_btn.height
+        this.globalData.navHeight = nav_height
+        this.globalData.navTop = nav_top
+        this.globalData.screenHeight = res.screenHeight
+      },
+      fail: () => setTimeout(() => this.getNavHeight(),1000)
+    })
+	}
+})

+ 88 - 0
app.json

@@ -0,0 +1,88 @@
+{
+	"pages": [
+		"pages/index/index",
+		"pages/catalog/catalog",
+		"pages/user/index"
+	],
+	"subPackages": [{
+			"root": "packageLogin",
+			"pages": [
+				"login/login"
+			]
+		},
+		{
+			"root": "packageGoods",
+			"pages": [
+				"detail/detail"
+			]
+		},
+		{
+			"root": "packageUser",
+			"pages": [
+				"information/information",
+				"nickNameModify/nickNameModify",
+				"mobileModify/mobileModify",
+
+				"collect/collect",
+				"footprint/footprint"
+			]
+		},
+		{
+			"root": "packagePoster",
+			"pages": [
+				"index"
+			]
+		},
+		{
+			"root": "packagePosterImg",
+			"pages": [
+				"index"
+			]
+		}
+		
+	],
+	"window": {
+		"navigationBarBackgroundColor": "#fff",
+		"navigationBarTextStyle": "black",
+		"backgroundColor": "#F5F5F5",
+		"backgroundTextStyle": "dark"
+	},
+	"tabBar": {
+		"backgroundColor": "#fff",
+		"borderStyle": "white",
+		"selectedColor": "#D32D2F",
+		"color": "#50555F",
+		"list": [{
+				"pagePath": "pages/index/index",
+				"iconPath": "static/images/home.png",
+				"selectedIconPath": "static/images/home@selected.png",
+				"text": "首页"
+			},
+			{
+				"pagePath": "pages/catalog/catalog",
+				"iconPath": "static/images/category.png",
+				"selectedIconPath": "static/images/category@selected.png",
+				"text": "分类"
+			},
+			{
+				"pagePath": "pages/user/index",
+				"iconPath": "static/images/my.png",
+				"selectedIconPath": "static/images/my@selected.png",
+				"text": "我的"
+			}
+		]
+	},
+	"networkTimeout": {
+		"request": 10000,
+		"connectSocket": 10000,
+		"uploadFile": 10000,
+		"downloadFile": 10000
+	},
+	"debug": false,
+	"sitemapLocation": "sitemap.json",
+	"requiredBackgroundModes": ["audio", "location"],
+	"usingComponents": {
+		"van-icon": "@vant/weapp/icon/index",
+		"van-empty": "@vant/weapp/empty/index"
+	}
+}

+ 200 - 0
app.wxss

@@ -0,0 +1,200 @@
+/**app.wxss**/
+@import '/static/font/iconfont.wxss';
+@import '/static/css/animate.wxss';
+
+view,
+image,
+text,
+navigator {
+	box-sizing: border-box;
+	padding: 0;
+	margin: 0;
+}
+
+page {
+	background-color: #f5f5f5;
+	font-size: 28rpx;
+	font-family: HarmonyOS Sans SC-Regular, HarmonyOS Sans SC;
+	font-weight: 400;
+	color: #333;
+}
+
+.jhx_bg0 {
+	background: #fff;
+}
+
+.acea-row {
+	display: flex;
+	flex-wrap: wrap;
+}
+
+.acea-row.row-top {
+	align-items: flex-start;
+}
+
+.acea-row.row-middle {
+	align-items: center;
+}
+
+.acea-row.row-bottom {
+	align-items: flex-end;
+}
+
+.acea-row.row-left {
+	justify-content: flex-start;
+}
+
+.acea-row.row-center {
+	justify-content: center;
+}
+
+.acea-row.row-right {
+	justify-content: flex-end;
+}
+
+.acea-row.row-between {
+	justify-content: space-between;
+}
+
+.acea-row.row-around {
+	justify-content: space-around;
+}
+
+.acea-row.row-evenly {
+	justify-content: space-evenly;
+}
+
+.acea-row.row-column {
+	flex-direction: column;
+}
+
+.acea-row.row-column-between {
+	flex-direction: column;
+	justify-content: space-between;
+}
+
+.acea-row.row-column-around {
+	flex-direction: column;
+	justify-content: space-around;
+}
+
+.acea-row.row-center-wrapper {
+	align-items: center;
+	justify-content: center;
+}
+
+.acea-row.row-between-wrapper {
+	align-items: center;
+	justify-content: space-between;
+}
+
+.line1 {
+	overflow: hidden;
+	text-overflow: ellipsis;
+	white-space: nowrap;
+}
+
+.line2 {
+	word-break: break-all;
+	display: -webkit-box;
+	-webkit-line-clamp: 2;
+	-webkit-box-orient: vertical;
+	white-space: normal;
+}
+
+@keyframes load {
+	from {
+		transform: rotate(0deg);
+	}
+
+	to {
+		transform: rotate(360deg);
+	}
+}
+
+@keyframes show {
+	0% { opacity: 0; }
+	100% { opacity: 1; }
+}
+
+@keyframes hide {
+	0% { opacity: 1; }
+	100% { opacity: 0; }
+}
+
+@keyframes left-open {
+	from { transform: rotateY(0deg); }
+	to { transform: rotateY(-130deg); }
+}
+
+@keyframes right-open {
+	from { transform: rotateY(0deg); }
+	to { transform: rotateY(130deg); }
+}
+
+@keyframes left-close {
+	from { transform: rotateY(-130deg); }
+	to { transform: rotateY(0deg); }
+}
+
+@keyframes right-close {
+	from { transform: rotateY(130deg); }
+	to { transform: rotateY(0deg); }
+}
+
+@keyframes signInBtn {
+  0% { transform: scale(1); }
+  50% { transform: scale(1.2); }
+  100% { transform: scale(1); }
+}
+
+.share-btn {
+	margin: 0;
+	padding: 0;
+	background-color: transparent;
+}
+
+.share-btn::after {
+	border: 0;
+}
+
+.van-popup {
+	width: 80%;
+	height: 50%;
+	border-radius: 12rpx;
+	line-height: 40rpx;
+}
+
+.van-popup.van-popup--bottom {
+	border-radius: 12rpx 12rpx 0 0;
+}
+
+.van-popup .title {
+	padding: 30rpx 0;
+	border-bottom: 2rpx solid rgba(110, 123, 143, 0.16);
+	text-align: center;
+	font-size: 32rpx;
+	font-weight: 500;
+	font-family: HarmonyOS Sans SC-Medium, HarmonyOS Sans SC;
+	color: #060606;
+}
+
+.van-popup .scroll-y {
+	height: calc(100% - 102rpx);
+}
+
+.van-popup .btn {
+	width: calc(100% - 48rpx);
+	position: fixed;
+	bottom: 56rpx;
+	background: #D32D2F;
+	border-radius: 90rpx;
+	text-align: center;
+	line-height: 80rpx;
+	font-size: 28rpx;
+	color: #fff;
+}
+
+.van-empty {
+	min-height: 960rpx;
+}

+ 26 - 0
config/api.js

@@ -0,0 +1,26 @@
+const { WxApiRoot } = require('./config')
+
+module.exports = {
+	GetSessionKey: WxApiRoot + 'auth/jscode2session', // 获取session_key unionId/openid
+  LoginByWeixin: WxApiRoot + 'auth/loginByWeixin', // 微信登录
+  Logout: WxApiRoot + 'auth/logout', // 账号登出
+
+	UserIndex: WxApiRoot + 'user/index', // 我的
+	UserInfo: WxApiRoot + 'user/getById', // 个人信息
+	UserUpdate: WxApiRoot + 'user/updateUser', // 修改我的信息
+
+	CollectList: WxApiRoot + 'collect/list', // 收藏/订阅列表
+  CollectAdd: WxApiRoot + 'collect/add', // 收藏
+	CollectDelete: WxApiRoot + 'collect/delete', // 取消收藏
+	FootprintList: WxApiRoot + 'footprint/list', // 足迹列表
+	FootprintDelete: WxApiRoot + 'footprint/delete', // 删除足迹
+	AddBrowse: WxApiRoot + 'browse/add', // 新增足迹
+
+  IndexUrl: WxApiRoot + 'home/index', // 首页数据接口
+  GetfloorGoods: WxApiRoot + 'home/floorGoodsList', // 首页底部分类商品
+
+  CatalogList: WxApiRoot + 'catalog/index', // 分类左侧一级目录
+  CatalogGoodsList: WxApiRoot + 'catalog/goodsList', // 分类商品
+  
+	GoodsDetail: WxApiRoot + 'goods/detail', // 商品详情
+}

+ 10 - 0
config/config.js

@@ -0,0 +1,10 @@
+// 部署api地址
+const WxApiRoot = 'http://192.168.101.251:8081/wx/'
+// const WxApiRoot = 'https://www.qdeasydo.com/wx/'
+
+// 用户协议
+const userAgreement = 'https://www.qdeasydo.com/api/folder/b1acd65d-28bc-4080-8d80-50e58b9cce3a'
+// 隐私政策
+const privacyPolicy = 'https://www.qdeasydo.com/api/folder/ce650251-5096-4210-94b9-d0c41eb37809'
+
+module.exports = { WxApiRoot, userAgreement, privacyPolicy }

+ 41 - 0
lib/login-agreement/index.js

@@ -0,0 +1,41 @@
+const config = require('../../config/config')
+const util = require('../../utils/util')
+const download = require('../../utils/download')
+
+Component({
+  properties: {
+    // 是否同意协议
+    read: {
+      type: Boolean,
+      value: false
+    },
+    // 是否显示气泡
+    show: {
+      type: Boolean,
+      value: false
+    }
+  },
+
+  data: {},
+
+  lifetimes: {
+    // 在组件实例进入页面节点树时执行
+    attached: function() {},
+    // 在组件实例被从页面节点树移除时执行
+    detached: function() {}
+  },
+
+  methods: {
+    toggleRead({ detail }) {
+      if (detail) this.triggerEvent('hidePopover')
+      this.triggerEvent('toggleRead', detail)
+		},
+		
+		showAgreement({ currentTarget }) {
+			const { type } =	currentTarget.dataset
+			const url = type == 'user' ? config.userAgreement : config.privacyPolicy
+			util.showLoad('加载中')
+			download.openAgreement(url).then(() => util.hideLoad()).catch(() => util.hideLoad())
+		}
+  }
+})

+ 7 - 0
lib/login-agreement/index.json

@@ -0,0 +1,7 @@
+{
+  "usingComponents": {
+    "van-checkbox": "@vant/weapp/checkbox/index",
+    "van-transition": "@vant/weapp/transition/index"
+  },
+  "component": true
+}

+ 9 - 0
lib/login-agreement/index.wxml

@@ -0,0 +1,9 @@
+<view class="login-agreement">
+	<van-transition wx:if="{{ show }}" name="fade">
+		<view class="popover">请阅读并勾选用户协议</view>
+	</van-transition>
+	<van-checkbox label-class="label" value="{{ read }}" icon-size="12" checked-color="#D32D2F" bind:change="toggleRead">已阅读并同意
+		<text class="agreement" data-type="user" catchtap="showAgreement">《用户协议》</text>
+		<text class="agreement" data-type="privacy" catchtap="showAgreement">《隐私政策》</text>
+	</van-checkbox>
+</view>

+ 40 - 0
lib/login-agreement/index.wxss

@@ -0,0 +1,40 @@
+.login-agreement {
+  position: fixed;
+  bottom: 80rpx;
+  left: 110rpx;
+}
+
+.popover {
+  position: relative;
+  left: -20rpx;
+  top: -32rpx;
+  width: 344rpx;
+  background: rgba(50, 50, 51, 0.9);
+  border-radius: 8rpx;
+  text-align: center;
+  line-height: 68rpx;
+  font-family: PingFang SC-Regular, PingFang SC;
+  color: #fff;
+}
+
+.popover::after {
+  position: absolute;
+  bottom: -12rpx;
+  left: 20rpx;
+  content: '';
+  width: 0;
+  height: 0;
+  border-left: 12rpx solid transparent;
+  border-right: 12rpx solid transparent;
+  border-top: 12rpx solid rgba(50, 50, 51, 0.9);
+}
+
+.label {
+  line-height: 28rpx;
+  font-size: 24rpx;
+  color: #999;
+}
+
+.agreement {
+  color: #060606;
+}

+ 43 - 0
lib/navbar/index.js

@@ -0,0 +1,43 @@
+const app = getApp()
+
+Component({
+  properties: {
+    // 导航栏标题
+    name: {
+      type: String,
+      value: ''
+    },
+    // 是否显示返回按钮
+    is_back: {
+      type: Boolean,
+      value: true
+		},
+    // 是否固定导航栏
+		fixed: {
+			type: Boolean,
+      value: false
+		}
+  },
+
+  data: {
+  },
+
+  lifetimes: {
+    // 在组件实例进入页面节点树时执行
+    attached: function() {
+      this.setData({
+        menuBtnHeight: app.globalData.menuBtnHeight,
+        navHeight: app.globalData.navHeight,
+        navTop: app.globalData.navTop
+      })
+    },
+    // 在组件实例被从页面节点树移除时执行
+    detached: function() {}
+  },
+
+  methods: {
+    navBack() {
+      wx.navigateBack()
+    }
+  }
+})

+ 3 - 0
lib/navbar/index.json

@@ -0,0 +1,3 @@
+{
+  "component": true
+}

+ 6 - 0
lib/navbar/index.wxml

@@ -0,0 +1,6 @@
+<view style="height: {{ navHeight }}px;" class="nav-bar">
+   <view style="height: {{ menuBtnHeight }}px; bottom: {{ navTop }}px;" class="nav-title {{ fixed ? 'nav-black' : '' }}">
+      <van-icon wx:if="{{ is_back }}" custom-style="position: absolute; bottom: {{ navTop }}px; left: 10px" name="arrow-left" size="24" bindtap="navBack" />
+      {{ name }}
+   </view>
+</view>

+ 20 - 0
lib/navbar/index.wxss

@@ -0,0 +1,20 @@
+.nav-bar {
+	position: relative;
+	z-index: 9999;
+}
+
+.nav-title {
+	position: absolute;
+	display: flex;
+	justify-content: center;
+	align-items: center;
+	width: 100%;
+	text-align: center;
+	font-size: 36rpx;
+	font-weight: bold;
+	color: #fff;
+}
+
+.nav-black {
+	color: #000;
+}

+ 67 - 0
lib/spec-popup/index.js

@@ -0,0 +1,67 @@
+const util = require('../../utils/util')
+
+Component({
+  properties: {
+    show: {
+      type: Boolean,
+      value: false
+    },
+    goods: { // 商品
+      type: Object
+		}
+  },
+
+  data: {
+		curSpec: {},
+		specName: [],
+		specValue: []
+  },
+
+	observers: {
+    goods: function(val) {
+			if (val) {
+				const { products, curSpec } = val
+				let result = []
+				const specs = products.map(p => p.specifications.join())
+				const specName = specs[0].split(',').map(s => s.split(':')[0])
+				const vList = specs.map(sp => sp.split(',').map(s => s.split(':')[1] ))
+				
+				vList.forEach(v => {
+					v.forEach((d, i) => {
+						const a = (result[i] = result[i] || [])
+						if (a.findIndex(a => a == d) == -1) a.push(d)
+					})
+				})
+				const curSpecValue = curSpec.specifications[0].split(',').map(s => s.split(':')[1])
+				
+				const specValue = result.map(res => res.map(name => ({ name, is_active: curSpecValue.findIndex(c => c == name) != -1 ? true : false })))
+				this.setData({ specName, specValue, curSpec })
+			}
+		}
+	},
+
+  methods: {
+    prevent() {
+      return false
+		},
+		
+		changeSpec({ currentTarget }) {
+			const { index, nameindex } = currentTarget.dataset
+			this.data.specValue[nameindex].map((spec, spec_i) => {
+				spec.is_active = spec_i == index ? true : false
+				return spec
+			})
+			this.setData({ specValue: this.data.specValue })
+
+			const spec = this.data.specName.map((name, spec_index) => name + ':' + this.data.specValue[spec_index].filter(val => val.is_active)[0].name).join(',')
+			const i = this.data.goods.products.findIndex(p => p.specifications.join() == spec)
+
+			this.setData({ curSpec: this.data.goods.products[i] })
+		},
+
+    hideSpec() {
+			this.setData({ goods: this.data.goods })
+			this.triggerEvent('hideSpec')
+		}
+  }
+})

+ 6 - 0
lib/spec-popup/index.json

@@ -0,0 +1,6 @@
+{
+	"component": true,
+  "usingComponents": {
+    "popup": "@vant/weapp/popup/index"
+  }
+}

+ 26 - 0
lib/spec-popup/index.wxml

@@ -0,0 +1,26 @@
+<wxs src="../../utils/filter.wxs" module="filter" />
+
+<popup custom-class="spec-popup" show="{{ show }}" position="bottom" closeable catchtouchmove="prevent" bind:close="hideSpec">
+	<view class="spec-top flex">
+		<view style="height: 176rpx;" class="flex">
+			<image class="spec-url" src="{{ curSpec.url }}" />
+			<view class="spec-selected flex">
+				<view class="flex column-bottom">
+					<view class="spec-price">¥<text class="txt">{{ curSpec.price }}</text></view>
+				</view>
+				<view>已选:{{ filter.specSelected(specValue) }}</view>
+			</view>
+		</view>
+	</view>
+
+	<scroll-view class="spec-content" scroll-y>
+		<view class="spec-list" wx:for="{{ specName }}" wx:for-item="name" wx:for-index="nameindex" wx:key="nameindex">
+			<view class="spec-label">{{ name }}</view>
+			<view class="spec-value {{ item.is_active ? 'value-active' : '' }}" wx:for="{{ specValue[nameindex] }}" wx:key="index" data-nameindex="{{ nameindex }}" data-index="{{ index }}" bindtap="changeSpec">{{ item.name }}</view>
+		</view>
+		<view class="spec-count flex">
+			<view class="count-label">库存</view>
+			<view class="flex row-middle">{{ curSpec.number }}</view>
+		</view>
+	</scroll-view>
+</popup>

+ 100 - 0
lib/spec-popup/index.wxss

@@ -0,0 +1,100 @@
+.flex {
+	display: flex;
+}
+
+.column-bottom {
+	align-items: flex-end;
+}
+
+.row-middle {
+	align-items: center;
+}
+
+.spec-popup {
+	height: 60%;
+	padding: 32rpx 0 0;
+	text-align: left;
+	z-index: 110 !important;
+}
+
+.spec-top {
+	width: calc(100% - 48rpx);
+	height: 30%;
+	margin: auto;
+	justify-content: space-between;
+	border-bottom: 2rpx solid rgba(110, 123, 143, 0.16);
+}
+
+.spec-url {
+	width: 176rpx;
+	height: 100%;
+	border-radius: 16rpx;
+}
+
+.spec-selected {
+	flex-direction: column;
+	justify-content: flex-end;
+	margin-left: 24rpx;
+	line-height: 26rpx;
+	font-size: 22rpx;
+	color: #50555F;
+}
+
+.spec-price {
+	margin-bottom: 12rpx;
+	line-height: 38rpx;
+	font-size: 32rpx;
+	color: #F94F50;
+}
+
+.txt {
+	padding-left: 4rpx;
+	line-height: 56rpx;
+	font-size: 48rpx;
+	font-family: DIN Alternate-Bold, DIN Alternate;
+	font-weight: bold;
+}
+
+.spec-content {
+	height: calc(70% - 36rpx);
+	margin-top: 36rpx;
+	padding-bottom: 32rpx;
+}
+
+.spec-list {
+	padding: 0 24rpx;
+	margin-bottom: 44rpx;
+}
+
+.spec-label {
+	margin-bottom: 20rpx;
+	line-height: 40rpx;
+}
+
+.spec-value {
+	display: inline-block;
+	margin-right: 24rpx;
+	padding: 14rpx 40rpx;
+	background: #f8f8f8;
+	border: 2rpx solid transparent;
+	border-radius: 42rpx;
+	text-align: center;
+	line-height: 28rpx;
+	color: #060606;
+}
+
+.value-active {
+	background: #fceeee;
+	border-color: #D32D2F;
+	color: #D32D2F;
+}
+
+.spec-count {
+	padding: 0 24rpx;
+	justify-content: space-between;
+}
+
+.count-label {
+	margin-bottom: 0;
+	line-height: 60rpx;
+}

+ 242 - 0
lib/wxParse/html2json.js

@@ -0,0 +1,242 @@
+/**
+ * author: Di (微信小程序开发工程师)
+ * organization: WeAppDev(微信小程序开发论坛)(http://weappdev.com)
+ *               垂直微信小程序开发交流社区
+ * 
+ * github地址: https://github.com/icindy/wxParse
+ * 
+ * for: 微信小程序富文本解析
+ * detail : http://weappdev.com/t/wxparse-alpha0-1-html-markdown/184
+ */
+
+var __placeImgeUrlHttps = "https";
+var __emojisReg = '';
+var __emojisBaseSrc = '';
+var __emojis = {};
+var wxDiscode = require('wxDiscode.js');
+var HTMLParser = require('htmlparser.js');
+// Empty Elements - HTML 5
+var empty = makeMap("area,base,basefont,br,col,frame,hr,img,input,link,meta,param,embed,command,keygen,source,track,wbr");
+// Block Elements - HTML 5
+var block = makeMap("br,a,code,address,article,applet,aside,audio,blockquote,button,canvas,center,dd,del,dir,div,dl,dt,fieldset,figcaption,figure,footer,form,frameset,h1,h2,h3,h4,h5,h6,header,hgroup,hr,iframe,ins,isindex,li,map,menu,noframes,noscript,object,ol,output,p,pre,section,script,table,tbody,td,tfoot,th,thead,tr,ul,video");
+
+// Inline Elements - HTML 5
+var inline = makeMap("abbr,acronym,applet,b,basefont,bdo,big,button,cite,del,dfn,em,font,i,iframe,img,input,ins,kbd,label,map,object,q,s,samp,script,select,small,span,strike,strong,sub,sup,textarea,tt,u,var");
+
+// Elements that you can, intentionally, leave open
+// (and which close themselves)
+var closeSelf = makeMap("colgroup,dd,dt,li,options,p,td,tfoot,th,thead,tr");
+
+// Attributes that have their values filled in disabled="disabled"
+var fillAttrs = makeMap("checked,compact,declare,defer,disabled,ismap,multiple,nohref,noresize,noshade,nowrap,readonly,selected");
+
+// Special Elements (can contain anything)
+var special = makeMap("wxxxcode-style,script,style,view,scroll-view,block");
+function makeMap(str) {
+    var obj = {}, items = str.split(",");
+    for (var i = 0; i < items.length; i++)
+        obj[items[i]] = true;
+    return obj;
+}
+
+function q(v) {
+    return '"' + v + '"';
+}
+
+function removeDOCTYPE(html) {
+    return html
+        .replace(/<\?xml.*\?>\n/, '')
+        .replace(/<!doctype.*\>\n/, '')
+        .replace(/<!DOCTYPE.*\>\n/, '');
+}
+
+
+function html2json(html, bindName) {
+    //处理字符串
+    html = removeDOCTYPE(html);
+    html = wxDiscode.strDiscode(html);
+    //生成node节点
+    var bufArray = [];
+    var results = {
+        node: bindName,
+        nodes: [],
+        images:[],
+        imageUrls:[]
+    };
+    HTMLParser(html, {
+        start: function (tag, attrs, unary) {
+            //debug(tag, attrs, unary);
+            // node for this element
+            var node = {
+                node: 'element',
+                tag: tag,
+            };
+
+            if (block[tag]) {
+                node.tagType = "block";
+            } else if (inline[tag]) {
+                node.tagType = "inline";
+            } else if (closeSelf[tag]) {
+                node.tagType = "closeSelf";
+            }
+
+            if (attrs.length !== 0) {
+                node.attr = attrs.reduce(function (pre, attr) {
+                    var name = attr.name;
+                    var value = attr.value;
+                    if (name == 'class') {
+                        // console.dir(value);
+                        //  value = value.join("")
+                        node.classStr = value;
+                    }
+                    // has multi attibutes
+                    // make it array of attribute
+                    if (name == 'style') {
+                        // console.dir(value);
+                        //  value = value.join("")
+                        node.styleStr = value;
+                    }
+                    if (value.match(/ /)) {
+                        value = value.split(' ');
+                    }
+                    
+
+                    // if attr already exists
+                    // merge it
+                    if (pre[name]) {
+                        if (Array.isArray(pre[name])) {
+                            // already array, push to last
+                            pre[name].push(value);
+                        } else {
+                            // single value, make it array
+                            pre[name] = [pre[name], value];
+                        }
+                    } else {
+                        // not exist, put it
+                        pre[name] = value;
+                    }
+
+                    return pre;
+                }, {});
+            }
+
+            //对img添加额外数据
+            if (node.tag === 'img') {
+                node.imgIndex = results.images.length;
+                var imgUrl = node.attr.src;
+                imgUrl = wxDiscode.urlToHttpUrl(imgUrl, __placeImgeUrlHttps);
+                node.attr.src = imgUrl;
+                node.from = bindName;
+                results.images.push(node);
+                results.imageUrls.push(imgUrl);
+            }
+
+            if (unary) {
+                // if this tag dosen't have end tag
+                // like <img src="hoge.png"/>
+                // add to parents
+                var parent = bufArray[0] || results;
+                if (parent.nodes === undefined) {
+                    parent.nodes = [];
+                }
+                parent.nodes.push(node);
+            } else {
+                bufArray.unshift(node);
+            }
+        },
+        end: function (tag) {
+            //debug(tag);
+            // merge into parent tag
+            var node = bufArray.shift();
+            if (node.tag !== tag) console.error('invalid state: mismatch end tag');
+
+            if (bufArray.length === 0) {
+                results.nodes.push(node);
+            } else {
+                var parent = bufArray[0];
+                if (parent.nodes === undefined) {
+                    parent.nodes = [];
+                }
+                parent.nodes.push(node);
+            }
+        },
+        chars: function (text) {
+            //debug(text);
+            var node = {
+                node: 'text',
+                text: text,
+                textArray:transEmojiStr(text)
+            };
+            
+            if (bufArray.length === 0) {
+                results.nodes.push(node);
+            } else {
+                var parent = bufArray[0];
+                if (parent.nodes === undefined) {
+                    parent.nodes = [];
+                }
+                parent.nodes.push(node);
+            }
+        },
+        comment: function (text) {
+            //debug(text);
+            var node = {
+                node: 'comment',
+                text: text,
+            };
+            var parent = bufArray[0];
+            if (parent.nodes === undefined) {
+                parent.nodes = [];
+            }
+            parent.nodes.push(node);
+        },
+    });
+    return results;
+};
+
+function transEmojiStr(str){
+  // var eReg = new RegExp("["+__reg+' '+"]");
+//   str = str.replace(/\[([^\[\]]+)\]/g,':$1:')
+  
+  var emojiObjs = [];
+  //如果正则表达式为空
+  if(__emojisReg.length == 0 || !__emojis){
+      var emojiObj = {}
+      emojiObj.node = "text";
+      emojiObj.text = str;
+      array = [emojiObj];
+      return array;
+  }
+  //这个地方需要调整
+  str = str.replace(/\[([^\[\]]+)\]/g,':$1:')
+  var eReg = new RegExp("[:]");
+  var array = str.split(eReg);
+  for(var i = 0; i < array.length; i++){
+    var ele = array[i];
+    var emojiObj = {};
+    if(__emojis[ele]){
+      emojiObj.node = "element";
+      emojiObj.tag = "emoji";
+      emojiObj.text = __emojis[ele];
+      emojiObj.baseSrc= __emojisBaseSrc;
+    }else{
+      emojiObj.node = "text";
+      emojiObj.text = ele;
+    }
+    emojiObjs.push(emojiObj);
+  }
+  
+  return emojiObjs;
+}
+
+function emojisInit(reg='',baseSrc="/wxParse/emojis/",emojis){
+    __emojisReg = reg;
+    __emojisBaseSrc=baseSrc;
+    __emojis=emojis;
+}
+
+module.exports = {
+    html2json: html2json,
+    emojisInit:emojisInit
+};
+

+ 182 - 0
lib/wxParse/htmlparser.js

@@ -0,0 +1,182 @@
+/**
+ * author: Di (微信小程序开发工程师)
+ * organization: WeAppDev(微信小程序开发论坛)(http://weappdev.com)
+ *               垂直微信小程序开发交流社区
+ * 
+ * github地址: https://github.com/icindy/wxParse
+ * 
+ * for: 微信小程序富文本解析
+ * detail : http://weappdev.com/t/wxparse-alpha0-1-html-markdown/184
+ */
+// Regular Expressions for parsing tags and attributes
+var startTag = /^<([-A-Za-z0-9_]+)((?:\s+[a-zA-Z_:][-a-zA-Z0-9_:.]*(?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+))?)*)\s*(\/?)>/,
+	endTag = /^<\/([-A-Za-z0-9_]+)[^>]*>/,
+	attr = /([a-zA-Z_:][-a-zA-Z0-9_:.]*)(?:\s*=\s*(?:(?:"((?:\\.|[^"])*)")|(?:'((?:\\.|[^'])*)')|([^>\s]+)))?/g;
+
+// Empty Elements - HTML 5
+var empty = makeMap("area,base,basefont,br,col,frame,hr,img,input,link,meta,param,embed,command,keygen,source,track,wbr");
+
+// Block Elements - HTML 5
+var block = makeMap("a,address,code,article,applet,aside,audio,blockquote,button,canvas,center,dd,del,dir,div,dl,dt,fieldset,figcaption,figure,footer,form,frameset,h1,h2,h3,h4,h5,h6,header,hgroup,hr,iframe,ins,isindex,li,map,menu,noframes,noscript,object,ol,output,p,pre,section,script,table,tbody,td,tfoot,th,thead,tr,ul,video");
+
+// Inline Elements - HTML 5
+var inline = makeMap("abbr,acronym,applet,b,basefont,bdo,big,br,button,cite,del,dfn,em,font,i,iframe,img,input,ins,kbd,label,map,object,q,s,samp,script,select,small,span,strike,strong,sub,sup,textarea,tt,u,var");
+
+// Elements that you can, intentionally, leave open
+// (and which close themselves)
+var closeSelf = makeMap("colgroup,dd,dt,li,options,p,td,tfoot,th,thead,tr");
+
+// Attributes that have their values filled in disabled="disabled"
+var fillAttrs = makeMap("checked,compact,declare,defer,disabled,ismap,multiple,nohref,noresize,noshade,nowrap,readonly,selected");
+
+// Special Elements (can contain anything)
+var special = makeMap("wxxxcode-style,script,style,view,scroll-view,block");
+
+function HTMLParser(html, handler) {
+	var index, chars, match, stack = [], last = html;
+	stack.last = function () {
+		return this[this.length - 1];
+	};
+
+	while (html) {
+		chars = true;
+
+		// Make sure we're not in a script or style element
+		if (!stack.last() || !special[stack.last()]) {
+
+			// Comment
+			if (html.indexOf("<!--") == 0) {
+				index = html.indexOf("-->");
+
+				if (index >= 0) {
+					if (handler.comment)
+						handler.comment(html.substring(4, index));
+					html = html.substring(index + 3);
+					chars = false;
+				}
+
+				// end tag
+			} else if (html.indexOf("</") == 0) {
+				match = html.match(endTag);
+
+				if (match) {
+					html = html.substring(match[0].length);
+					match[0].replace(endTag, parseEndTag);
+					chars = false;
+				}
+
+				// start tag
+			} else if (html.indexOf("<") == 0) {
+				match = html.match(startTag);
+
+				if (match) {
+					html = html.substring(match[0].length);
+					match[0].replace(startTag, parseStartTag);
+					chars = false;
+				}
+			}
+
+			if (chars) {
+				index = html.indexOf("<");
+
+				var text = index < 0 ? html : html.substring(0, index);
+				html = index < 0 ? "" : html.substring(index);
+
+				if (handler.chars)
+					handler.chars(text);
+			}
+
+		} else {
+
+			html = html.replace(new RegExp("([\\s\\S]*?)<\/" + stack.last() + "[^>]*>"), function (all, text) {
+				text = text.replace(/<!--([\s\S]*?)-->|<!\[CDATA\[([\s\S]*?)]]>/g, "$1$2");
+				if (handler.chars)
+					handler.chars(text);
+
+				return "";
+			});
+
+
+			parseEndTag("", stack.last());
+		}
+
+		if (html == last)
+			throw "Parse Error: " + html;
+		last = html;
+	}
+
+	// Clean up any remaining tags
+	parseEndTag();
+
+	function parseStartTag(tag, tagName, rest, unary) {
+		tagName = tagName.toLowerCase();
+
+		if (block[tagName]) {
+			while (stack.last() && inline[stack.last()]) {
+				parseEndTag("", stack.last());
+			}
+		}
+
+		if (closeSelf[tagName] && stack.last() == tagName) {
+			parseEndTag("", tagName);
+		}
+
+		unary = empty[tagName] || !!unary;
+
+		if (!unary)
+			stack.push(tagName);
+
+		if (handler.start) {
+			var attrs = [];
+
+			rest.replace(attr, function (match, name) {
+				var value = arguments[2] ? arguments[2] :
+					arguments[3] ? arguments[3] :
+						arguments[4] ? arguments[4] :
+							fillAttrs[name] ? name : "";
+
+				attrs.push({
+					name: name,
+					value: value,
+					escaped: value.replace(/(^|[^\\])"/g, '$1\\\"') //"
+				});
+			});
+
+			if (handler.start) {
+				handler.start(tagName, attrs, unary);
+			}
+
+		}
+	}
+
+	function parseEndTag(tag, tagName) {
+		// If no tag name is provided, clean shop
+		if (!tagName)
+			var pos = 0;
+
+		// Find the closest opened tag of the same type
+		else
+			for (var pos = stack.length - 1; pos >= 0; pos--)
+				if (stack[pos] == tagName)
+					break;
+
+		if (pos >= 0) {
+			// Close all the open elements, up the stack
+			for (var i = stack.length - 1; i >= pos; i--)
+				if (handler.end)
+					handler.end(stack[i]);
+
+			// Remove the open elements from the stack
+			stack.length = pos;
+		}
+	}
+};
+
+function makeMap(str) {
+	var obj = {}, items = str.split(",");
+	for (var i = 0; i < items.length; i++)
+		obj[items[i]] = true;
+	return obj;
+}
+
+module.exports = HTMLParser;

Разлика између датотеке није приказан због своје велике величине
+ 2529 - 0
lib/wxParse/showdown.js


+ 206 - 0
lib/wxParse/wxDiscode.js

@@ -0,0 +1,206 @@
+// HTML 支持的数学符号
+function strNumDiscode(str){
+    str = str.replace(/&forall;/g, '∀');
+    str = str.replace(/&part;/g, '∂');
+    str = str.replace(/&exists;/g, '∃');
+    str = str.replace(/&empty;/g, '∅');
+    str = str.replace(/&nabla;/g, '∇');
+    str = str.replace(/&isin;/g, '∈');
+    str = str.replace(/&notin;/g, '∉');
+    str = str.replace(/&ni;/g, '∋');
+    str = str.replace(/&prod;/g, '∏');
+    str = str.replace(/&sum;/g, '∑');
+    str = str.replace(/&minus;/g, '−');
+    str = str.replace(/&lowast;/g, '∗');
+    str = str.replace(/&radic;/g, '√');
+    str = str.replace(/&prop;/g, '∝');
+    str = str.replace(/&infin;/g, '∞');
+    str = str.replace(/&ang;/g, '∠');
+    str = str.replace(/&and;/g, '∧');
+    str = str.replace(/&or;/g, '∨');
+    str = str.replace(/&cap;/g, '∩');
+    str = str.replace(/&cap;/g, '∪');
+    str = str.replace(/&int;/g, '∫');
+    str = str.replace(/&there4;/g, '∴');
+    str = str.replace(/&sim;/g, '∼');
+    str = str.replace(/&cong;/g, '≅');
+    str = str.replace(/&asymp;/g, '≈');
+    str = str.replace(/&ne;/g, '≠');
+    str = str.replace(/&le;/g, '≤');
+    str = str.replace(/&ge;/g, '≥');
+    str = str.replace(/&sub;/g, '⊂');
+    str = str.replace(/&sup;/g, '⊃');
+    str = str.replace(/&nsub;/g, '⊄');
+    str = str.replace(/&sube;/g, '⊆');
+    str = str.replace(/&supe;/g, '⊇');
+    str = str.replace(/&oplus;/g, '⊕');
+    str = str.replace(/&otimes;/g, '⊗');
+    str = str.replace(/&perp;/g, '⊥');
+    str = str.replace(/&sdot;/g, '⋅');
+    return str;
+}
+
+//HTML 支持的希腊字母
+function strGreeceDiscode(str){
+    str = str.replace(/&Alpha;/g, 'Α');
+    str = str.replace(/&Beta;/g, 'Β');
+    str = str.replace(/&Gamma;/g, 'Γ');
+    str = str.replace(/&Delta;/g, 'Δ');
+    str = str.replace(/&Epsilon;/g, 'Ε');
+    str = str.replace(/&Zeta;/g, 'Ζ');
+    str = str.replace(/&Eta;/g, 'Η');
+    str = str.replace(/&Theta;/g, 'Θ');
+    str = str.replace(/&Iota;/g, 'Ι');
+    str = str.replace(/&Kappa;/g, 'Κ');
+    str = str.replace(/&Lambda;/g, 'Λ');
+    str = str.replace(/&Mu;/g, 'Μ');
+    str = str.replace(/&Nu;/g, 'Ν');
+    str = str.replace(/&Xi;/g, 'Ν');
+    str = str.replace(/&Omicron;/g, 'Ο');
+    str = str.replace(/&Pi;/g, 'Π');
+    str = str.replace(/&Rho;/g, 'Ρ');
+    str = str.replace(/&Sigma;/g, 'Σ');
+    str = str.replace(/&Tau;/g, 'Τ');
+    str = str.replace(/&Upsilon;/g, 'Υ');
+    str = str.replace(/&Phi;/g, 'Φ');
+    str = str.replace(/&Chi;/g, 'Χ');
+    str = str.replace(/&Psi;/g, 'Ψ');
+    str = str.replace(/&Omega;/g, 'Ω');
+
+    str = str.replace(/&alpha;/g, 'α');
+    str = str.replace(/&beta;/g, 'β');
+    str = str.replace(/&gamma;/g, 'γ');
+    str = str.replace(/&delta;/g, 'δ');
+    str = str.replace(/&epsilon;/g, 'ε');
+    str = str.replace(/&zeta;/g, 'ζ');
+    str = str.replace(/&eta;/g, 'η');
+    str = str.replace(/&theta;/g, 'θ');
+    str = str.replace(/&iota;/g, 'ι');
+    str = str.replace(/&kappa;/g, 'κ');
+    str = str.replace(/&lambda;/g, 'λ');
+    str = str.replace(/&mu;/g, 'μ');
+    str = str.replace(/&nu;/g, 'ν');
+    str = str.replace(/&xi;/g, 'ξ');
+    str = str.replace(/&omicron;/g, 'ο');
+    str = str.replace(/&pi;/g, 'π');
+    str = str.replace(/&rho;/g, 'ρ');
+    str = str.replace(/&sigmaf;/g, 'ς');
+    str = str.replace(/&sigma;/g, 'σ');
+    str = str.replace(/&tau;/g, 'τ');
+    str = str.replace(/&upsilon;/g, 'υ');
+    str = str.replace(/&phi;/g, 'φ');
+    str = str.replace(/&chi;/g, 'χ');
+    str = str.replace(/&psi;/g, 'ψ');
+    str = str.replace(/&omega;/g, 'ω');
+    str = str.replace(/&thetasym;/g, 'ϑ');
+    str = str.replace(/&upsih;/g, 'ϒ');
+    str = str.replace(/&piv;/g, 'ϖ');
+    str = str.replace(/&middot;/g, '·');
+    return str;
+}
+
+// 
+
+function strcharacterDiscode(str){
+    // 加入常用解析
+    str = str.replace(/&nbsp;/g, ' ');
+    str = str.replace(/&quot;/g, '"');
+    str = str.replace(/&amp;/g, '&');
+    // str = str.replace(/&lt;/g, '‹');
+    // str = str.replace(/&gt;/g, '›');
+
+    str = str.replace(/&lt;/g, '<');
+    str = str.replace(/&gt;/g, '>');
+
+    return str;
+}
+
+// HTML 支持的其他实体
+function strOtherDiscode(str){
+    str = str.replace(/&OElig;/g, 'Œ');
+    str = str.replace(/&oelig;/g, 'œ');
+    str = str.replace(/&Scaron;/g, 'Š');
+    str = str.replace(/&scaron;/g, 'š');
+    str = str.replace(/&Yuml;/g, 'Ÿ');
+    str = str.replace(/&fnof;/g, 'ƒ');
+    str = str.replace(/&circ;/g, 'ˆ');
+    str = str.replace(/&tilde;/g, '˜');
+    str = str.replace(/&ensp;/g, '');
+    str = str.replace(/&emsp;/g, '');
+    str = str.replace(/&thinsp;/g, '');
+    str = str.replace(/&zwnj;/g, '');
+    str = str.replace(/&zwj;/g, '');
+    str = str.replace(/&lrm;/g, '');
+    str = str.replace(/&rlm;/g, '');
+    str = str.replace(/&ndash;/g, '–');
+    str = str.replace(/&mdash;/g, '—');
+    str = str.replace(/&lsquo;/g, '‘');
+    str = str.replace(/&rsquo;/g, '’');
+    str = str.replace(/&sbquo;/g, '‚');
+    str = str.replace(/&ldquo;/g, '“');
+    str = str.replace(/&rdquo;/g, '”');
+    str = str.replace(/&bdquo;/g, '„');
+    str = str.replace(/&dagger;/g, '†');
+    str = str.replace(/&Dagger;/g, '‡');
+    str = str.replace(/&bull;/g, '•');
+    str = str.replace(/&hellip;/g, '…');
+    str = str.replace(/&permil;/g, '‰');
+    str = str.replace(/&prime;/g, '′');
+    str = str.replace(/&Prime;/g, '″');
+    str = str.replace(/&lsaquo;/g, '‹');
+    str = str.replace(/&rsaquo;/g, '›');
+    str = str.replace(/&oline;/g, '‾');
+    str = str.replace(/&euro;/g, '€');
+    str = str.replace(/&trade;/g, '™');
+
+    str = str.replace(/&larr;/g, '←');
+    str = str.replace(/&uarr;/g, '↑');
+    str = str.replace(/&rarr;/g, '→');
+    str = str.replace(/&darr;/g, '↓');
+    str = str.replace(/&harr;/g, '↔');
+    str = str.replace(/&crarr;/g, '↵');
+    str = str.replace(/&lceil;/g, '⌈');
+    str = str.replace(/&rceil;/g, '⌉');
+
+    str = str.replace(/&lfloor;/g, '⌊');
+    str = str.replace(/&rfloor;/g, '⌋');
+    str = str.replace(/&loz;/g, '◊');
+    str = str.replace(/&spades;/g, '♠');
+    str = str.replace(/&clubs;/g, '♣');
+    str = str.replace(/&hearts;/g, '♥');
+
+    str = str.replace(/&diams;/g, '♦');
+
+    return str;
+}
+
+function strMoreDiscode(str){
+    str = str.replace(/\r\n/g,"");  
+    str = str.replace(/\n/g,"");
+
+    str = str.replace(/code/g,"wxxxcode-style");
+    return str;
+}
+
+function strDiscode(str){
+    str = strNumDiscode(str);
+    str = strGreeceDiscode(str);
+    str = strcharacterDiscode(str);
+    str = strOtherDiscode(str);
+    str = strMoreDiscode(str);
+    return str;
+}
+function urlToHttpUrl(url,rep){
+    
+    var patt1 = new RegExp("^//");
+    var result = patt1.test(url);
+    if(result){
+        url = rep+":"+url;
+    }
+    return  url;
+}
+
+module.exports = {
+    strDiscode:strDiscode,
+    urlToHttpUrl:urlToHttpUrl
+}

+ 146 - 0
lib/wxParse/wxParse.js

@@ -0,0 +1,146 @@
+/**
+ * author: Di (微信小程序开发工程师)
+ * organization: WeAppDev(微信小程序开发论坛)(http://weappdev.com)
+ *               垂直微信小程序开发交流社区
+ * 
+ * github地址: https://github.com/icindy/wxParse
+ * 
+ * for: 微信小程序富文本解析
+ * detail : http://weappdev.com/t/wxparse-alpha0-1-html-markdown/184
+ */
+
+/**
+ * utils函数引入
+ **/
+import showdown from 'showdown.js';
+import HtmlToJson from 'html2json.js';
+/**
+ * 配置及公有属性
+ **/
+/**
+ * 主函数入口区
+ **/
+function wxParse(bindName = 'wxParseData', type='html', data='<div class="color:red;">数据不能为空</div>', target,imagePadding) {
+  var that = target;
+  var transData = {};//存放转化后的数据
+  if (type == 'html') {
+    transData = HtmlToJson.html2json(data, bindName);
+    // console.log(JSON.stringify(transData, ' ', ' '));
+  } else if (type == 'md' || type == 'markdown') {
+    var converter = new showdown.Converter();
+    var html = converter.makeHtml(data);
+    transData = HtmlToJson.html2json(html, bindName);
+    // console.log(JSON.stringify(transData, ' ', ' '));
+  }
+  transData.view = {};
+  transData.view.imagePadding = 0;
+  if(typeof(imagePadding) != 'undefined'){
+    transData.view.imagePadding = imagePadding
+  }
+  var bindData = {};
+  bindData[bindName] = transData;
+  that.setData(bindData)
+  that.wxParseImgLoad = wxParseImgLoad;
+  that.wxParseImgTap = wxParseImgTap;
+}
+// 图片点击事件
+function wxParseImgTap(e) {
+  var that = this;
+  var nowImgUrl = e.target.dataset.src;
+  var tagFrom = e.target.dataset.from;
+  if (typeof (tagFrom) != 'undefined' && tagFrom.length > 0) {
+    wx.previewImage({
+      current: nowImgUrl, // 当前显示图片的http链接
+      urls: that.data[tagFrom].imageUrls // 需要预览的图片http链接列表
+    })
+  }
+}
+
+/**
+ * 图片视觉宽高计算函数区 
+ **/
+function wxParseImgLoad(e) {
+  var that = this;
+  var tagFrom = e.target.dataset.from;
+  var idx = e.target.dataset.idx;
+  if (typeof (tagFrom) != 'undefined' && tagFrom.length > 0) {
+    calMoreImageInfo(e, idx, that, tagFrom)
+  } 
+}
+// 假循环获取计算图片视觉最佳宽高
+function calMoreImageInfo(e, idx, that, bindName) {
+  var temData = that.data[bindName];
+  if (temData.images.length == 0) {
+    return;
+  }
+  var temImages = temData.images;
+  //因为无法获取view宽度 需要自定义padding进行计算,稍后处理
+  var recal = wxAutoImageCal(e.detail.width, e.detail.height,that,bindName); 
+  temImages[idx].width = recal.imageWidth;
+  temImages[idx].height = recal.imageheight; 
+  temData.images = temImages;
+  var bindData = {};
+  bindData[bindName] = temData;
+  that.setData(bindData);
+}
+
+// 计算视觉优先的图片宽高
+function wxAutoImageCal(originalWidth, originalHeight,that,bindName) {
+  //获取图片的原始长宽
+  var windowWidth = 0, windowHeight = 0;
+  var autoWidth = 0, autoHeight = 0;
+  var results = {};
+  wx.getSystemInfo({
+    success: function (res) {
+      var padding = that.data[bindName].view.imagePadding;
+      windowWidth = res.windowWidth-2*padding;
+      windowHeight = res.windowHeight;
+      //判断按照那种方式进行缩放
+      // console.log("windowWidth" + windowWidth);
+      if (originalWidth > windowWidth) {//在图片width大于手机屏幕width时候
+        autoWidth = windowWidth;
+        // console.log("autoWidth" + autoWidth);
+        autoHeight = (autoWidth * originalHeight) / originalWidth;
+        // console.log("autoHeight" + autoHeight);
+        results.imageWidth = autoWidth;
+        results.imageheight = autoHeight;
+      } else {//否则展示原来的数据
+        results.imageWidth = originalWidth;
+        results.imageheight = originalHeight;
+      }
+    }
+  })
+  return results;
+}
+
+function wxParseTemArray(temArrayName,bindNameReg,total,that){
+  var array = [];
+  var temData = that.data;
+  var obj = null;
+  for(var i = 0; i < total; i++){
+    var simArr = temData[bindNameReg+i].nodes;
+    array.push(simArr);
+  }
+
+  temArrayName = temArrayName || 'wxParseTemArray';
+  obj = JSON.parse('{"'+ temArrayName +'":""}');
+  obj[temArrayName] = array;
+  that.setData(obj);
+}
+
+/**
+ * 配置emojis
+ * 
+ */
+
+function emojisInit(reg='',baseSrc="/wxParse/emojis/",emojis){
+   HtmlToJson.emojisInit(reg,baseSrc,emojis);
+}
+
+module.exports = {
+  wxParse: wxParse,
+  wxParseTemArray:wxParseTemArray,
+  emojisInit:emojisInit
+}
+
+

+ 928 - 0
lib/wxParse/wxParse.wxml

@@ -0,0 +1,928 @@
+
+<!--**
+ * author: Di (微信小程序开发工程师)
+ * organization: WeAppDev(微信小程序开发论坛)(http://weappdev.com)
+ *               垂直微信小程序开发交流社区
+ * 
+ * github地址: https://github.com/icindy/wxParse
+ * 
+ * for: 微信小程序富文本解析
+ * detail : http://weappdev.com/t/wxparse-alpha0-1-html-markdown/184
+ */-->
+
+ <!--基础元素-->
+<template name="wxParseVideo">
+    <!--增加video标签支持,并循环添加-->
+    <view class="{{item.classStr}} wxParse-{{item.tag}}" style="{{item.styleStr}}">
+        <video class="{{item.classStr}} wxParse-{{item.tag}}-video" src="{{item.attr.src}}"></video>
+    </view>
+</template>
+
+<template name="wxParseImg">
+    <image class="{{item.classStr}} wxParse-{{item.tag}}" data-from="{{item.from}}" data-src="{{item.attr.src}}"  data-idx="{{item.imgIndex}}"  src="{{item.attr.src}}" mode="aspectFit" bindload="wxParseImgLoad" bindtap="wxParseImgTap" style="width:{{item.width}}px;height:{{item.height}}px;{{item.attr.style}}"   />
+</template>
+
+<template name="WxEmojiView">
+  <view class="WxEmojiView wxParse-inline" style="{{item.styleStr}}">
+    <block wx:for="{{item.textArray}}" wx:key="index">
+      <block class="{{item.text == '\\n' ? 'wxParse-hide':''}}" wx:if="{{item.node == 'text'}}">{{item.text}}</block>
+      <block wx:elif="{{item.node == 'element'}}">
+        <image class="wxEmoji" src="{{item.baseSrc}}{{item.text}}" />
+      </block>
+    </block>
+  </view>
+</template>
+
+<!--入口模版-->
+
+<template name="wxParse">
+    <block wx:for="{{wxParseData}}" wx:key="index">
+        <template is="wxParse0" data="{{item}}"/>
+    </block>
+</template>
+
+
+<!--循环模版-->
+<template name="wxParse0">
+    <!--<template is="wxParse1" data="{{item}}" />-->
+    <!--判断是否是标签节点-->
+    <block wx:if="{{item.node == 'element'}}">
+        <block wx:if="{{item.tag == 'button'}}">
+            <button type="default" size="mini" >
+                <block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="index">
+                    <template is="wxParse1" data="{{item}}"/>
+                </block>
+             </button>
+        </block>
+        <!--li类型-->
+        <block wx:elif="{{item.tag == 'li'}}">
+            <view class="{{item.classStr}} wxParse-li">
+                <view class="{{item.classStr}} wxParse-li-inner">
+                    <view class="{{item.classStr}} wxParse-li-text">
+                        <view class="{{item.classStr}} wxParse-li-circle"></view>
+                    </view>
+                    <view class="{{item.classStr}} wxParse-li-text">
+                        <block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="index">
+                            <template is="wxParse1" data="{{item}}"/>
+                        </block>
+                    </view>
+                </view>
+            </view>
+        </block>
+
+        <!--video类型-->
+        <block wx:elif="{{item.tag == 'video'}}">
+            <template is="wxParseVideo" data="{{item}}"/>  
+        </block>
+
+        <!--img类型-->
+        <block wx:elif="{{item.tag == 'img'}}">
+            <template is="wxParseImg" data="{{item}}"/>
+        </block>
+
+        <!--a类型-->
+        <block wx:elif="{{item.tag == 'a'}}">
+            <view bindtap="wxParseTagATap" class="wxParse-inline {{item.classStr}} wxParse-{{item.tag}}" data-c="{{item.attr.href}}"  style="{{item.styleStr}}">
+                <block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="index">
+                    <template is="wxParse1" data="{{item}}"/>
+                </block>
+            </view>
+        </block>
+        <block wx:elif="{{item.tag == 'table'}}">
+            <view class="{{item.classStr}} wxParse-{{item.tag}}" style="{{item.styleStr}}">
+                <block  wx:for="{{item.nodes}}" wx:for-item="item" wx:key="index">       
+                    <template is="wxParse1" data="{{item}}"/>                 
+                </block>
+            </view>
+        </block>
+
+        <!--其他块级标签-->
+        <block wx:elif="{{item.tagType == 'block'}}">
+            <view class="{{item.classStr}} wxParse-{{item.tag}}" style="{{item.styleStr}}">
+                <block  wx:for="{{item.nodes}}" wx:for-item="item" wx:key="index">       
+                    <template is="wxParse1" data="{{item}}"/>                 
+                </block>
+            </view>
+        </block>
+
+        <!--内联标签-->
+        <view wx:else class="{{item.classStr}} wxParse-{{item.tag}} wxParse-{{item.tagType}}" style="{{item.styleStr}}">
+            <block  wx:for="{{item.nodes}}" wx:for-item="item" wx:key="index">       
+                <template is="wxParse1" data="{{item}}"/>                 
+            </block>
+        </view>
+
+    </block>
+
+    <!--判断是否是文本节点-->
+    <block wx:elif="{{item.node == 'text'}}">
+        <!--如果是,直接进行-->
+        <template is="WxEmojiView" data="{{item}}"/>
+    </block>
+
+</template>
+
+
+
+<!--循环模版-->
+<template name="wxParse1">
+    <!--<template is="wxParse2" data="{{item}}" />-->
+    <!--判断是否是标签节点-->
+    <block wx:if="{{item.node == 'element'}}">
+        <block wx:if="{{item.tag == 'button'}}">
+            <button type="default" size="mini" >
+                <block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="index">
+                    <template is="wxParse2" data="{{item}}"/>
+                </block>
+             </button>
+        </block>
+        <!--li类型-->
+        <block wx:elif="{{item.tag == 'li'}}">
+            <view class="{{item.classStr}} wxParse-li">
+                <view class="{{item.classStr}} wxParse-li-inner">
+                    <view class="{{item.classStr}} wxParse-li-text">
+                        <view class="{{item.classStr}} wxParse-li-circle"></view>
+                    </view>
+                    <view class="{{item.classStr}} wxParse-li-text">
+                        <block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="index">
+                            <template is="wxParse2" data="{{item}}"/>
+                        </block>
+                    </view>
+                </view>
+            </view>
+        </block>
+
+        <!--video类型-->
+        <block wx:elif="{{item.tag == 'video'}}">
+            <template is="wxParseVideo" data="{{item}}"/>  
+        </block>
+
+        <!--img类型-->
+        <block wx:elif="{{item.tag == 'img'}}">
+            <template is="wxParseImg" data="{{item}}"/>
+        </block>
+
+        <!--a类型-->
+        <block wx:elif="{{item.tag == 'a'}}">
+            <view bindtap="wxParseTagATap" class="wxParse-inline {{item.classStr}} wxParse-{{item.tag}}" data-src="{{item.attr.href}}"  style="{{item.styleStr}}">
+                <block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="index">
+                    <template is="wxParse2" data="{{item}}"/>
+                </block>
+            </view>
+        </block>
+        
+        <!--其他块级标签-->
+        <block wx:elif="{{item.tagType == 'block'}}">
+            <view class="{{item.classStr}} wxParse-{{item.tag}}" style="{{item.styleStr}}">
+                <block  wx:for="{{item.nodes}}" wx:for-item="item" wx:key="index">       
+                    <template is="wxParse2" data="{{item}}"/>                 
+                </block>
+            </view>
+        </block>
+
+        <!--内联标签-->
+        <view wx:else class="{{item.classStr}} wxParse-{{item.tag}} wxParse-{{item.tagType}}" style="{{item.styleStr}}">
+            <block  wx:for="{{item.nodes}}" wx:for-item="item" wx:key="index">       
+                <template is="wxParse2" data="{{item}}"/>                 
+            </block>
+        </view>
+
+    </block>
+
+    <!--判断是否是文本节点-->
+    <block wx:elif="{{item.node == 'text'}}">
+        <!--如果是,直接进行-->
+        <template is="WxEmojiView" data="{{item}}"/>
+    </block>
+
+</template>
+
+
+<!--循环模版-->
+<template name="wxParse2">
+    <!--<template is="wxParse3" data="{{item}}" />-->
+    <!--判断是否是标签节点-->
+    <block wx:if="{{item.node == 'element'}}">
+        <block wx:if="{{item.tag == 'button'}}">
+            <button type="default" size="mini" >
+                <block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="index">
+                    <template is="wxParse3" data="{{item}}"/>
+                </block>
+             </button>
+        </block>
+        <!--li类型-->
+        <block wx:elif="{{item.tag == 'li'}}">
+            <view class="{{item.classStr}} wxParse-li">
+                <view class="{{item.classStr}} wxParse-li-inner">
+                    <view class="{{item.classStr}} wxParse-li-text">
+                        <view class="{{item.classStr}} wxParse-li-circle"></view>
+                    </view>
+                    <view class="{{item.classStr}} wxParse-li-text">
+                        <block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="index">
+                            <template is="wxParse3" data="{{item}}"/>
+                        </block>
+                    </view>
+                </view>
+            </view>
+        </block>
+
+        <!--video类型-->
+        <block wx:elif="{{item.tag == 'video'}}">
+            <template is="wxParseVideo" data="{{item}}"/>  
+        </block>
+
+        <!--img类型-->
+        <block wx:elif="{{item.tag == 'img'}}">
+            <template is="wxParseImg" data="{{item}}"/>
+        </block>
+
+        <!--a类型-->
+        <block wx:elif="{{item.tag == 'a'}}">
+            <view bindtap="wxParseTagATap" class="wxParse-inline {{item.classStr}} wxParse-{{item.tag}}" data-src="{{item.attr.href}}"  style="{{item.styleStr}}">
+                <block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="index">
+                    <template is="wxParse3" data="{{item}}"/>
+                </block>
+            </view>
+        </block>
+        
+        <!--其他块级标签-->
+        <block wx:elif="{{item.tagType == 'block'}}">
+            <view class="{{item.classStr}} wxParse-{{item.tag}}" style="{{item.styleStr}}">
+                <block  wx:for="{{item.nodes}}" wx:for-item="item" wx:key="index">       
+                    <template is="wxParse3" data="{{item}}"/>                 
+                </block>
+            </view>
+        </block>
+
+        <!--内联标签-->
+        <view wx:else class="{{item.classStr}} wxParse-{{item.tag}} wxParse-{{item.tagType}}" style="{{item.styleStr}}">
+            <block  wx:for="{{item.nodes}}" wx:for-item="item" wx:key="index">       
+                <template is="wxParse3" data="{{item}}"/>                 
+            </block>
+        </view>
+
+    </block>
+
+    <!--判断是否是文本节点-->
+    <block wx:elif="{{item.node == 'text'}}">
+        <!--如果是,直接进行-->
+        <template is="WxEmojiView" data="{{item}}"/>
+    </block>
+
+</template>
+
+<!--循环模版-->
+<template name="wxParse3">
+    <!--<template is="wxParse4" data="{{item}}" />-->
+    <!--判断是否是标签节点-->
+    <block wx:if="{{item.node == 'element'}}">
+        <block wx:if="{{item.tag == 'button'}}">
+            <button type="default" size="mini" >
+                <block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="index">
+                    <template is="wxParse4" data="{{item}}"/>
+                </block>
+             </button>
+        </block>
+        <!--li类型-->
+        <block wx:elif="{{item.tag == 'li'}}">
+            <view class="{{item.classStr}} wxParse-li">
+                <view class="{{item.classStr}} wxParse-li-inner">
+                    <view class="{{item.classStr}} wxParse-li-text">
+                        <view class="{{item.classStr}} wxParse-li-circle"></view>
+                    </view>
+                    <view class="{{item.classStr}} wxParse-li-text">
+                        <block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="index">
+                            <template is="wxParse4" data="{{item}}"/>
+                        </block>
+                    </view>
+                </view>
+            </view>
+        </block>
+
+        <!--video类型-->
+        <block wx:elif="{{item.tag == 'video'}}">
+            <template is="wxParseVideo" data="{{item}}"/>  
+        </block>
+
+        <!--img类型-->
+        <block wx:elif="{{item.tag == 'img'}}">
+            <template is="wxParseImg" data="{{item}}"/>
+        </block>
+
+        <!--a类型-->
+        <block wx:elif="{{item.tag == 'a'}}">
+            <view bindtap="wxParseTagATap" class="wxParse-inline {{item.classStr}} wxParse-{{item.tag}}" data-src="{{item.attr.href}}"  style="{{item.styleStr}}">
+                <block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="index">
+                    <template is="wxParse4" data="{{item}}"/>
+                </block>
+            </view>
+        </block>
+        
+        <!--其他块级标签-->
+        <block wx:elif="{{item.tagType == 'block'}}">
+            <view class="{{item.classStr}} wxParse-{{item.tag}}" style="{{item.styleStr}}">
+                <block  wx:for="{{item.nodes}}" wx:for-item="item" wx:key="index">       
+                    <template is="wxParse4" data="{{item}}"/>                 
+                </block>
+            </view>
+        </block>
+
+        <!--内联标签-->
+        <view wx:else class="{{item.classStr}} wxParse-{{item.tag}} wxParse-{{item.tagType}}" style="{{item.styleStr}}">
+            <block  wx:for="{{item.nodes}}" wx:for-item="item" wx:key="index">       
+                <template is="wxParse4" data="{{item}}"/>                 
+            </block>
+        </view>
+
+    </block>
+
+    <!--判断是否是文本节点-->
+    <block wx:elif="{{item.node == 'text'}}">
+        <!--如果是,直接进行-->
+        <template is="WxEmojiView" data="{{item}}"/>
+    </block>
+
+</template>
+
+<!--循环模版-->
+<template name="wxParse4">
+    <!--<template is="wxParse5" data="{{item}}" />-->
+    <!--判断是否是标签节点-->
+    <block wx:if="{{item.node == 'element'}}">
+        <block wx:if="{{item.tag == 'button'}}">
+            <button type="default" size="mini" >
+                <block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="index">
+                    <template is="wxParse5" data="{{item}}"/>
+                </block>
+             </button>
+        </block>
+        <!--li类型-->
+        <block wx:elif="{{item.tag == 'li'}}">
+            <view class="{{item.classStr}} wxParse-li">
+                <view class="{{item.classStr}} wxParse-li-inner">
+                    <view class="{{item.classStr}} wxParse-li-text">
+                        <view class="{{item.classStr}} wxParse-li-circle"></view>
+                    </view>
+                    <view class="{{item.classStr}} wxParse-li-text">
+                        <block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="index">
+                            <template is="wxParse5" data="{{item}}"/>
+                        </block>
+                    </view>
+                </view>
+            </view>
+        </block>
+
+        <!--video类型-->
+        <block wx:elif="{{item.tag == 'video'}}">
+            <template is="wxParseVideo" data="{{item}}"/>  
+        </block>
+
+        <!--img类型-->
+        <block wx:elif="{{item.tag == 'img'}}">
+            <template is="wxParseImg" data="{{item}}"/>
+        </block>
+
+        <!--a类型-->
+        <block wx:elif="{{item.tag == 'a'}}">
+            <view bindtap="wxParseTagATap" class="wxParse-inline {{item.classStr}} wxParse-{{item.tag}}" data-src="{{item.attr.href}}"  style="{{item.styleStr}}">
+                <block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="index">
+                    <template is="wxParse5" data="{{item}}"/>
+                </block>
+            </view>
+        </block>
+        
+        <!--其他块级标签-->
+        <block wx:elif="{{item.tagType == 'block'}}">
+            <view class="{{item.classStr}} wxParse-{{item.tag}}" style="{{item.styleStr}}">
+                <block  wx:for="{{item.nodes}}" wx:for-item="item" wx:key="index">       
+                    <template is="wxParse5" data="{{item}}"/>                 
+                </block>
+            </view>
+        </block>
+
+        <!--内联标签-->
+        <view wx:else class="{{item.classStr}} wxParse-{{item.tag}} wxParse-{{item.tagType}}" style="{{item.styleStr}}">
+            <block  wx:for="{{item.nodes}}" wx:for-item="item" wx:key="index">       
+                <template is="wxParse5" data="{{item}}"/>                 
+            </block>
+        </view>
+
+    </block>
+
+    <!--判断是否是文本节点-->
+    <block wx:elif="{{item.node == 'text'}}">
+        <!--如果是,直接进行-->
+        <template is="WxEmojiView" data="{{item}}"/>
+    </block>
+
+</template>
+
+<!--循环模版-->
+<template name="wxParse5">
+    <!--<template is="wxParse6" data="{{item}}" />-->
+    <!--判断是否是标签节点-->
+    <block wx:if="{{item.node == 'element'}}">
+        <block wx:if="{{item.tag == 'button'}}">
+            <button type="default" size="mini" >
+                <block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="index">
+                    <template is="wxParse6" data="{{item}}"/>
+                </block>
+             </button>
+        </block>
+        <!--li类型-->
+        <block wx:elif="{{item.tag == 'li'}}">
+            <view class="{{item.classStr}} wxParse-li">
+                <view class="{{item.classStr}} wxParse-li-inner">
+                    <view class="{{item.classStr}} wxParse-li-text">
+                        <view class="{{item.classStr}} wxParse-li-circle"></view>
+                    </view>
+                    <view class="{{item.classStr}} wxParse-li-text">
+                        <block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="index">
+                            <template is="wxParse6" data="{{item}}"/>
+                        </block>
+                    </view>
+                </view>
+            </view>
+        </block>
+
+        <!--video类型-->
+        <block wx:elif="{{item.tag == 'video'}}">
+            <template is="wxParseVideo" data="{{item}}"/>  
+        </block>
+
+        <!--img类型-->
+        <block wx:elif="{{item.tag == 'img'}}">
+            <template is="wxParseImg" data="{{item}}"/>
+        </block>
+
+        <!--a类型-->
+        <block wx:elif="{{item.tag == 'a'}}">
+            <view bindtap="wxParseTagATap" class="wxParse-inline {{item.classStr}} wxParse-{{item.tag}}" data-src="{{item.attr.href}}"  style="{{item.styleStr}}">
+                <block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="index">
+                    <template is="wxParse6" data="{{item}}"/>
+                </block>
+            </view>
+        </block>
+        
+        <!--其他块级标签-->
+        <block wx:elif="{{item.tagType == 'block'}}">
+            <view class="{{item.classStr}} wxParse-{{item.tag}}" style="{{item.styleStr}}">
+                <block  wx:for="{{item.nodes}}" wx:for-item="item" wx:key="index">       
+                    <template is="wxParse6" data="{{item}}"/>                 
+                </block>
+            </view>
+        </block>
+
+        <!--内联标签-->
+        <view wx:else class="{{item.classStr}} wxParse-{{item.tag}} wxParse-{{item.tagType}}" style="{{item.styleStr}}">
+            <block  wx:for="{{item.nodes}}" wx:for-item="item" wx:key="index">       
+                <template is="wxParse6" data="{{item}}"/>                 
+            </block>
+        </view>
+
+    </block>
+
+    <!--判断是否是文本节点-->
+    <block wx:elif="{{item.node == 'text'}}">
+        <!--如果是,直接进行-->
+        <template is="WxEmojiView" data="{{item}}"/>
+    </block>
+
+</template>
+
+<!--循环模版-->
+<template name="wxParse6">
+    <!--<template is="wxParse7" data="{{item}}" />-->
+    <!--判断是否是标签节点-->
+    <block wx:if="{{item.node == 'element'}}">
+        <block wx:if="{{item.tag == 'button'}}">
+            <button type="default" size="mini" >
+                <block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="index">
+                    <template is="wxParse7" data="{{item}}"/>
+                </block>
+             </button>
+        </block>
+        <!--li类型-->
+        <block wx:elif="{{item.tag == 'li'}}">
+            <view class="{{item.classStr}} wxParse-li">
+                <view class="{{item.classStr}} wxParse-li-inner">
+                    <view class="{{item.classStr}} wxParse-li-text">
+                        <view class="{{item.classStr}} wxParse-li-circle"></view>
+                    </view>
+                    <view class="{{item.classStr}} wxParse-li-text">
+                        <block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="index">
+                            <template is="wxParse7" data="{{item}}"/>
+                        </block>
+                    </view>
+                </view>
+            </view>
+        </block>
+
+        <!--video类型-->
+        <block wx:elif="{{item.tag == 'video'}}">
+            <template is="wxParseVideo" data="{{item}}"/>  
+        </block>
+
+        <!--img类型-->
+        <block wx:elif="{{item.tag == 'img'}}">
+            <template is="wxParseImg" data="{{item}}"/>
+        </block>
+
+        <!--a类型-->
+        <block wx:elif="{{item.tag == 'a'}}">
+            <view bindtap="wxParseTagATap" class="wxParse-inline {{item.classStr}} wxParse-{{item.tag}}" data-src="{{item.attr.href}}"  style="{{item.styleStr}}">
+                <block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="index">
+                    <template is="wxParse7" data="{{item}}"/>
+                </block>
+            </view>
+        </block>
+        
+        <!--其他块级标签-->
+        <block wx:elif="{{item.tagType == 'block'}}">
+            <view class="{{item.classStr}} wxParse-{{item.tag}}" style="{{item.styleStr}}">
+                <block  wx:for="{{item.nodes}}" wx:for-item="item" wx:key="index">       
+                    <template is="wxParse7" data="{{item}}"/>                 
+                </block>
+            </view>
+        </block>
+
+        <!--内联标签-->
+        <view wx:else class="{{item.classStr}} wxParse-{{item.tag}} wxParse-{{item.tagType}}" style="{{item.styleStr}}">
+            <block  wx:for="{{item.nodes}}" wx:for-item="item" wx:key="index">       
+                <template is="wxParse7" data="{{item}}"/>                 
+            </block>
+        </view>
+
+    </block>
+
+    <!--判断是否是文本节点-->
+    <block wx:elif="{{item.node == 'text'}}">
+        <!--如果是,直接进行-->
+        <template is="WxEmojiView" data="{{item}}"/>
+    </block>
+
+</template>
+<!--循环模版-->
+<template name="wxParse7">
+    <!--<template is="wxParse8" data="{{item}}" />-->
+    <!--判断是否是标签节点-->
+    <block wx:if="{{item.node == 'element'}}">
+        <block wx:if="{{item.tag == 'button'}}">
+            <button type="default" size="mini" >
+                <block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="index">
+                    <template is="wxParse8" data="{{item}}"/>
+                </block>
+             </button>
+        </block>
+        <!--li类型-->
+        <block wx:elif="{{item.tag == 'li'}}">
+            <view class="{{item.classStr}} wxParse-li">
+                <view class="{{item.classStr}} wxParse-li-inner">
+                    <view class="{{item.classStr}} wxParse-li-text">
+                        <view class="{{item.classStr}} wxParse-li-circle"></view>
+                    </view>
+                    <view class="{{item.classStr}} wxParse-li-text">
+                        <block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="index">
+                            <template is="wxParse8" data="{{item}}"/>
+                        </block>
+                    </view>
+                </view>
+            </view>
+        </block>
+
+        <!--video类型-->
+        <block wx:elif="{{item.tag == 'video'}}">
+            <template is="wxParseVideo" data="{{item}}"/>  
+        </block>
+
+        <!--img类型-->
+        <block wx:elif="{{item.tag == 'img'}}">
+            <template is="wxParseImg" data="{{item}}"/>
+        </block>
+
+        <!--a类型-->
+        <block wx:elif="{{item.tag == 'a'}}">
+            <view bindtap="wxParseTagATap" class="wxParse-inline {{item.classStr}} wxParse-{{item.tag}}" data-src="{{item.attr.href}}"  style="{{item.styleStr}}">
+                <block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="index">
+                    <template is="wxParse8" data="{{item}}"/>
+                </block>
+            </view>
+        </block>
+        
+        <!--其他块级标签-->
+        <block wx:elif="{{item.tagType == 'block'}}">
+            <view class="{{item.classStr}} wxParse-{{item.tag}}" style="{{item.styleStr}}">
+                <block  wx:for="{{item.nodes}}" wx:for-item="item" wx:key="index">       
+                    <template is="wxParse8" data="{{item}}"/>                 
+                </block>
+            </view>
+        </block>
+
+        <!--内联标签-->
+        <view wx:else class="{{item.classStr}} wxParse-{{item.tag}} wxParse-{{item.tagType}}" style="{{item.styleStr}}">
+            <block  wx:for="{{item.nodes}}" wx:for-item="item" wx:key="index">       
+                <template is="wxParse8" data="{{item}}"/>                 
+            </block>
+        </view>
+
+    </block>
+
+    <!--判断是否是文本节点-->
+    <block wx:elif="{{item.node == 'text'}}">
+        <!--如果是,直接进行-->
+        <template is="WxEmojiView" data="{{item}}"/>
+    </block>
+
+</template>
+
+<!--循环模版-->
+<template name="wxParse8">
+    <!--<template is="wxParse9" data="{{item}}" />-->
+    <!--判断是否是标签节点-->
+    <block wx:if="{{item.node == 'element'}}">
+        <block wx:if="{{item.tag == 'button'}}">
+            <button type="default" size="mini" >
+                <block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="index">
+                    <template is="wxParse9" data="{{item}}"/>
+                </block>
+             </button>
+        </block>
+        <!--li类型-->
+        <block wx:elif="{{item.tag == 'li'}}">
+            <view class="{{item.classStr}} wxParse-li">
+                <view class="{{item.classStr}} wxParse-li-inner">
+                    <view class="{{item.classStr}} wxParse-li-text">
+                        <view class="{{item.classStr}} wxParse-li-circle"></view>
+                    </view>
+                    <view class="{{item.classStr}} wxParse-li-text">
+                        <block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="index">
+                            <template is="wxParse9" data="{{item}}"/>
+                        </block>
+                    </view>
+                </view>
+            </view>
+        </block>
+
+        <!--video类型-->
+        <block wx:elif="{{item.tag == 'video'}}">
+            <template is="wxParseVideo" data="{{item}}"/>  
+        </block>
+
+        <!--img类型-->
+        <block wx:elif="{{item.tag == 'img'}}">
+            <template is="wxParseImg" data="{{item}}"/>
+        </block>
+
+        <!--a类型-->
+        <block wx:elif="{{item.tag == 'a'}}">
+            <view bindtap="wxParseTagATap" class="wxParse-inline {{item.classStr}} wxParse-{{item.tag}}" data-src="{{item.attr.href}}"  style="{{item.styleStr}}">
+                <block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="index">
+                    <template is="wxParse9" data="{{item}}"/>
+                </block>
+            </view>
+        </block>
+        
+        <!--其他块级标签-->
+        <block wx:elif="{{item.tagType == 'block'}}">
+            <view class="{{item.classStr}} wxParse-{{item.tag}}" style="{{item.styleStr}}">
+                <block  wx:for="{{item.nodes}}" wx:for-item="item" wx:key="index">       
+                    <template is="wxParse9" data="{{item}}"/>                 
+                </block>
+            </view>
+        </block>
+
+        <!--内联标签-->
+        <view wx:else class="{{item.classStr}} wxParse-{{item.tag}} wxParse-{{item.tagType}}" style="{{item.styleStr}}">
+            <block  wx:for="{{item.nodes}}" wx:for-item="item" wx:key="index">       
+                <template is="wxParse9" data="{{item}}"/>                 
+            </block>
+        </view>
+
+    </block>
+
+    <!--判断是否是文本节点-->
+    <block wx:elif="{{item.node == 'text'}}">
+        <!--如果是,直接进行-->
+        <template is="WxEmojiView" data="{{item}}"/>
+    </block>
+
+</template>
+
+<!--循环模版-->
+<template name="wxParse9">
+    <!--<template is="wxParse10" data="{{item}}" />-->
+    <!--判断是否是标签节点-->
+    <block wx:if="{{item.node == 'element'}}">
+        <block wx:if="{{item.tag == 'button'}}">
+            <button type="default" size="mini" >
+                <block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="index">
+                    <template is="wxParse10" data="{{item}}"/>
+                </block>
+             </button>
+        </block>
+        <!--li类型-->
+        <block wx:elif="{{item.tag == 'li'}}">
+            <view class="{{item.classStr}} wxParse-li">
+                <view class="{{item.classStr}} wxParse-li-inner">
+                    <view class="{{item.classStr}} wxParse-li-text">
+                        <view class="{{item.classStr}} wxParse-li-circle"></view>
+                    </view>
+                    <view class="{{item.classStr}} wxParse-li-text">
+                        <block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="index">
+                            <template is="wxParse10" data="{{item}}"/>
+                        </block>
+                    </view>
+                </view>
+            </view>
+        </block>
+
+        <!--video类型-->
+        <block wx:elif="{{item.tag == 'video'}}">
+            <template is="wxParseVideo" data="{{item}}"/>  
+        </block>
+
+        <!--img类型-->
+        <block wx:elif="{{item.tag == 'img'}}">
+            <template is="wxParseImg" data="{{item}}"/>
+        </block>
+
+        <!--a类型-->
+        <block wx:elif="{{item.tag == 'a'}}">
+            <view bindtap="wxParseTagATap" class="wxParse-inline {{item.classStr}} wxParse-{{item.tag}}" data-src="{{item.attr.href}}"  style="{{item.styleStr}}">
+                <block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="index">
+                    <template is="wxParse10" data="{{item}}"/>
+                </block>
+            </view>
+        </block>
+        
+        <!--其他块级标签-->
+        <block wx:elif="{{item.tagType == 'block'}}">
+            <view class="{{item.classStr}} wxParse-{{item.tag}}" style="{{item.styleStr}}">
+                <block  wx:for="{{item.nodes}}" wx:for-item="item" wx:key="index">       
+                    <template is="wxParse10" data="{{item}}"/>                 
+                </block>
+            </view>
+        </block>
+
+        <!--内联标签-->
+        <view wx:else class="{{item.classStr}} wxParse-{{item.tag}} wxParse-{{item.tagType}}" style="{{item.styleStr}}">
+            <block  wx:for="{{item.nodes}}" wx:for-item="item" wx:key="index">       
+                <template is="wxParse10" data="{{item}}"/>                 
+            </block>
+        </view>
+
+    </block>
+
+    <!--判断是否是文本节点-->
+    <block wx:elif="{{item.node == 'text'}}">
+        <!--如果是,直接进行-->
+        <template is="WxEmojiView" data="{{item}}"/>
+    </block>
+
+</template>
+
+<!--循环模版-->
+<template name="wxParse10">
+    <!--<template is="wxParse11" data="{{item}}" />-->
+    <!--判断是否是标签节点-->
+    <block wx:if="{{item.node == 'element'}}">
+        <block wx:if="{{item.tag == 'button'}}">
+            <button type="default" size="mini" >
+                <block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="index">
+                    <template is="wxParse11" data="{{item}}"/>
+                </block>
+             </button>
+        </block>
+        <!--li类型-->
+        <block wx:elif="{{item.tag == 'li'}}">
+            <view class="{{item.classStr}} wxParse-li">
+                <view class="{{item.classStr}} wxParse-li-inner">
+                    <view class="{{item.classStr}} wxParse-li-text">
+                        <view class="{{item.classStr}} wxParse-li-circle"></view>
+                    </view>
+                    <view class="{{item.classStr}} wxParse-li-text">
+                        <block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="index">
+                            <template is="wxParse11" data="{{item}}"/>
+                        </block>
+                    </view>
+                </view>
+            </view>
+        </block>
+
+        <!--video类型-->
+        <block wx:elif="{{item.tag == 'video'}}">
+            <template is="wxParseVideo" data="{{item}}"/>  
+        </block>
+
+        <!--img类型-->
+        <block wx:elif="{{item.tag == 'img'}}">
+            <template is="wxParseImg" data="{{item}}"/>
+        </block>
+
+        <!--a类型-->
+        <block wx:elif="{{item.tag == 'a'}}">
+            <view bindtap="wxParseTagATap" class="wxParse-inline {{item.classStr}} wxParse-{{item.tag}}" data-src="{{item.attr.href}}"  style="{{item.styleStr}}">
+                <block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="index">
+                    <template is="wxParse11" data="{{item}}"/>
+                </block>
+            </view>
+        </block>
+        
+        <!--其他块级标签-->
+        <block wx:elif="{{item.tagType == 'block'}}">
+            <view class="{{item.classStr}} wxParse-{{item.tag}}" style="{{item.styleStr}}">
+                <block  wx:for="{{item.nodes}}" wx:for-item="item" wx:key="index">       
+                    <template is="wxParse11" data="{{item}}"/>                 
+                </block>
+            </view>
+        </block>
+
+        <!--内联标签-->
+        <view wx:else class="{{item.classStr}} wxParse-{{item.tag}} wxParse-{{item.tagType}}" style="{{item.styleStr}}">
+            <block  wx:for="{{item.nodes}}" wx:for-item="item" wx:key="index">       
+                <template is="wxParse11" data="{{item}}"/>                 
+            </block>
+        </view>
+
+    </block>
+
+    <!--判断是否是文本节点-->
+    <block wx:elif="{{item.node == 'text'}}">
+        <!--如果是,直接进行-->
+        <template is="WxEmojiView" data="{{item}}"/>
+    </block>
+
+</template>
+
+<!--循环模版-->
+<template name="wxParse11">
+    <!--<template is="wxParse12" data="{{item}}" />-->
+    <!--判断是否是标签节点-->
+    <block wx:if="{{item.node == 'element'}}">
+        <block wx:if="{{item.tag == 'button'}}">
+            <button type="default" size="mini" >
+                <block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="index">
+                    <template is="wxParse12" data="{{item}}"/>
+                </block>
+             </button>
+        </block>
+        <!--li类型-->
+        <block wx:elif="{{item.tag == 'li'}}">
+            <view class="{{item.classStr}} wxParse-li">
+                <view class="{{item.classStr}} wxParse-li-inner">
+                    <view class="{{item.classStr}} wxParse-li-text">
+                        <view class="{{item.classStr}} wxParse-li-circle"></view>
+                    </view>
+                    <view class="{{item.classStr}} wxParse-li-text">
+                        <block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="index">
+                            <template is="wxParse12" data="{{item}}"/>
+                        </block>
+                    </view>
+                </view>
+            </view>
+        </block>
+
+        <!--video类型-->
+        <block wx:elif="{{item.tag == 'video'}}">
+            <template is="wxParseVideo" data="{{item}}"/>  
+        </block>
+
+        <!--img类型-->
+        <block wx:elif="{{item.tag == 'img'}}">
+            <template is="wxParseImg" data="{{item}}"/>
+        </block>
+
+        <!--a类型-->
+        <block wx:elif="{{item.tag == 'a'}}">
+            <view bindtap="wxParseTagATap" class="wxParse-inline {{item.classStr}} wxParse-{{item.tag}}" data-src="{{item.attr.href}}"  style="{{item.styleStr}}">
+                <block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="index">
+                    <template is="wxParse12" data="{{item}}"/>
+                </block>
+            </view>
+        </block>
+        
+        <!--其他块级标签-->
+        <block wx:elif="{{item.tagType == 'block'}}">
+            <view class="{{item.classStr}} wxParse-{{item.tag}}" style="{{item.styleStr}}">
+                <block  wx:for="{{item.nodes}}" wx:for-item="item" wx:key="index">       
+                    <template is="wxParse12" data="{{item}}"/>                 
+                </block>
+            </view>
+        </block>
+
+        <!--内联标签-->
+        <view wx:else class="{{item.classStr}} wxParse-{{item.tag}} wxParse-{{item.tagType}}" style="{{item.styleStr}}">
+            <block  wx:for="{{item.nodes}}" wx:for-item="item" wx:key="index">       
+                <template is="wxParse12" data="{{item}}"/>                 
+            </block>
+        </view>
+
+    </block>
+
+    <!--判断是否是文本节点-->
+    <block wx:elif="{{item.node == 'text'}}">
+        <!--如果是,直接进行-->
+        <template is="WxEmojiView" data="{{item}}"/>
+    </block>
+
+</template>

+ 214 - 0
lib/wxParse/wxParse.wxss

@@ -0,0 +1,214 @@
+
+/**
+ * author: Di (微信小程序开发工程师)
+ * organization: WeAppDev(微信小程序开发论坛)(http://weappdev.com)
+ *               垂直微信小程序开发交流社区
+ * 
+ * github地址: https://github.com/icindy/wxParse
+ * 
+ * for: 微信小程序富文本解析
+ * detail : http://weappdev.com/t/wxparse-alpha0-1-html-markdown/184
+ */
+
+.wxParse{
+    margin: 0 5px;
+    font-family: Helvetica,sans-serif;
+    font-size: 28rpx;
+    color: #666;
+    line-height: 1.8;
+}
+view{
+    word-break:break-all; overflow:auto;
+}
+.wxParse-inline{
+    display: inline;
+    margin: 0;
+    padding: 0;
+}
+/*//标题 */
+.wxParse-div{margin: 0;padding: 0;}
+.wxParse-h1{ font-size:2em; margin: .67em 0 }
+.wxParse-h2{ font-size:1.5em; margin: .75em 0 }
+.wxParse-h3{ font-size:1.17em; margin: .83em 0 }
+.wxParse-h4{ margin: 1.12em 0}
+.wxParse-h5 { font-size:.83em; margin: 1.5em 0 }
+.wxParse-h6{ font-size:.75em; margin: 1.67em 0 }
+
+.wxParse-h1 {
+  font-size: 18px;
+  font-weight: 400;
+  margin-bottom: .9em;
+}
+.wxParse-h2 {
+  font-size: 16px;
+  font-weight: 400;
+  margin-bottom: .34em;
+}
+.wxParse-h3 {
+  font-weight: 400;
+  font-size: 15px;
+  margin-bottom: .34em;
+}
+.wxParse-h4 {
+  font-weight: 400;
+  font-size: 14px;
+  margin-bottom: .24em;
+}
+.wxParse-h5 {
+  font-weight: 400;
+  font-size: 13px;
+  margin-bottom: .14em;
+}
+.wxParse-h6 {
+  font-weight: 400;
+  font-size: 12px;
+  margin-bottom: .04em;
+}
+
+.wxParse-h1, .wxParse-h2, .wxParse-h3, .wxParse-h4, .wxParse-h5, .wxParse-h6, .wxParse-b, .wxParse-strong  { font-weight: bolder }
+
+.wxParse-i,.wxParse-cite,.wxParse-em,.wxParse-var,.wxParse-address{font-style:italic}
+.wxParse-pre,.wxParse-tt,.wxParse-code,.wxParse-kbd,.wxParse-samp{font-family:monospace}
+.wxParse-pre{white-space:pre}
+.wxParse-big{font-size:1.17em}
+.wxParse-small,.wxParse-sub,.wxParse-sup{font-size:.83em}
+.wxParse-sub{vertical-align:sub}
+.wxParse-sup{vertical-align:super}
+.wxParse-s,.wxParse-strike,.wxParse-del{text-decoration:line-through}
+/*wxparse-自定义个性化的css样式*/
+/*增加video的css样式*/
+.wxParse-strong,wxParse-s{display: inline}
+.wxParse-a{
+    color: deepskyblue;
+    word-break:break-all;
+    overflow:auto;
+}
+
+.wxParse-video{
+    text-align: center;
+    margin: 10px 0;
+}
+
+.wxParse-video-video{
+    width:100%;
+}
+
+.wxParse-img{
+    background-color: #efefef;
+    overflow: hidden;
+    width:40px;
+    height: 40px;
+}
+
+.wxParse-blockquote {
+    margin: 0;
+    padding:10px 0 10px 5px;
+    font-family:Courier, Calibri,"宋体";
+    background:#f5f5f5;
+    border-left: 3px solid #dbdbdb;
+}
+
+.wxParse-code,.wxParse-wxxxcode-style{
+    display: inline;
+    background:#f5f5f5;
+}
+.wxParse-ul{
+    margin: 20rpx 10rpx;
+}
+
+.wxParse-li,.wxParse-li-inner{
+    display: flex;
+    align-items: baseline;
+    margin: 10rpx 0;
+}
+.wxParse-li-text{
+    align-items: center;
+    line-height: 20px;
+}
+
+.wxParse-li-circle{
+    display: inline-flex;
+    width: 5px;
+    height: 5px;
+    margin-right: 5px;
+    background-color: #333;
+    border-radius: 50%;
+}
+
+.wxParse-li-square{
+    display: inline-flex;
+    width: 10rpx;
+    height: 10rpx;
+    background-color: #333;
+    margin-right: 5px;
+}
+.wxParse-li-ring{
+    display: inline-flex;
+    width: 10rpx;
+    height: 10rpx;
+    border: 2rpx solid #333;
+    border-radius: 50%;
+    background-color: #fff;
+    margin-right: 5px;
+}
+
+/*.wxParse-table{
+    width: 100%;
+    height: 400px;
+}
+.wxParse-thead,.wxParse-tfoot,.wxParse-tr{
+    display: flex;
+    flex-direction: row;
+}
+.wxParse-th,.wxParse-td{
+    display: flex;
+    width: 580px;
+    overflow: auto;
+}*/
+
+.wxParse-u {
+  text-decoration: underline;
+}
+.wxParse-hide{
+    display: none;
+}
+.WxEmojiView{
+    align-items: center;
+}
+.wxEmoji{
+    width: 16px;
+    height:16px;
+}
+.wxParse-tr{
+	display: flex;
+	border-right:1px solid #e0e0e0;
+	border-bottom:1px solid #e0e0e0;
+}
+.wxParse-th,
+.wxParse-td{
+	flex:1;
+	padding:5px;
+	font-size:28rpx;
+	border-left:1px solid #e0e0e0;
+	word-break: break-all;
+}
+.wxParse-td:last{
+	border-top:1px solid #e0e0e0;
+}
+.wxParse-th{
+	background:#f0f0f0;
+	border-top:1px solid #e0e0e0;
+}
+
+.wxParse-dl {
+	margin-block-start: 1em;
+	margin-block-end: 1em;
+	margin-inline-start: 0px;
+	margin-inline-end: 0px;
+}
+.wxParse-dt {
+	margin: 0 10rpx;
+}
+.wxParse-dd {
+	margin-inline-start: 40px;
+}

+ 5 - 0
package.json

@@ -0,0 +1,5 @@
+{
+  "dependencies": {
+    "@vant/weapp": "^1.10.2"
+  }
+}

+ 157 - 0
packageGoods/detail/detail.js

@@ -0,0 +1,157 @@
+let WxParse = require('../../lib/wxParse/wxParse')
+
+let util = require('../../utils/util')
+let api = require('../../config/api')
+
+Page({
+  data: {
+		id: 0, // 商品id
+		productId: 0, // 规格id
+		shareId: 0, // 分享id
+		shareUrl: '', // 分享图片二维码
+
+    show_spec: false, // 是否显示 商品规格弹出框
+		
+    swiper_index: 0, // 当前图片index
+		goodsData: null,
+		
+		collectId: 0, // 收藏id
+  },
+
+  onLoad: function({ scene, obj }) {
+		let id = 0
+		let productId = 0
+		let shareId = 0
+		if (scene) { // 分享
+			// 商品id,商品类型,商品活动id,分享用户id
+			[id, shareId] = decodeURIComponent(scene).split(',')
+		} else {
+			const data = JSON.parse(obj)
+			id = data.id
+			productId = data.productId ? data.productId : 0
+		}
+		this.setData({ id, productId, shareId })
+		if(wx.getStorageSync('token')) this.setBrowse(id)
+	},
+	
+	onShow() {
+		this.getGoodsDetail()
+	},
+
+	// 足迹
+	setBrowse(goodsId) {
+		util.showLoad('加载中')
+    util.request(api.AddBrowse, { goodsId },'POST').then(res => {
+      util.hideLoad()
+      if (res.errno != 0) util.showErrorToast(res.errmsg)
+    }).catch(() => {
+      util.hideLoad()
+      util.showErrorToast('网络连接失败')
+    })
+	},
+
+  getGoodsDetail() {
+		const { id, productId } = this.data
+
+		util.showLoad('加载中')
+    util.request(api.GoodsDetail, { id }).then(res => {
+      util.hideLoad()
+      if (res.errno === 0) {
+				const { info, productList, collectId } = res.data
+				const products = productList.map(p => {
+					p.stock = p.number
+					return p
+				})
+
+				
+				WxParse.wxParse('goodsDetail', 'html', info.detail, this)
+				const picUrl = info.picUrl.split(',')
+
+				const pro_i = productId ? products.findIndex(p => p.id == productId) : 0
+
+				const goodsData = {
+					...info,
+					detail: undefined,
+					products,
+					curSpec: products[pro_i],
+					picUrl
+				}
+				delete goodsData.detail
+
+				this.setData({ goodsData, collectId: collectId || 0 })
+      } else util.showErrorToast(res.errmsg)
+    }).catch(() => {
+      util.hideLoad()
+      util.showErrorToast('网络连接失败')
+    })
+	},
+
+  prevent() {
+    return false
+  },
+
+  // 设置当前图片index
+  setPicIndex({ detail }) {
+    this.setData({ swiper_index: detail.current })
+  },
+
+  // 预览商品图片
+	previewImage({ currentTarget }) {
+		const { current, urls } = currentTarget.dataset
+		wx.previewImage({ current, urls })
+	},
+
+	// 收藏取消收藏
+	toggleCollect() {
+		const { collectId, id } = this.data
+		util.showLoad('加载中')
+		if (collectId) { // 取消收藏
+			util.request(api.CollectDelete, [collectId], 'POST').then(res => {
+				util.hideLoad()
+				if (res.errno === 0) {
+					util.showToast('已取消收藏')
+					this.setData({ collectId: 0 })
+				} else util.showErrorToast(res.errmsg)
+			}).catch(() => {
+				util.hideLoad()
+				util.showErrorToast('网络连接失败')
+			})
+		} else {
+			util.request(api.CollectAdd, id, 'POST').then(res => {
+				util.hideLoad()
+				if (res.errno === 0) {
+					util.showToast('已添加收藏')
+					this.setData({ collectId: res.data.id })
+				} else util.showErrorToast(res.errmsg)
+			}).catch(() => {
+				util.hideLoad()
+				util.showErrorToast('网络连接失败')
+			})
+		}
+	},
+
+  // 显示规格弹出框
+  showSpec() {
+		this.setData({ show_spec: true })
+	},
+	
+  // 隐藏规格弹出框
+  hideSpec() {
+		this.setData({ show_spec: false })
+	},
+
+	onShareAppMessage({ from }) {
+		const { id, productId, goodsData } = this.data
+		const obj = { id, productId }
+
+		const promise = new Promise(resolve => {
+			resolve({
+				title: '富玖铭商户',
+				path: `/packageGoods/detail/detail?obj=${JSON.stringify(obj)}`
+			})
+		})
+		return from == "button" ? { title: goodsData.name, imageUrl: goodsData.picUrl[0] } : promise
+	},
+
+	onShareTimeline() {}
+})

+ 6 - 0
packageGoods/detail/detail.json

@@ -0,0 +1,6 @@
+{
+  "navigationBarTitleText": "商品详情",
+  "usingComponents": {
+    "spec-popup": "/lib/spec-popup/index"
+  }
+}

+ 58 - 0
packageGoods/detail/detail.wxml

@@ -0,0 +1,58 @@
+<view class="goods-container">
+  <wxs src="../../utils/filter.wxs" module="filter" />
+
+  <!-- 轮播图 -->
+  <view class="swiper">
+    <swiper duration="600" bindchange="setPicIndex">
+      <swiper-item wx:for="{{ goodsData.picUrl }}" wx:key="index" data-current="{{ goodsData.picUrl[index] }}" data-urls="{{ goodsData.picUrl }}" bindtap="previewImage">
+				<image src="{{ item }}" />
+			</swiper-item>
+    </swiper>
+    <view class="dots">{{ swiper_index + 1 }}/{{ goodsData.picUrl.length }}</view>
+  </view>
+
+  <view class="goods-content">
+    <!-- 商品详情 -->
+    <view class="goods-detail jhx_bg0">
+      <view class="top acea-row row-between-wrapper">
+        <view class="price">¥<text>{{ goodsData.curSpec.price }}</text></view>
+				<button class="share-btn" open-type="share">
+					<image src="/packageGoods/detail/icon_share.png" />
+				</button>
+      </view>
+
+			<view class="acea-row row-between">
+      	<view class="name line1 line2">{{ goodsData.name }}</view>
+				<view wx:if="{{ collectId }}" class="collect">
+					<van-icon custom-class="collect-icon" name="goods-collect" color="#D32D2F" bindtap="toggleCollect" />
+					<view>已收藏</view>
+				</view>
+				<view wx:else class="collect">
+					<van-icon custom-class="collect-icon" name="goods-collect-o" color="#767a81" bindtap="toggleCollect" />
+					<view>收藏</view>
+				</view>
+			</view>
+    </view>
+
+    <!-- 相关信息 -->
+    <view class="information jhx_bg0">
+      <view class="default acea-row row-middle" bindtap="showSpec">
+        <view class="label">已选</view>
+        <view style="flex: 1" class="acea-row row-between">
+          <view>{{ filter.getCartSpec(goodsData.curSpec.specifications) }}</view>
+          <van-icon name="arrow" size="14" color="#8e8e8e" />
+        </view>
+      </view>
+    </view>
+  </view>
+  
+  <view class="introduce acea-row row-center-wrapper">详情介绍</view>
+  <!-- 详情图 -->
+  <view class="detail-drawing jhx_bg0">
+    <import src="/lib/wxParse/wxParse.wxml" />
+    <template is="wxParse" data="{{ wxParseData: goodsDetail.nodes }}" />
+  </view>
+
+  <!-- 商品规格弹出框 -->
+	<spec-popup show="{{ show_spec }}" goods="{{ goodsData }}" bindhideSpec="hideSpec" />
+</view>

+ 156 - 0
packageGoods/detail/detail.wxss

@@ -0,0 +1,156 @@
+@import '../../lib/wxParse/wxParse.wxss';
+
+page {
+	padding-bottom: calc(12rpx + constant(safe-area-inset-bottom));
+	padding-bottom: calc(12rpx + env(safe-area-inset-bottom));
+}
+
+.goods-container .icon {
+	width: 28rpx;
+	height: 28rpx;
+}
+
+.goods-container .swiper {
+	width: 100%;
+	height: 750rpx;
+	position: relative;
+}
+
+.goods-container swiper {
+	width: 100%;
+	height: 100%;
+}
+
+.goods-container swiper image {
+	width: 100%;
+	height: 100%;
+	background: #f2f2f2;
+}
+
+.goods-container .dots {
+	position: absolute;
+	bottom: 28rpx;
+	right: 28rpx;
+	width: 80rpx;
+	padding: 6rpx 0;
+	background: rgba(0, 0, 0, 0.3);
+	border-radius: 60rpx;
+	text-align: center;
+	line-height: 28rpx;
+	color: #FFF;
+}
+
+.goods-container .goods-content {
+	width: 100%;
+	padding: 0 24rpx;
+}
+
+.goods-container .goods-detail {
+	margin-top: 20rpx;
+	padding: 24rpx 12rpx 20rpx 20rpx;
+	border-radius: 12rpx;
+	font-family: HarmonyOS Sans SC-Medium, HarmonyOS Sans SC;
+}
+
+.goods-container .goods-detail .top {
+	margin-bottom: 16rpx;
+}
+
+.goods-container .goods-detail .top .price {
+	font-size: 40rpx;
+	font-family: DIN Alternate-Bold, DIN Alternate;
+	font-weight: bold;
+	color: #F94F50;
+}
+
+.goods-container .goods-detail .top .price text {
+	padding-left: 4rpx;
+	font-size: 56rpx;
+}
+
+.goods-container .goods-detail .top .share-btn {
+	display: inline-block;
+	height: 48rpx;
+	line-height: 48rpx;
+}
+
+.goods-container .goods-detail .top .share-btn image {
+	width: 48rpx;
+	height: 48rpx;
+}
+
+.goods-container .goods-detail .name {
+	flex: 1;
+	line-height: 48rpx;
+	font-size: 32rpx;
+	font-weight: 500;
+	color: #1A1A1A;
+}
+
+.goods-container .goods-detail .collect {
+	width: 76rpx;
+	margin-top: 8rpx;
+	text-align: center;
+	font-size: 22rpx;
+}
+
+.goods-container .goods-detail .collect .collect-icon {
+	font-size: 52rpx;
+	opacity: .8;
+}
+
+.goods-container .information {
+	margin: 16rpx 0;
+	padding: 20rpx;
+	border-radius: 20rpx;
+}
+
+.goods-container .information .default {
+	margin-bottom: 40rpx;
+	font-size: 24rpx;
+	color: #060606;
+}
+
+.goods-container .information .default:last-child {
+	margin-bottom: 0;
+}
+
+.goods-container .information .default .label {
+	margin-right: 40rpx;
+	color: #767E8B;
+}
+
+.goods-container .information .default .value {
+	flex: 1;
+	width: calc(100% - 88rpx);
+}
+
+.goods-container .information .default .value .addr {
+	width: calc(100% - 44rpx);
+}
+
+.goods-container .introduce {
+	margin: 54rpx 0 24rpx;
+	font-size: 22rpx;
+	color: #50555F;
+}
+
+.goods-container .introduce::before {
+	content: '';
+	display: inline-block;
+	width: 126rpx;
+	margin-right: 16rpx;
+	border: 2rpx dashed #767E8B;
+}
+
+.goods-container .introduce::after {
+	content: '';
+	display: inline-block;
+	width: 126rpx;
+	margin-left: 16rpx;
+	border: 2rpx dashed #767E8B;
+}
+
+.goods-container .detail-drawing {
+	margin-top: 16rpx;
+}

BIN
packageGoods/detail/icon_share.png


+ 47 - 0
packageLogin/login/login.js

@@ -0,0 +1,47 @@
+let util = require('../../utils/util')
+let user = require('../../utils/user')
+
+let app = getApp()
+
+Page({
+  data: {
+    read: false,
+    popover: false
+	},
+
+	showPopover() {
+		this.setData({ popover: true })
+	},
+
+	getPhoneNumber() {
+		util.showLoad('登录中')
+		user.getSessionKey().then(res => {
+			if (res.errcode) throw res.errmsg
+			else {
+				const data = { openId: res.openid }
+				user.loginByPhone(data).then(() => {
+					util.hideLoad()
+					wx.navigateBack()
+				}).catch(err => {
+					util.hideLoad()
+					wx.removeStorageSync('token')
+					wx.removeStorageSync('userInfo')
+					util.showErrorToast(err)
+				})
+			}
+		}).catch(() => {
+			util.hideLoad()
+			wx.removeStorageSync('token')
+					wx.removeStorageSync('userInfo')
+			util.showErrorToast('获取openid失败')
+		})
+	},
+
+  hidePopover() {
+    this.setData({ popover: false })
+  },
+
+  toggleRead({ detail }) {
+    this.setData({ read: detail })
+  }
+})

+ 6 - 0
packageLogin/login/login.json

@@ -0,0 +1,6 @@
+{
+  "navigationBarTitleText": "登录",
+  "usingComponents": {
+    "agreement": "/lib/login-agreement/index"
+  }
+}

+ 9 - 0
packageLogin/login/login.wxml

@@ -0,0 +1,9 @@
+<view class="login-container">
+  <view class="title">你好,</view>
+  <view class="subtitle">欢迎来到富玖铭</view>
+
+  <button wx:if="{{ read }}" class="btn wx-btn" hover-class="none" bind:tap="getPhoneNumber">微信用户一键登录</button>
+  <button wx:else class="btn wx-btn" hover-class="none" bindtap="showPopover">微信用户一键登录</button>
+
+  <agreement read="{{ read }}" show="{{ popover }}" bindtoggleRead="toggleRead" bindhidePopover="hidePopover" />
+</view>

Разлика између датотеке није приказан због своје велике величине
+ 39 - 0
packageLogin/login/login.wxss


BIN
packagePoster/images/bg.png


BIN
packagePoster/images/door-left.png


BIN
packagePoster/images/door-right.png


+ 71 - 0
packagePoster/index.js

@@ -0,0 +1,71 @@
+const config = require('../config/config')
+const util = require('../utils/util')
+const user = require('../utils/user')
+const download = require('../utils/download')
+
+Page({
+	data: {
+		open: false,
+
+		signInClass: "",
+		doorLeftClass: "",
+		doorRightClass: "",
+		doorInviteClass: ""
+	},
+
+	prevent() {
+    return false
+	},
+
+	toggleDoor() {
+		let { open, signInClass, doorLeftClass, doorRightClass, doorInviteClass } = this.data
+		signInClass = open && 'signIn-btn-show' || 'signIn-btn-hide'
+		if (open) setTimeout(() => this.setData({ signInClass: "" }), 1000);
+		doorLeftClass = !open && 'door-left-open' || 'door-left-close'
+		doorRightClass = !open && 'door-right-open' || 'door-right-close'
+		doorInviteClass = !open && 'door-invite-show' || 'door-invite-hide'
+		this.setData({ open: !open, signInClass, doorLeftClass, doorRightClass, doorInviteClass })
+	},
+
+	showAgreement({ currentTarget }) {
+		const { type } =	currentTarget.dataset
+		const url = type == 'user' ? config.userAgreement : config.privacyPolicy
+		util.showLoad('加载中')
+		download.openAgreement(url).then(() => util.hideLoad()).catch(() => util.hideLoad())
+	},
+
+	login() {
+		if (wx.getStorageSync('token')) return wx.reLaunch({ url: '/pages/index/index' })
+
+		util.showLoad('登录中')
+		user.getSessionKey().then(res => {
+			if (res.errcode) throw res.errmsg
+			else {
+				const data = { openId: res.openid }
+				user.loginByPhone(data).then(() => {
+					util.hideLoad()
+					wx.reLaunch({ url: '/pages/index/index' })
+				}).catch(err => {
+					util.hideLoad()
+					wx.removeStorageSync('token')
+					wx.removeStorageSync('userInfo')
+					util.showErrorToast(err)
+				})
+			}
+		}).catch(() => {
+			util.hideLoad()
+			wx.removeStorageSync('token')
+			wx.removeStorageSync('userInfo')
+			util.showErrorToast('获取openid失败')
+		})
+	},
+	
+	onShareAppMessage() {
+		return promise = new Promise(resolve => {
+			resolve({
+				title: '八马茶业开业邀请',
+				path: "/packagePoster/index"
+			})
+		})
+	}
+})

+ 4 - 0
packagePoster/index.json

@@ -0,0 +1,4 @@
+{
+  "navigationStyle": "custom",
+  "usingComponents": {}
+}

+ 33 - 0
packagePoster/index.wxml

@@ -0,0 +1,33 @@
+<view class='poster'>
+	<image class="backgroundImg" src="./images/bg.png" />
+	
+	<view class="background-door">
+		<view class="btn signIn-btn {{ signInClass }}" bindtap="toggleDoor">签到</view>
+		
+		<view class="background-door__left">
+			<image class="{{ doorLeftClass }}" mode="heightFix" src="./images/door-left.png" />
+		</view>
+		<view class="background-door__right">
+			<image class="{{ doorRightClass }}" mode="heightFix" src="./images/door-right.png" />
+		</view>
+
+		<view class="background-door__invite {{ doorInviteClass }}">
+			<div class="border_corner border_corner_left_top"></div>
+			<div class="border_corner border_corner_right_top"></div>
+			<div class="border_corner border_corner_left_bottom"></div>
+			<div class="border_corner border_corner_right_bottom"></div>
+			
+			<view class="content">
+				请您在使用<text class="keynote">富玖铭小程序</text>前点击
+				<text class="agreement" data-type="user" catchtap="showAgreement">《用户协议》</text>
+				<text class="agreement" data-type="privacy" catchtap="showAgreement">《隐私政策》</text>并仔细阅读。如您同意协议的全部内容,请点击"<text class="keynote">同意</text>"并开始使用我们的服务。
+			</view>
+
+			<view class="btn-group">
+				<view class="btn" bindtap="toggleDoor">取消</view>
+				<view class="btn" bindtap="login">同意</view>
+			</view>
+		</view>
+	</view>
+
+</view>

+ 183 - 0
packagePoster/index.wxss

@@ -0,0 +1,183 @@
+.poster {
+	position: relative;
+	width: 100%;
+	height: 100vh;
+	background: #c11f1b;
+}
+
+.poster .btn {
+	text-align: center;
+	line-height: 100rpx;
+	font-size: 16px;
+	font-weight: 500;
+	color: #e5bb8f;
+}
+
+.poster .backgroundImg {
+	position: absolute;
+	top: calc(constant(safe-area-inset-bottom) / 2);
+	top: calc(env(safe-area-inset-bottom) / 2);
+	width: 100%;
+	height: calc(100% - constant(safe-area-inset-bottom));
+	height: calc(100% - env(safe-area-inset-bottom));
+}
+
+.poster .background-door {
+	position: absolute;
+	bottom: calc(constant(safe-area-inset-bottom) / 2);
+	bottom: calc(env(safe-area-inset-bottom) / 2);
+	width: 100%;
+	height: calc(55% - constant(safe-area-inset-bottom));
+	height: calc(55% - env(safe-area-inset-bottom));
+	perspective: 500px;
+}
+
+.poster .background-door .signIn-btn {
+	z-index: 10;
+	position: absolute;
+	bottom: 30%;
+	left: 35%;
+	width: 30%;
+	padding-left: 10rpx;
+	background: linear-gradient(to right, #cf382c, #b71619);
+  box-shadow: 0 0 48rpx #b71619;
+	border-radius: 20rpx;
+	letter-spacing: 10rpx;
+	animation: signInBtn 1.5s ease-in-out infinite;
+}
+
+.poster .background-door .signIn-btn-hide {
+	opacity: 0;
+	animation: hide 0.2s linear;
+}
+
+.poster .background-door .signIn-btn-show {
+	animation: show 1s ease-in;
+}
+
+.poster .background-door .background-door__left,
+.poster .background-door .background-door__right {
+	position: absolute;
+	width: 50%;
+	height: 100%;
+	perspective: 500px;
+}
+
+.poster .background-door .background-door__right {
+	right: 0;
+}
+
+.poster .background-door image {
+	position: absolute;
+	height: 100%;
+	transform-origin: right center;
+}
+
+.poster .background-door .background-door__left image {
+	right: 0;
+	transform-origin: left center;
+}
+
+.poster .background-door .door-left-open {
+	transform: rotateY(-130deg);
+	animation: left-open 1s linear;
+}
+
+.poster .background-door .door-left-close {
+	transform: rotateY(0deg);
+	animation: left-close 1s linear;
+}
+
+.poster .background-door .door-right-open {
+	transform: rotateY(130deg);
+	animation: right-open 1s linear;
+}
+
+.poster .background-door .door-right-close {
+	transform: rotateY(0deg);
+	animation: right-close 1s linear;
+}
+
+.poster .background-door .background-door__invite {
+	position: absolute;
+	top: 12%;
+	left: 20%;
+	width: 60%;
+	opacity: 0;
+}
+
+.poster .background-door .background-door__invite .border_corner {
+	position: absolute;
+	width: 32rpx;
+	height: 32rpx;
+	border: 4rpx solid #e5bb8f;
+}
+
+.poster .background-door .background-door__invite .border_corner_left_top{
+	top: -28rpx;
+	left: -24rpx;
+	border-right: none;
+	border-bottom: none;
+	border-top-left-radius: 12rpx;
+}
+
+.poster .background-door .background-door__invite .border_corner_right_top{
+	top: -28rpx;
+	right: -24rpx;
+	border-left: none;
+	border-bottom: none;
+	border-top-right-radius: 12rpx;
+}
+
+.poster .background-door .background-door__invite .border_corner_left_bottom{
+	bottom: -2rpx;
+	left: -24rpx;
+	border-right: none;
+	border-top: none;
+	border-bottom-left-radius: 12rpx;
+}
+
+.poster .background-door .background-door__invite .border_corner_right_bottom{
+	bottom: -2rpx;
+	right: -24rpx;
+	border-left: none;
+	border-top: none;
+	border-bottom-right-radius: 12rpx;
+}
+
+.poster .background-door .background-door__invite.door-invite-show {
+	opacity: 1;
+	animation: show 1s linear;
+}
+
+.poster .background-door .background-door__invite.door-invite-hide {
+	opacity: 0;
+	animation: hide 1s linear;
+}
+
+.poster .background-door .background-door__invite	.content {
+	margin-bottom: 30rpx;
+	line-height: 58rpx;
+	color: #e5bb8f;
+	text-indent: 2em;
+}
+
+.poster .background-door .background-door__invite	.content .keynote {
+  color: #fff;
+}
+
+.poster .background-door .background-door__invite	.content .agreement {
+  color: #1989FA;
+}
+
+.poster .background-door .background-door__invite .btn-group {
+	display: flex;
+}
+
+.poster .background-door .background-door__invite .btn-group .btn {
+	width: 50%;
+}
+
+.poster .background-door .background-door__invite .btn-group .btn:first-child {
+	color: #969799;
+}

BIN
packagePosterImg/images/bg.png


BIN
packagePosterImg/images/door-left.png


BIN
packagePosterImg/images/door-right.png


+ 12 - 0
packagePosterImg/index.js

@@ -0,0 +1,12 @@
+Page({
+	data: {},
+
+	onShareAppMessage() {
+		return promise = new Promise(resolve => {
+			resolve({
+				title: '八马茶业开业邀请',
+				path: "/packagePoster/index"
+			})
+		})
+	}
+})

+ 4 - 0
packagePosterImg/index.json

@@ -0,0 +1,4 @@
+{
+  "navigationStyle": "custom",
+  "usingComponents": {}
+}

+ 12 - 0
packagePosterImg/index.wxml

@@ -0,0 +1,12 @@
+<view class='poster'>
+	<image class="backgroundImg" src="./images/bg.png" />
+
+	<view class="background-door">
+		<view class="background-door__left">
+			<image mode="heightFix" src="./images/door-left.png" />
+		</view>
+		<view class="background-door__right">
+			<image mode="heightFix" src="./images/door-right.png" />
+		</view>
+	</view>
+</view>

+ 48 - 0
packagePosterImg/index.wxss

@@ -0,0 +1,48 @@
+.poster {
+	position: relative;
+	width: 100%;
+	height: 100vh;
+	background: #c11f1b;
+}
+
+.poster .backgroundImg {
+	position: absolute;
+	top: calc(constant(safe-area-inset-bottom) / 2);
+	top: calc(env(safe-area-inset-bottom) / 2);
+	width: 100%;
+	height: calc(100% - constant(safe-area-inset-bottom));
+	height: calc(100% - env(safe-area-inset-bottom));
+}
+
+.poster .background-door {
+	position: absolute;
+	bottom: calc(constant(safe-area-inset-bottom) / 2);
+	bottom: calc(env(safe-area-inset-bottom) / 2);
+	width: 100%;
+	height: calc(55% - constant(safe-area-inset-bottom));
+	height: calc(55% - env(safe-area-inset-bottom));
+	perspective: 500px;
+}
+
+.poster .background-door .background-door__left,
+.poster .background-door .background-door__right {
+	position: absolute;
+	width: 50%;
+	height: 100%;
+	perspective: 500px;
+}
+
+.poster .background-door .background-door__right {
+	right: 0;
+}
+
+.poster .background-door image {
+	position: absolute;
+	height: 100%;
+	transform-origin: right center;
+}
+
+.poster .background-door .background-door__left image {
+	right: 0;
+	transform-origin: left center;
+}

+ 84 - 0
packageUser/collect/collect.js

@@ -0,0 +1,84 @@
+const util = require('../../utils/util')
+const api = require('../../config/api')
+
+Page({
+  data: {
+		loading: false,
+		isEdit: false, // 是否显示选择按钮
+		selectList: [], // 已选中收藏id
+
+    collectList: [],
+    page: 1,
+    totalPages: 1
+  },
+
+  onShow: function() {
+    this.getCollectList()
+	},
+	
+	pullDownRefresh() {
+    this.setData({ page: 1, loading: true })
+    this.getCollectList()
+    this.setData({ loading: false })
+	},
+
+	// 加载更多
+	scrolltolower() {
+		if (this.data.totalPages > this.data.page) {
+			this.setData({ page: this.data.page + 1 })
+			this.getCollectList()
+		} else util.showToast('已经到底了')
+	},
+
+	getCollectList() {
+		util.showLoad('加载中')
+		util.request(api.CollectList, { page: this.data.page, type: 0 }).then(res => {
+			util.hideLoad()
+			if (res.errno === 0) {
+				const list = res.data.collectList.map(item => {
+					item.picUrl = item.picUrl.split(',')
+					return item
+				})
+
+				const collectList = this.data.page == 1 ? list : this.data.collectList.concat(list)
+				this.setData({ collectList, totalPages: res.data.totalPages })
+			} else util.showErrorToast(res.errmsg)
+		}).catch(() => {
+			util.hideLoad()
+			util.showErrorToast('网络连接失败')
+		})
+	},
+
+	// 编辑
+	toggleEdit() {
+		this.setData({ isEdit: !this.data.isEdit, selectList: [] })
+	},
+
+	selectCollect({ detail }) {
+		this.setData({ selectList: detail })
+	},
+
+	deleteCollect() {
+		const { selectList } = this.data
+		if (!selectList.length) return
+		util.showLoad('加载中')
+		util.request(api.CollectDelete, selectList, 'POST').then(res => {
+			util.hideLoad()
+			if (res.errno === 0) {
+				this.setData({ isEdit: false })
+				this.getCollectList()
+			} else util.showErrorToast(res.errmsg)
+		}).catch(() => {
+			util.hideLoad()
+			util.showErrorToast('网络连接失败')
+		})
+	},
+
+	// 商品详情
+  toDetail({ currentTarget }) {
+		if (!this.data.isEdit) {
+			const { id } = currentTarget.dataset
+			wx.navigateTo({ url: `/packageGoods/detail/detail?obj=${JSON.stringify({ id })}` })
+		}
+	}
+})

+ 7 - 0
packageUser/collect/collect.json

@@ -0,0 +1,7 @@
+{
+  "navigationBarTitleText": "我的收藏",
+  "usingComponents": {
+  	"van-checkbox-group": "@vant/weapp/checkbox-group/index",
+    "van-checkbox": "@vant/weapp/checkbox/index"
+  }
+}

+ 30 - 0
packageUser/collect/collect.wxml

@@ -0,0 +1,30 @@
+<view class="collect-container">
+	<van-empty wx:if="{{ !collectList.length }}" image="/packageUser/collect/empty_collect.png" description="您还没有收藏" />
+
+  <view wx:else class="content">
+    <view class="title jhx_bg0 acea-row row-between-wrapper">
+      <view>收藏 ( {{ collectList.length }} )</view>
+      <view wx:if="{{ !isEdit }}" bindtap="toggleEdit">编辑</view>
+			<block wx:else>
+				<view class="acea-row row-middle">
+					<view class="del-btn" bindtap="deleteCollect">删除</view>
+					<view bindtap="toggleEdit">取消</view>
+				</view>
+			</block>
+    </view>
+
+		<scroll-view class="collect-scroll" scroll-y refresher-enabled refresher-triggered="{{ loading }}" bindrefresherrefresh="pullDownRefresh" bindscrolltolower="scrolltolower">
+			<van-checkbox-group value="{{ selectList }}" bind:change="selectCollect">
+				<van-checkbox custom-class="item jhx_bg0 {{ !isEdit ? 'no-radio' : '' }} {{ index != collectList.length - 1 ? 'border' : '' }}" wx:for="{{ collectList }}" wx:key="{{ item.collectId }}" name="{{ item.collectId }}" icon-size="16" checked-color="#D32D2F">
+					<view class="acea-row row-between-wrapper" data-id="{{ item.id }}" bindtap="toDetail">
+						<image src="{{ item.picUrl[0] }}" />
+						<view class="right acea-row row-column row-between">
+							<view class="name line1 line2">{{ item.name }}</view>
+							<view class="price"><text>¥</text>{{ item.retailPrice }}</view>
+						</view>
+					</view>
+				</van-checkbox>
+			</van-checkbox-group>
+		</scroll-view>
+  </view>
+</view>

+ 94 - 0
packageUser/collect/collect.wxss

@@ -0,0 +1,94 @@
+page {
+	padding-bottom: 32rpx;
+}
+
+.collect-container .van-empty {
+	height: 100vh;
+	background: #fff;
+}
+
+.collect-container .content .title {
+  padding: 0 36rpx 0 24rpx;
+  line-height: 80rpx;
+  color: #50555F;
+}
+
+.collect-container .content .title .del-btn {
+	margin-right: 24rpx;
+	color: #D32D2F;
+}
+
+.collect-container .content .collect-scroll {
+	height: calc(100vh - 112rpx);
+}
+
+.collect-container .content .collect-scroll .item {
+	position: relative;
+  padding: 40rpx 24rpx;
+}
+
+.collect-container .content .collect-scroll .item .van-checkbox__icon-wrap {
+	margin-right: 24rpx;
+}
+
+.collect-container .content .collect-scroll .border::after {
+  position: absolute;
+  bottom: 0;
+  left: 24rpx;
+  content: '';
+  width: calc(100% - 24rpx);
+  height: 2rpx;
+  background: rgba(110, 123, 143, 0.16);
+}
+
+.collect-container .content .collect-scroll .no-radio .van-checkbox__icon-wrap {
+	display: none;
+}
+
+.collect-container .content .collect-scroll .item .van-checkbox__label {
+	flex: 1;
+	padding-left: 0;
+}
+
+.collect-container .content .collect-scroll .item image {
+  width: 176rpx;
+  height: 176rpx;
+  border-radius: 8rpx;
+}
+
+.collect-container .content .collect-scroll .item .right {
+  flex: 1;
+  height: 176rpx;
+  margin-left: 24rpx;
+  line-height: 28rpx;
+  font-size: 24rpx;
+  color: #060606;
+}
+
+.collect-container .content .collect-scroll .item .right .name {
+  line-height: 32rpx;
+  font-size: 26rpx;
+  color: #060606;
+}
+
+.collect-container .content .collect-scroll .item .right .price {
+  line-height: 42rpx;
+  font-size: 36rpx;
+  font-family: DIN Alternate-Bold, DIN Alternate;
+  font-weight: bold;
+}
+
+.collect-container .content .collect-scroll .item .right .price text {
+	padding-right: 4rpx;
+	line-height: 28rpx;
+	font-size: 24rpx;
+}
+
+.collect-container .content .collect-scroll .item .right .btn {
+  width: 160rpx;
+  background: #D32D2F;
+  border-radius: 60rpx;
+  text-align: center;
+  line-height: 48rpx;
+  color: #fff;
+}

BIN
packageUser/collect/empty_collect.png


+ 85 - 0
packageUser/footprint/footprint.js

@@ -0,0 +1,85 @@
+const util = require('../../utils/util')
+const api = require('../../config/api')
+
+Page({
+  data: {
+		loading: false,
+		isEdit: false, // 是否显示选择按钮
+		selectList: [], // 已选中足迹id
+
+    footprintList: []
+  },
+
+  onShow: function() {
+    this.getFootprintList()
+	},
+	
+	pullDownRefresh() {
+    this.setData({ loading: true })
+    this.getFootprintList()
+    this.setData({ loading: false })
+	},
+
+	formatDate(date) {
+		const month = new Date(date).getMonth() + 1
+		const day = new Date(date).getDate()
+		return month + '月' + day + '日'
+	},
+
+	getFootprintList() {
+		util.showLoad('加载中')
+		util.request(api.FootprintList).then(res => {
+			util.hideLoad()
+			if (res.errno === 0) {
+				let footprintList = []
+				for (const k in res.data) {
+					if (Object.hasOwnProperty.call(res.data, k)) {
+						const date = this.formatDate(k)
+						const list = res.data[k].map(item => {
+							item.picUrl = item.picUrl.split(',')
+							return item
+						})
+						footprintList.push({ date, list })
+					}
+				}
+				this.setData({ footprintList })
+			} else util.showErrorToast(res.errmsg)
+		}).catch(() => {
+			util.hideLoad()
+			util.showErrorToast('网络连接失败')
+		})
+	},
+
+	// 编辑
+	toggleEdit() {
+		this.setData({ isEdit: !this.data.isEdit, selectList: [] })
+	},
+
+	selectFootprint({ detail }) {
+		this.setData({ selectList: detail })
+	},
+
+	deleteFootprint() {
+		const { selectList } = this.data
+		if (!selectList.length) return
+		util.showLoad('加载中')
+		util.request(api.FootprintDelete, selectList, 'POST').then(res => {
+			util.hideLoad()
+			if (res.errno === 0) {
+				this.setData({ isEdit: false })
+				this.getFootprintList()
+			} else util.showErrorToast(res.errmsg)
+		}).catch(() => {
+			util.hideLoad()
+			util.showErrorToast('网络连接失败')
+		})
+	},
+
+	// 商品详情
+  toDetail({ currentTarget }) {
+		if (!this.data.isEdit) {
+			const { id } = currentTarget.dataset
+			wx.navigateTo({ url: `/packageGoods/detail/detail?obj=${JSON.stringify({ id })}` })
+		}
+	}
+})

+ 7 - 0
packageUser/footprint/footprint.json

@@ -0,0 +1,7 @@
+{
+  "navigationBarTitleText": "浏览足迹",
+  "usingComponents": {
+  	"van-checkbox-group": "@vant/weapp/checkbox-group/index",
+    "van-checkbox": "@vant/weapp/checkbox/index"
+  }
+}

+ 33 - 0
packageUser/footprint/footprint.wxml

@@ -0,0 +1,33 @@
+<view class="footprint-container">
+	<van-empty wx:if="{{ !footprintList.length }}" image="/static/images/empty_goods.png" description="您最近还没有足迹哦" />
+
+  <view wx:else class="content">
+    <view class="title jhx_bg0 acea-row row-middle row-right">
+      <view wx:if="{{ !isEdit }}" bindtap="toggleEdit">编辑</view>
+			<block wx:else>
+				<view class="del-btn" bindtap="deleteFootprint">删除</view>
+				<view bindtap="toggleEdit">取消</view>
+			</block>
+    </view>
+
+		<scroll-view class="footprint-scroll" scroll-y refresher-enabled refresher-triggered="{{ loading }}" bindrefresherrefresh="pullDownRefresh">
+			<van-checkbox-group wx:for="{{ footprintList }}" wx:for-item="footprint" wx:key="index" value="{{ selectList }}" bind:change="selectFootprint">
+				<view class="date">{{ footprint.date }}</view>
+				<van-checkbox custom-class="item jhx_bg0 {{ !isEdit ? 'no-radio' : '' }}" wx:for="{{ footprint.list }}" wx:key="{{ item.footPrintId }}" name="{{ item.footPrintId }}" icon-size="16" checked-color="#D32D2F" data-id="{{ item.id }}" bindtap="toDetail">
+					<view class="acea-row row-between-wrapper">
+						<image class="pic" src="{{ item.picUrl[0] }}" />
+						<view class="right acea-row row-column row-between">
+							<view class="name line1 line2">{{ item.name }}</view>
+							<view class="acea-row row-between row-bottom">
+								<view class="price"><text>¥</text>{{ item.retailPrice }}</view>
+								<van-icon name="./meizhuang.png" size="24" />
+							</view>
+						</view>
+					</view>
+				</van-checkbox>
+			</van-checkbox-group>
+
+			<view class="no-more">- 到底啦,仅显示近7天的记录哦 —</view>
+		</scroll-view>
+  </view>
+</view>

+ 95 - 0
packageUser/footprint/footprint.wxss

@@ -0,0 +1,95 @@
+page {
+	padding-bottom: 32rpx;
+}
+
+.footprint-container .van-empty {
+	height: 100vh;
+	background: #fff;
+}
+
+.footprint-container .content .title {
+  padding: 0 36rpx 0 24rpx;
+  line-height: 80rpx;
+  color: #50555F;
+}
+
+.footprint-container .content .title .del-btn {
+	margin-right: 24rpx;
+	color: #D32D2F;
+}
+
+.footprint-container .content .footprint-scroll {
+	height: calc(100vh - 112rpx);
+}
+
+.footprint-container .content .footprint-scroll .date {
+	padding: 20rpx 24rpx 4rpx;
+	line-height: 40rpx;
+	font-size: 28rpx;
+	font-family: HarmonyOS Sans SC-Medium, HarmonyOS Sans SC;
+	font-weight: 500;
+	color: #060606;
+}
+
+.footprint-container .content .footprint-scroll .item {
+	position: relative;
+	left: 24rpx;
+	width: calc(100% - 48rpx);
+	margin-top: 16rpx;
+	padding: 40rpx 24rpx;
+  border-radius: 16rpx;
+}
+
+.footprint-container .content .footprint-scroll .item .van-checkbox__icon-wrap {
+	margin-right: 24rpx;
+}
+
+.footprint-container .content .footprint-scroll .no-radio .van-checkbox__icon-wrap {
+	display: none;
+}
+
+.footprint-container .content .footprint-scroll .item .van-checkbox__label {
+	flex: 1;
+	padding-left: 0;
+}
+
+.footprint-container .content .footprint-scroll .item .pic {
+  width: 176rpx;
+  height: 176rpx;
+  border-radius: 8rpx;
+}
+
+.footprint-container .content .footprint-scroll .item .right {
+  flex: 1;
+  height: 176rpx;
+  margin-left: 24rpx;
+  line-height: 28rpx;
+  font-size: 24rpx;
+  color: #060606;
+}
+
+.footprint-container .content .footprint-scroll .item .right .name {
+  line-height: 32rpx;
+  font-size: 26rpx;
+  color: #060606;
+}
+
+.footprint-container .content .footprint-scroll .item .right .price {
+  line-height: 42rpx;
+  font-size: 36rpx;
+  font-family: DIN Alternate-Bold, DIN Alternate;
+  font-weight: bold;
+}
+
+.footprint-container .content .footprint-scroll .item .right .price text {
+	padding-right: 4rpx;
+	line-height: 28rpx;
+	font-size: 24rpx;
+}
+
+.footprint-container .content .footprint-scroll .no-more {
+  margin-top: 32rpx;
+  text-align: center;
+  font-size: 24rpx;
+  color: #767E8B;
+}

BIN
packageUser/footprint/meizhuang.png


+ 79 - 0
packageUser/information/information.js

@@ -0,0 +1,79 @@
+const api = require('../../config/api')
+const util = require('../../utils/util')
+const upload = require('../../utils/upload')
+
+Page({
+  data: {
+		userInfo: {}
+  },
+
+	onShow() {
+		this.getUserInfo()
+	},
+
+	getUserInfo() {
+		util.showLoad('加载中')
+    util.request(api.UserInfo).then(res => {
+      util.hideLoad()
+      if (res.errno === 0) {
+				wx.setStorageSync('userInfo', res.data)
+				this.setData({ userInfo: res.data })
+      } else util.showToast(res.errmsg)
+    }).catch(() => {
+      util.hideLoad()
+      util.showErrorToast('网络连接失败')
+    })	
+	},
+
+	// 更新头像
+	updateUser(avatar) {
+		util.request(api.UserUpdate, { id: this.data.userInfo.id, avatar }, 'POST').then(res => {
+			util.hideLoad()
+			if (res.errno === 0) this.getUserInfo()
+			else util.showErrorToast(res.errmsg)
+		}).catch(() => {
+			util.hideLoad()
+			util.showErrorToast('网络连接失败')
+		})
+	},
+
+	// 更换头像
+	chooseMedia() {
+		const that = this
+		wx.chooseMedia({
+			count: 1,
+			mediaType: ['image'],
+			success: async suc => {
+				try {
+					util.showLoad('上传中')
+					const filePath = suc.tempFiles[0].tempFilePath
+					const url = await upload.uploadImage(filePath)
+					that.updateUser(url)
+				} catch (error) {
+					util.hideLoad()
+					util.showErrorToast(error)
+				}
+			},
+			fail: () => {
+				util.hideLoad()
+				util.showToast('已取消')
+			}
+		})
+	},
+	
+  // 退出登录
+  logout() {
+    wx.showModal({
+      confirmColor: '#D32D2F',
+      content: '确定退出登录吗?',
+      success: res => {
+        if (res.confirm) {
+          util.request(api.Logout, {}, 'POST')
+          wx.removeStorageSync('token')
+          wx.removeStorageSync('userInfo')
+          wx.reLaunch({ url: '/pages/index/index' })
+        }
+      }
+    })
+  }
+})

+ 4 - 0
packageUser/information/information.json

@@ -0,0 +1,4 @@
+{
+  "navigationBarTitleText": "个人信息",
+  "usingComponents": {}
+}

+ 25 - 0
packageUser/information/information.wxml

@@ -0,0 +1,25 @@
+<wxs src="../../utils/filter.wxs" module="filter" />
+
+<view class="setting-container">
+	<view class="avatar-cell jhx_bg0" bindtap="chooseMedia">
+		<image class="avatar" src="{{ userInfo.avatar }}" />
+		<view class="label">更换头像</view>
+	</view>
+  <navigator hover-class="none" class="cell border jhx_bg0 acea-row row-between-wrapper" url="/packageUser/nickNameModify/nickNameModify">
+    <view class="label">姓名</view>
+    <view>{{ userInfo.nickname }}<van-icon name="arrow" /></view>
+	</navigator>
+	<navigator hover-class="none" class="cell border jhx_bg0 acea-row row-between-wrapper" url="/packageUser/mobileModify/mobileModify">
+    <view class="label">手机号码</view>
+		<view>
+			<block wx:if="{{ userInfo.mobile && userInfo.mobile.length == 11 }}">{{ userInfo.mobile }}</block>
+			<van-icon name="arrow" />
+		</view>
+	</navigator>
+  <view class="cell border jhx_bg0 acea-row row-between-wrapper">
+    <view class="label">OPENID</view>
+    <view>{{ userInfo.weixinOpenid }}</view>
+  </view>
+
+  <view class="btn" bindtap="logout">退出登录</view>
+</view>

+ 101 - 0
packageUser/information/information.wxss

@@ -0,0 +1,101 @@
+.setting-container {
+	padding-bottom: 32rpx;
+}
+
+.setting-container .avatar-cell {
+	position: relative;
+	padding: 32rpx 0;
+	text-align: center;
+}
+
+.setting-container .avatar-cell::after {
+	position: absolute;
+	bottom: 0;
+	left: 24rpx;
+	content: '';
+	width: calc(100% - 48rpx);
+	height: 2rpx;
+	background: rgba(110, 123, 143, 0.16);
+}
+
+.setting-container .avatar-cell .avatar {
+	display: block;
+	width: 160rpx;
+	height: 160rpx;
+	margin: auto;
+	border-radius: 50%;
+}
+
+.setting-container .avatar-cell .label {
+	margin-top: 24rpx;
+	color: #D32D2F;
+}
+
+.setting-container .cell {
+	position: relative;
+	padding: 24rpx;
+	line-height: 80rpx;
+	color: rgba(118, 126, 139, 0.57);
+}
+
+.setting-container .border::after {
+	position: absolute;
+	bottom: 0;
+	left: 24rpx;
+	content: '';
+	width: calc(100% - 48rpx);
+	height: 2rpx;
+	background: rgba(110, 123, 143, 0.16);
+}
+
+.setting-container .cell .label {
+	color: #50555F;
+}
+
+.setting-container .cell .error {
+	color: #D32D2F;
+}
+
+.setting-container .cell .suc {
+	color: #0FC917;
+}
+
+.setting-container .btn {
+	width: calc(100% - 48rpx);
+	margin: 48rpx auto 0;
+	background: #D32D2F;
+	border-radius: 90rpx;
+	text-align: center;
+	line-height: 80rpx;
+	font-size: 28rpx;
+	color: #fff;
+}
+
+.auth-popup .van-cell {
+	margin-bottom: 24rpx;
+	padding: 16rpx 20rpx;
+	background: #f5f5f5;
+	border-radius: 8rpx;
+}
+
+.auth-popup .van-cell .van-cell__title {
+	max-width: 3.6em !important;
+	min-width: 3.6em !important;
+	margin-right: 24rpx;
+	font-size: 26rpx;
+	color: #060606;
+}
+
+.auth-popup .van-cell .van-cell__value {
+	text-align: left;
+	color: #060606;
+}
+
+.auth-popup .van-cell .van-field__label {
+	color: #060606;
+}
+
+.auth-popup .van-cell .van-field__placeholder {
+	font-size: 26rpx;
+	color: #999;
+}

+ 34 - 0
packageUser/mobileModify/mobileModify.js

@@ -0,0 +1,34 @@
+const api = require('../../config/api')
+const util = require('../../utils/util')
+const check = require('../../utils/check')
+
+Page({
+	data: {
+		id: 0,
+		mobile: ''
+	},
+
+	onLoad() {
+		const { id, mobile } = wx.getStorageSync('userInfo')
+		this.setData({ id, mobile: mobile && mobile.length == 11 ? mobile : '' })
+	},
+
+	nameInput({ detail }) {
+    this.setData({ mobile: detail })
+	},
+
+	submit() {
+		const { id, mobile } = this.data
+		if (!check.validPhone(mobile)) return util.showToast('请输入正确手机号')
+
+		util.showLoad('加载中')
+		util.request(api.UserUpdate, { id, mobile }, 'POST').then(res => {
+			util.hideLoad()
+			if (res.errno === 0) wx.navigateBack()
+			else util.showErrorToast(res.errmsg)
+		}).catch(() => {
+			util.hideLoad()
+			util.showErrorToast('网络连接失败')
+		})
+	}
+})

+ 6 - 0
packageUser/mobileModify/mobileModify.json

@@ -0,0 +1,6 @@
+{
+	"navigationBarTitleText": "修改手机号",
+	"usingComponents": {
+    "van-field": "@vant/weapp/field/index"
+	}
+}

+ 4 - 0
packageUser/mobileModify/mobileModify.wxml

@@ -0,0 +1,4 @@
+<view class="modify-nickname">
+	<van-field value="{{ mobile }}" focus border="{{ false }}" clearable placeholder="请输入手机号" bind:change="nameInput" />
+	<view class="btn" bindtap="submit">保存</view>
+</view>

+ 24 - 0
packageUser/mobileModify/mobileModify.wxss

@@ -0,0 +1,24 @@
+.modify-nickname .van-field__placeholder {
+	color: #999;
+}
+
+.modify-nickname .desc {
+	padding: 24rpx;
+	line-height: 36rpx;
+	font-size: 24rpx;
+	color: #50555F;
+}
+
+.modify-nickname .btn {
+	position: fixed;
+	left: 24rpx;
+	bottom: 120rpx;
+	width: calc(100% - 48rpx);
+	background: #D32D2F;
+	border-radius: 90rpx;
+	text-align: center;
+	line-height: 40px;
+	font-family: HarmonyOS Sans SC-Regular, HarmonyOS Sans SC;
+	font-weight: 400;
+	color: #fff;
+}

+ 35 - 0
packageUser/nickNameModify/nickNameModify.js

@@ -0,0 +1,35 @@
+const api = require('../../config/api')
+const util = require('../../utils/util')
+const check = require('../../utils/check')
+
+Page({
+	data: {
+		id: 0,
+		nickname: ''
+	},
+
+	onLoad() {
+		const { id, nickname } = wx.getStorageSync('userInfo')
+		this.setData({ id, nickname: nickname ? nickname : '' })
+	},
+
+	nameInput({ detail }) {
+    this.setData({ nickname: detail })
+	},
+
+	// 修改昵称
+	submit() {
+		const { id, nickname } = this.data
+		if (!check.validNickName(nickname)) return util.showToast('请输入4-20个字符')
+
+		util.showLoad('加载中')
+		util.request(api.UserUpdate, { id, nickname }, 'POST').then(res => {
+			util.hideLoad()
+			if (res.errno === 0) wx.navigateBack()
+			else util.showErrorToast(res.errmsg)
+		}).catch(() => {
+			util.hideLoad()
+			util.showErrorToast('网络连接失败')
+		})
+	}
+})

+ 6 - 0
packageUser/nickNameModify/nickNameModify.json

@@ -0,0 +1,6 @@
+{
+	"navigationBarTitleText": "修改姓名",
+	"usingComponents": {
+    "van-field": "@vant/weapp/field/index"
+	}
+}

+ 5 - 0
packageUser/nickNameModify/nickNameModify.wxml

@@ -0,0 +1,5 @@
+<view class="modify-nickname">
+	<van-field value="{{ nickname }}" focus border="{{ false }}" clearable placeholder="请输入姓名" bind:change="nameInput" />
+	<view class="desc">2-10个字符组成</view>
+	<view class="btn" bindtap="submit">保存</view>
+</view>

+ 24 - 0
packageUser/nickNameModify/nickNameModify.wxss

@@ -0,0 +1,24 @@
+.modify-nickname .van-field__placeholder {
+	color: #999;
+}
+
+.modify-nickname .desc {
+	padding: 24rpx;
+	line-height: 36rpx;
+	font-size: 24rpx;
+	color: #50555F;
+}
+
+.modify-nickname .btn {
+	position: fixed;
+	left: 24rpx;
+	bottom: 120rpx;
+	width: calc(100% - 48rpx);
+	background: #D32D2F;
+	border-radius: 90rpx;
+	text-align: center;
+	line-height: 40px;
+	font-family: HarmonyOS Sans SC-Regular, HarmonyOS Sans SC;
+	font-weight: 400;
+	color: #fff;
+}

+ 94 - 0
pages/catalog/catalog.js

@@ -0,0 +1,94 @@
+let util = require('../../utils/util')
+let api = require('../../config/api')
+let app = getApp()
+
+Page({
+  data: {
+    leftMenu: [],
+		menuId: 0, // 左侧目录当前选中
+		toView: 'menu0', // 滚动到的目录
+
+		loading: false,
+    goodsList: [], // 当前分类列表
+		name: '',
+		page: 1,
+    totalPages: 1
+  },
+
+  onShow() {
+    if (!this.data.leftMenu.length) this.getLeftMenu()
+		else {
+			if (app.globalData.menuId) this.setData({ menuId: app.globalData.menuId, toView: `menu${app.globalData.menuId}` })
+			this.getCategoryGoods()
+		} 
+  },
+
+  // 获取左侧目录
+  getLeftMenu() {
+    util.showLoad('加载中...')
+    util.request(api.CatalogList).then(res => {
+      util.hideLoad()
+      if (res.errno === 0) {
+				let menuId = res.data.categoryList.length && res.data.categoryList[0].id || 0
+				if (app.globalData.menuId) menuId = app.globalData.menuId
+				this.setData({ leftMenu: res.data.categoryList, menuId, toView: menuId && `menu${menuId}` || "menu0" })
+				this.getCategoryGoods()
+			} else util.showErrorToast(res.errmsg)
+    }).catch(() => {
+      util.hideLoad()
+      util.showErrorToast('网络连接失败')
+    })
+  },
+
+  // 获取分类商品
+  getCategoryGoods() {
+		const filter = { page: this.data.page, categoryId: this.data.menuId, name: this.data.name }
+		util.showLoad('加载中...')
+    util.request(api.CatalogGoodsList, filter).then(res => {
+      util.hideLoad()
+      if (res.errno === 0) {
+				const list = res.data.goodsList.map(item => {
+					item.picUrl = item.picUrl.split(',')
+					return item
+				})
+				const goodsList = this.data.page == 1 ? list : this.data.goodsList.concat(list)
+				this.setData({ totalPages: res.data.totalPages, goodsList })
+			} else util.showErrorToast(res.errmsg)
+    }).catch(() => {
+      util.hideLoad()
+			util.showErrorToast('网络连接失败')
+    })
+  },
+
+  // 左侧切换分类
+  changeCategory({ currentTarget }) {
+    const { id } = currentTarget.dataset
+    this.setData({ menuId: id })
+		app.globalData.menuId = id
+		this.getCategoryGoods()
+	},
+	
+	nameInput({ detail }) {
+    this.setData({ page: 1, name: detail })
+    this.getCategoryGoods()
+	},
+
+	pullDownRefresh() {
+    this.setData({ page: 1, name: '', loading: true })
+    this.getCategoryGoods()
+    this.setData({ loading: false })
+	},
+
+	// 加载更多
+	scrolltolower() {
+		if (this.data.totalPages > this.data.page) {
+      this.setData({ page: this.data.page + 1 })
+      this.getCategoryGoods()
+    } else util.showToast('已经到底了')
+	},
+
+  toDetail({ currentTarget }) {
+		const { id } = currentTarget.dataset
+    wx.navigateTo({ url: `/packageGoods/detail/detail?obj=${JSON.stringify({ id })}` })
+	}
+})

+ 6 - 0
pages/catalog/catalog.json

@@ -0,0 +1,6 @@
+{
+	"navigationBarTitleText": "分类",
+	"usingComponents": {
+    "van-field": "@vant/weapp/field/index"
+  }
+}

+ 24 - 0
pages/catalog/catalog.wxml

@@ -0,0 +1,24 @@
+<view class="catalog-container acea-row">
+  <scroll-view class="scroll" scroll-y scroll-with-animation enable-passive scroll-into-view="{{ toView }}">
+    <view id="menu{{ item.id }}" class="item {{ item.id == menuId ? 'active' : '' }}" wx:for="{{ leftMenu }}" wx:key="index" data-id="{{ item.id }}" bindtap="changeCategory">{{ item.name }}</view>
+  </scroll-view>
+
+	<view class="content">
+		<view class="top jhx_bg0">
+			<van-field value="{{ name }}" left-icon='/static/images/icon_search_black.png' placeholder="搜索商品" border="{{ false }}" bind:change="nameInput" />
+		</view>
+
+		<scroll-view class="list" scroll-y refresher-enabled refresher-triggered="{{ loading }}" bindrefresherrefresh="pullDownRefresh" bindscrolltolower="scrolltolower">
+			<van-empty wx:if="{{ !goodsList.length }}" image="/static/images/empty_goods.png" description="没有相关商品" />
+			<view class="item jhx_bg0" wx:for="{{ goodsList }}" wx:key="id" data-id="{{ item.id }}" bindtap="toDetail">
+				<view class="left-image"><image src="{{ item.picUrl[0] }}" /></view>
+				<view style="flex: 1;">
+					<view class="title line1 line2">{{ item.name }}</view>
+					<view class="label {{ item.labelName ? '' : 'block' }}">{{ item.labelName }}</view>
+					<view class="price"><text>¥</text>{{ item.retailPrice }}</view>
+				</view>
+			</view>
+		</scroll-view>
+	</view>
+
+</view>

+ 145 - 0
pages/catalog/catalog.wxss

@@ -0,0 +1,145 @@
+page {
+  background: #fff;
+}
+
+.catalog-container {
+  font-size: 28rpx;
+  font-family: HarmonyOS Sans SC-Regular, HarmonyOS Sans SC;
+  font-weight: 400;
+}
+
+.catalog-container .scroll {
+  width: 200rpx;
+  height: calc(100vh);
+  background: #f5f5f5;
+}
+
+.catalog-container .scroll .item {
+  width: 100%;
+  text-align: center;
+  line-height: 144rpx;
+  color: #060606;
+}
+
+.catalog-container .scroll .active {
+  position: relative;
+  background: #fff;
+  color: #D32D2F;
+}
+
+.catalog-container .scroll .active::before {
+  position: absolute;
+  top: 52rpx;
+  left: 0;
+  content: '';
+  width: 6rpx;
+  height: 38rpx;
+  background: #D32D2F;
+}
+
+.catalog-container .content {
+  height: calc(100vh);
+  flex: 1;
+  padding: 0 20rpx;
+}
+
+.catalog-container .content .top {
+	width: 100%;
+	margin-bottom: 24rpx;
+	padding-top: 12rpx;
+}
+
+.catalog-container .content .top .van-cell {
+	width: calc(100% - 48rpx);
+	margin: 0 auto 12rpx;
+	padding: 6rpx 24rpx;
+	background: rgba(118, 126, 139, 0.1);
+	border-radius: 8rpx;
+	font-size: 24rpx;
+}
+
+.catalog-container .content .top .van-cell .van-cell__left-icon-wrap {
+	margin-right: 16rpx;
+}
+
+.catalog-container .content .top .van-cell .van-icon {
+	top: -4rpx;
+}
+
+.catalog-container .content .top .van-cell .van-field__placeholder {
+	line-height: 28rpx;
+	font-size: 28rpx;
+	color: #767E8B;
+}
+
+.catalog-container .content .list {
+	height: calc(100vh - 96rpx);
+}
+
+.catalog-container .content .list .van-empty {
+	width: calc(100% - 48rpx);
+	height: 100%;
+	margin: 0 auto;
+	min-height: auto;
+	background: #fff;
+	border-radius: 8rpx;
+}
+
+.catalog-container .content .list .item {
+	width: 100%;
+	margin-bottom: 14rpx;
+	display: flex;
+}
+
+.catalog-container .content .list .item .left-image {
+	width: 200rpx;
+	height: 200rpx;
+}
+
+.catalog-container .content .list .item .left-image image {
+	display: block;
+	width: 90%;
+	height: 90%;
+	margin: 5% auto;
+	border: 1px solid #dde2e8;
+	border-radius: 8rpx;
+}
+
+.catalog-container .content .list .item .title {
+	height: 56rpx;
+	margin: 16rpx;
+	line-height: 28rpx;
+	font-size: 24rpx;
+	color: #000;
+}
+
+.catalog-container .content .list .item .label {
+	display: inline-block;
+	margin-left: 16rpx;
+	padding: 0 8rpx;
+	border: 2rpx solid rgba(255, 2, 0, 0.2);
+	border-radius: 4rpx;
+	line-height: 32rpx;
+	font-size: 20rpx;
+	color: #D32D2F;
+}
+
+.catalog-container .content .list .item .block {
+	padding: 0;
+	border: 0;
+}
+
+.catalog-container .content .list .item .price {
+	padding: 16rpx;
+	line-height: 46rpx;
+	font-size: 40rpx;
+	font-family: DIN Alternate-Bold, DIN Alternate;
+	font-weight: bold;
+	color: #060606;
+}
+
+.catalog-container .content .list .item .price text {
+	padding-right: 4rpx;
+	line-height: 28rpx;
+	font-size: 24rpx;
+}

+ 131 - 0
pages/index/index.js

@@ -0,0 +1,131 @@
+const api = require('../../config/api')
+const util = require('../../utils/util')
+const check = require('../../utils/check')
+let app = getApp()
+
+Page({
+  data: {
+		show: false,
+		nickname: "",
+		mobile: "",
+
+		banner: [],
+    channel: [],
+    
+    categoryId: -2, // 底部商品分类id
+    category: [
+      { id: -2, name: '推荐' },
+      { id: -1, name: '新品' }
+    ],
+    floorGoods: [],
+    page: 1,
+    totalPages: 1
+	},
+	
+  onLoad() {
+		const token = wx.getStorageSync('token'), userInfo = wx.getStorageSync('userInfo')
+		if (token && userInfo && (!userInfo.mobile || userInfo.mobile.length != 11)) this.setData({ show: true })
+    this.getIndexData()
+  },
+
+  onPullDownRefresh() {
+    this.getIndexData()
+    wx.stopPullDownRefresh()
+  },
+
+  onReachBottom() {
+    if (this.data.totalPages > this.data.page) {
+			this.setData({ page: this.data.page + 1 })
+      this.getfloorGoods()
+    }
+  },
+
+  getIndexData() {
+    util.showLoad('加载中')
+    util.request(api.IndexUrl).then(res => {
+      util.hideLoad()
+      if (res.errno === 0) {
+				res.data.floorGoodsList.forEach(g => g.picUrl = g.picUrl.split(','))
+        this.setData({
+					banner: res.data.banner,
+          floorGoods: res.data.floorGoodsList,
+          totalPages: res.data.totalPages
+				})
+				if (res.data.channel && res.data.channel.length) this.setData({ channel: res.data.channel.splice(0, 8) })
+      } else util.showErrorToast(res.errmsg)
+    }).catch(() => {
+      util.hideLoad()
+      util.showErrorToast('网络连接失败')
+    })
+  },
+
+  // 获取底部 分类商品
+  getfloorGoods(e) {
+		const { page, categoryId } = this.data
+    util.showLoad('加载中')
+    util.request(api.GetfloorGoods, { page, categoryId }).then(res => {
+      util.hideLoad()
+      if (res.errno === 0) {
+				res.data.goodsList.forEach(g => g.picUrl = g.picUrl.split(','))
+				const floorGoods = e ? res.data.goodsList : this.data.floorGoods.concat(res.data.goodsList)
+        this.setData({ totalPages: res.data.totalPages, floorGoods })
+      } else util.showErrorToast(res.errmsg)
+    }).catch(() => {
+      util.hideLoad()
+			util.showErrorToast('网络连接失败')
+		})
+  },
+
+  // 切换底部分类
+  changeCategory({ currentTarget }) {
+		const { id } = currentTarget.dataset
+		this.setData({ categoryId: id, page: 1 })
+    this.getfloorGoods('reset')
+	},
+	
+  toCatelog({ currentTarget }) {
+    const { id } = currentTarget.dataset
+    app.globalData.menuId = id
+    wx.switchTab({ url: '/pages/catalog/catalog' })
+  },
+
+  // 商品详情
+  toDetail({ currentTarget }) {
+    const { item } = currentTarget.dataset
+    wx.navigateTo({ url: `/packageGoods/detail/detail?obj=${JSON.stringify({ id: item.id })}` })
+	},
+
+	hidePopup() {
+		this.setData({ show: false, nickname: "", mobile: "" })
+	},
+
+	nameInput({ detail }) {
+    this.setData({ nickname: detail })
+	},
+
+	mobileInput({ detail }) {
+    this.setData({ mobile: detail })
+	},
+
+	updateUser() {
+		const { nickname, mobile } = this.data
+		const { id } = wx.getStorageSync('userInfo')
+
+		if (!check.validNickName(nickname)) return util.showToast('请输入2-10个字符')
+		if (!check.validPhone(mobile)) return util.showToast('请输入正确手机号')
+		
+		util.showLoad('加载中')
+		util.request(api.UserUpdate, { id, nickname, mobile }, 'POST').then(res => {
+			util.hideLoad()
+			if (res.errno === 0) {
+				wx.setStorageSync('userInfo', { ...wx.getStorageSync('userInfo'), nickname, mobile })
+				this.hidePopup()
+			} else util.showErrorToast(res.errmsg)
+		}).catch(() => {
+			util.hideLoad()
+			util.showErrorToast('网络连接失败')
+		})
+	},
+	
+	onShareAppMessage() {}
+})

+ 8 - 0
pages/index/index.json

@@ -0,0 +1,8 @@
+{
+  "navigationBarTitleText": "富玖铭",
+  "enablePullDownRefresh": true,
+  "usingComponents": {
+		"popup": "@vant/weapp/popup/index",
+    "van-field": "@vant/weapp/field/index"
+	}
+}

+ 58 - 0
pages/index/index.wxml

@@ -0,0 +1,58 @@
+<view class="container">
+  <!-- 轮播图 -->
+  <swiper class="swiper" indicator-dots autoplay circular interval="3000" duration="1000">
+    <swiper-item wx:for="{{ banner }}" wx:key="id">
+      <navigator hover-class="none" url="{{ item.link }}">
+        <image src="{{ item.url }}" />
+      </navigator>
+    </swiper-item>
+  </swiper>
+  <!-- welfare -->
+  <view class="welfare acea-row row-evenly">
+    <view class="item acea-row row-middle">
+      <image src="/static/images/index_shangcheng.png" />
+      <text>官方商城</text>
+    </view>
+    <view class="item acea-row row-middle">
+      <image src="/static/images/index_zhengpin.png" />
+      <text>正品保证</text>
+    </view>
+  </view>
+  <!-- 商品类目 -->
+  <view class="category jhx_bg0 acea-row row-between">
+    <view class="item" wx:for="{{ channel }}" wx:key="id" data-id="{{ item.id }}" bindtap="toCatelog">
+      <image src="{{ item.iconUrl }}" />
+      <view>{{ item.name }}</view>
+    </view>
+  </view>
+
+  <!-- 商品 -->
+  <view class="goods">
+    <scroll-view class="scroll category-scroll" scroll-x>
+      <view class="item {{ categoryId == item.id ? 'active' : '' }}" wx:for="{{ category }}" wx:key="id" bindtap="changeCategory" data-id="{{ item.id }}">{{ item.name }}</view>
+    </scroll-view>
+
+    <view class="list acea-row row-between">
+      <view class="item jhx_bg0" wx:for="{{ floorGoods }}" wx:key="id" data-item="{{ item }}" bindtap="toDetail">
+        <image src="{{ item.picUrl[0] }}" />
+        <view class="title line1 line2">{{ item.name }}</view>
+        <view class="label {{ item.labelName ? '' : 'block' }}">{{ item.labelName }}</view>
+        <view class="price"><text>¥</text>{{ item.retailPrice }}</view>
+      </view>
+    </view>
+
+    <van-empty wx:if="{{ !floorGoods.length }}" image="/static/images/empty_goods.png" description="没有相关商品" />
+    <view wx:else hidden="{{ totalPages > page }}" class="no-more">— 没有更多了 —</view>
+	</view>
+	
+	<popup custom-class="user-popup" show="{{ show }}" closeable catchtouchmove="prevent" bind:close="hidePopup">
+    <view class="title">维护身份信息</view>
+		<van-field label="姓名" value="{{ nickname }}" border="{{ false }}" clearable placeholder="请输入姓名" bind:input="nameInput" />
+		<van-field label="手机号" value="{{ mobile }}" border="{{ false }}" clearable placeholder="请输入手机号" bind:input="mobileInput" />
+
+    <view class="btn-group">
+			<view class="btn" bindtap="hidePopup">取消</view>
+			<view class="btn" bindtap="updateUser">提交</view>
+		</view>
+  </popup>
+</view>

+ 215 - 0
pages/index/index.wxss

@@ -0,0 +1,215 @@
+page {
+  padding-bottom: 32rpx;
+}
+
+.container {
+  width: 100%;
+  padding: 0 24rpx;
+  background: #f5f5f5;
+}
+
+.container .swiper {
+  width: 100%;
+  height: 312rpx;
+}
+
+.container .swiper image {
+  width: 100%;
+  height: 312rpx;
+}
+
+.container .welfare {
+  padding: 16rpx 32rpx;
+}
+
+.container .welfare .item image {
+  width: 32rpx;
+  height: 32rpx;
+  margin-right: 8rpx;
+}
+
+.container .welfare .item text {
+  font-size: 22rpx;
+  color: #50555F;
+}
+
+.container .category {
+  border-radius: 8rpx;
+  padding-bottom: 40rpx;
+}
+
+.container .category .item {
+  width: 25%;
+  height: 136rpx;
+	margin-top: 40rpx;
+	text-align: center;
+	font-size: 24rpx;
+  color: #50555F;
+}
+
+.container .category .item image {
+  width: 80rpx;
+  height: 80rpx;
+  margin-bottom: 16rpx;
+  border-radius: 50%;
+}
+
+.container .goods {
+  margin-top: 16rpx;
+}
+
+.container .goods .category-scroll {
+  padding: 24rpx 0;
+}
+
+.container .goods .category-scroll .item {
+  line-height: 38rpx;
+  font-size: 32rpx;
+  font-weight: 400;
+  color: #060606;
+}
+
+.container .goods .category-scroll .active {
+  color: #D32D2F;
+}
+
+.container .goods .category-scroll .item:not(:first-child)::before {
+  content: "|";
+  margin-left: 24rpx;
+  margin-right: 64rpx;
+  color: #e7e8ea;
+}
+
+.container .goods .list .item {
+  width: calc((100% - 14rpx) / 2);
+  margin-bottom: 14rpx;
+  border-radius: 8rpx;
+}
+
+.container .goods .list .item:nth-child(2n-1) {
+  margin-right: 14rpx;
+}
+
+.container .goods .list .item image {
+  width: 100%;
+  height: 344rpx;
+  border-radius: 8rpx 8rpx 0 0;
+}
+
+.container .goods .list .item .title {
+  height: 56rpx;
+  margin: 16rpx;
+  line-height: 28rpx;
+  font-size: 24rpx;
+  font-family: HarmonyOS Sans SC-Regular, HarmonyOS Sans SC;
+  font-weight: 400;
+  color: #000;
+}
+
+.container .goods .list .item .label {
+  display: inline-block;
+  margin-left: 16rpx;
+  padding: 0 8rpx;
+  border: 2rpx solid rgba(255, 2, 0, 0.2);
+  border-radius: 4rpx;
+  line-height: 32rpx;
+  font-size: 20rpx;
+  font-family: HarmonyOS Sans SC-Regular, HarmonyOS Sans SC;
+  font-weight: 400;
+  color: #D32D2F;
+}
+
+.container .goods .list .item .block {
+  padding: 0;
+  border: 0;
+}
+
+.container .goods .list .item .price {
+  padding: 16rpx;
+  line-height: 46rpx;
+  font-size: 40rpx;
+  font-family: DIN Alternate-Bold, DIN Alternate;
+  font-weight: bold;
+  color: #060606;
+}
+
+.container .goods .list .item .price text {
+  padding-right: 4rpx;
+  line-height: 28rpx;
+  font-size: 24rpx;
+}
+
+.container .no-more {
+  margin-top: 32rpx;
+  text-align: center;
+  font-size: 24rpx;
+  font-weight: 400;
+  color: #767E8B;
+}
+
+.container .van-empty {
+  background: #fff;
+  border-radius: 8rpx;
+}
+
+.scroll {
+  width: 100%;
+  white-space: nowrap;
+}
+
+.scroll .item {
+  display: inline-block;
+}
+
+
+.user-popup {
+	top: 45%;
+	width: 80%;
+	height: fit-content;
+	border-radius: 30rpx;
+	line-height: 40rpx;
+}
+
+.user-popup .title {
+	padding: 30rpx 0;
+	border: none;
+	text-align: center;
+	font-size: 32rpx;
+	font-weight: 500;
+	font-family: HarmonyOS Sans SC-Medium, HarmonyOS Sans SC;
+	color: #060606;
+}
+
+.user-popup .van-field__placeholder {
+	color: #999;
+}
+
+.user-popup .auth-desc {
+	padding-left: 30rpx;
+	padding-bottom: 20rpx;
+	border-bottom: 2rpx solid rgba(110, 123, 143, 0.16);
+	line-height: 36rpx;
+	font-size: 24rpx;
+	color: #767E8B;
+}
+
+.user-popup .btn-group {
+	margin-top: 30rpx;
+	display: flex;
+}
+
+.user-popup .btn {
+	position: static;
+	background: transparent;
+	border-radius: 0;
+	border-top: 1px solid #f5f5f5;
+	line-height: 100rpx;
+	font-size: 16px;
+	font-weight: 700;
+	color: #576B95;
+}
+
+.user-popup .btn:first-child {
+	border-right: 1px solid #f5f5f5;
+	color: #000;
+}

+ 73 - 0
pages/user/index.js

@@ -0,0 +1,73 @@
+let util = require('../../utils/util')
+let api = require('../../config/api')
+let app = getApp()
+
+Page({
+  data: {
+		fixed: false,
+		userInfo: { nickname: '点击登录', avatar: '/static/images/avatar.png' },
+		userMenus: [
+			{ url: '/packageUser/collect/collect', name: '收藏', value: 0 },
+      { url: '/packageUser/footprint/footprint', name: '浏览足迹', value: 0 }
+		],
+
+		categoryList: [
+			{ pic: "https://www.qdeasydo.com/api/folder/500f9715-cf28-485e-8df3-11bd5127935c", id: 100101307 },
+			{ pic: "https://www.qdeasydo.com/api/folder/6eb7bb4a-dbea-489f-a010-416bf6a8ddd2", id: 100101311 },
+			{ pic: "https://www.qdeasydo.com/api/folder/e061f829-268c-437e-8734-9a34b5c4b2f6", id: 100101313 },
+			{ pic: "https://www.qdeasydo.com/api/folder/2ac688c9-3218-4b1d-a3f3-83f0b420cb3e", id: 100101316 }
+		]
+  },
+
+  onLoad: function() {
+    this.setData({ navHeight: app.globalData.navHeight })
+  },
+
+  onShow: function() {
+		let userInfo = { nickname: '点击登录', avatar: '/static/images/avatar.png' }
+    if (wx.getStorageSync('token')) {
+			userInfo = { ...this.data.userInfo, ...wx.getStorageSync('userInfo') }
+			this.getUser()
+		}
+		this.setData({ userInfo })
+	},
+
+	// 获取用户的登录信息
+  getUser() {
+    util.showLoad('加载中')
+    util.request(api.UserIndex).then(res => {
+      util.hideLoad()
+      if (res.errno === 0) {
+				let { userMenus } = this.data
+				let { collectCount, footPrintCount } = res.data
+        userMenus[0].value = collectCount
+        userMenus[1].value = footPrintCount
+				this.setData({ userMenus })
+      } else util.showErrorToast(res.errmsg)
+    }).catch(() => {
+      util.hideLoad()
+      util.showErrorToast('网络连接失败')
+    })
+  },
+	
+	onPageScroll({ scrollTop }) {
+		const fixed = scrollTop > app.globalData.navHeight ? true : false
+		this.setData({ fixed })
+	},
+
+	redirect({ currentTarget }) {
+		const { url } = currentTarget.dataset
+		if (!wx.getStorageSync('token')) {
+			wx.navigateTo({ url: '/packageLogin/login/login' })
+			return
+		}
+
+		wx.navigateTo({ url })
+	},
+
+	toCategory({ currentTarget }) {
+    const { id } = currentTarget.dataset
+		app.globalData.menuId = id
+    wx.switchTab({ url: '/pages/catalog/catalog' })
+	}
+})

+ 6 - 0
pages/user/index.json

@@ -0,0 +1,6 @@
+{
+  "navigationStyle": "custom",
+  "usingComponents": {
+    "navbar": "/lib/navbar/index"
+  }
+}

+ 26 - 0
pages/user/index.wxml

@@ -0,0 +1,26 @@
+<view class='user'>
+	<!-- 个人中心 个人信息 -->
+	<view class="top">
+		<image class="backgroundImg" src="/static/images/profile_bg.png" />
+		<navbar class="navbar {{ fixed ? 'jhx_bg0' : '' }}" name="个人中心" is_back="{{ false }}" fixed="{{ fixed }}" />
+
+		<view style="height: {{ 232 - navHeight }}px; top: {{ navHeight + 5 }}px;" class="header">
+			<view class="acea-row row-middle">
+				<image src='{{userInfo.avatar}}' data-url="/packageUser/information/information" catchtap="redirect" />
+				<view class='text'>
+					<view class='name line1' data-url="/packageUser/information/information" catchtap="redirect">{{userInfo.nickname}}</view>
+				</view>
+			</view>
+			<view class="person acea-row">
+				<view class="personal" wx:for="{{ userMenus }}" wx:key="index" data-url="{{ item.url }}" catchtap='redirect'>
+					<view class="count">{{ item.value }}</view>
+					<view>{{ item.name }}</view>
+				</view>
+			</view>
+		</view>
+	</view>
+
+  <view class='wrapper'>
+		<image wx:for="{{ categoryList }}" wx:key="id" src="{{ item.pic }}" data-id="{{ item.id }}" bind:tap="toCategory" />
+	</view>
+</view>

+ 75 - 0
pages/user/index.wxss

@@ -0,0 +1,75 @@
+page {
+	padding-bottom: calc(32rpx + constant(safe-area-inset-bottom));
+	padding-bottom: calc(32rpx + env(safe-area-inset-bottom));
+	font-family: HarmonyOS Sans SC-Regular, HarmonyOS Sans SC;
+	font-weight: 400;
+}
+
+.user .top {
+	position: relative;
+	width: 100%;
+	height: 464rpx;
+}
+
+.user .top .backgroundImg {
+	position: absolute;
+	width: 100%;
+	height: 100%;
+}
+
+.user .top .navbar {
+	position: fixed;
+	top: 0;
+	z-index: 980;
+	width: 100%;
+}
+
+.user .top .header {
+	position: relative;
+	padding: 0 24rpx;
+}
+
+.user .top .header image {
+	width: 120rpx;
+	height: 120rpx;
+	margin-right: 30rpx;
+	border-radius: 50%;
+	border: 4rpx solid #f5f5f5;
+}
+
+.user .header .text .name {
+	width: 400rpx;
+	margin-bottom: 10rpx;
+	line-height: 46rpx;
+	font-size: 40rpx;
+	font-family: HarmonyOS Sans SC-Bold, HarmonyOS Sans SC;
+	font-weight: bold;
+	color: #fff;
+}
+
+.user .header .person {
+	width: 100%;
+	margin-top: 30rpx;
+}
+
+.user .header .person .personal {
+	width: 50%;
+	text-align: center;
+	line-height: 32rpx;
+	font-size: 24rpx;
+	color: #fff;
+}
+
+.user .header .person .personal .count {
+	margin-bottom: 16rpx;
+	font-size: 32rpx;
+	font-family: DIN Alternate-Bold, DIN Alternate;
+	font-weight: bold;
+}
+
+.wrapper image {
+	display: block;
+	width: 100%;
+	height: 300rpx;
+	margin: 20rpx 0;
+}

+ 69 - 0
project.config.json

@@ -0,0 +1,69 @@
+{
+  "description": "项目配置文件,详见文档:https://developers.weixin.qq.com/miniprogram/dev/devtools/projectconfig.html",
+  "setting": {
+    "urlCheck": false,
+    "es6": true,
+    "enhance": false,
+    "postcss": true,
+    "preloadBackgroundData": false,
+    "minified": true,
+    "newFeature": true,
+    "coverView": true,
+    "nodeModules": true,
+    "autoAudits": false,
+    "showShadowRootInWxmlPanel": true,
+    "scopeDataCheck": false,
+    "uglifyFileName": true,
+    "checkInvalidKey": true,
+    "checkSiteMap": false,
+    "uploadWithSourceMap": true,
+    "compileHotReLoad": false,
+    "useMultiFrameRuntime": true,
+    "useApiHook": true,
+    "babelSetting": {
+      "ignore": [],
+      "disablePlugins": [],
+      "outputPath": ""
+    },
+    "useIsolateContext": true,
+    "useCompilerModule": true,
+    "userConfirmedUseCompilerModuleSwitch": false,
+    "packNpmManually": true,
+    "packNpmRelationList": [
+      {
+        "packageJsonPath": "./package.json",
+        "miniprogramNpmDistDir": "./miniprogram/"
+      }
+    ],
+    "useApiHostProcess": true,
+    "userConfirmedBundleSwitch": false,
+    "minifyWXSS": true,
+    "disableUseStrict": false,
+    "minifyWXML": true,
+    "showES6CompileOption": false,
+    "useCompilerPlugins": false,
+    "ignoreUploadUnusedFiles": true,
+    "lazyloadPlaceholderEnable": false,
+    "useStaticServer": true,
+    "condition": false,
+    "compileWorklet": false,
+    "localPlugins": false,
+    "swc": false,
+    "disableSWC": true
+  },
+  "compileType": "miniprogram",
+  "libVersion": "3.14.3",
+  "projectname": "wx-mini-program",
+  "simulatorType": "wechat",
+  "simulatorPluginLibVersion": {},
+  "packOptions": {
+    "ignore": [],
+    "include": []
+  },
+  "editorSetting": {
+    "tabIndent": "tab",
+    "tabSize": 2
+  },
+  "condition": {},
+  "appid": "wxc17b59551d6bb89f"
+}

+ 25 - 0
project.private.config.json

@@ -0,0 +1,25 @@
+{
+  "condition": {},
+  "description": "项目私有配置文件。此文件中的内容将覆盖 project.config.json 中的相同字段。项目的改动优先同步到此文件中。详见文档:https://developers.weixin.qq.com/miniprogram/dev/devtools/projectconfig.html",
+  "setting": {
+    "urlCheck": false,
+    "compileHotReLoad": true,
+    "coverView": true,
+    "lazyloadPlaceholderEnable": false,
+    "skylineRenderEnable": false,
+    "preloadBackgroundData": false,
+    "autoAudits": false,
+    "useApiHook": true,
+    "useApiHostProcess": true,
+    "showShadowRootInWxmlPanel": true,
+    "useStaticServer": true,
+    "useLanDebug": false,
+    "showES6CompileOption": false,
+    "checkInvalidKey": true,
+    "ignoreDevUnusedFiles": true,
+    "bigPackageSizeSupport": false,
+    "useIsolateContext": true
+  },
+  "libVersion": "3.14.3",
+  "projectname": "%E5%AF%8C%E7%8E%96%E9%93%AD"
+}

+ 21 - 0
sitemap.json

@@ -0,0 +1,21 @@
+{
+  "desc": "关于本文件的更多信息,请参考文档 https://developers.weixin.qq.com/miniprogram/dev/framework/sitemap.html",
+  "rules": [
+    {
+      "action": "disallow",
+      "page": "packageGoods/checkout/checkout"
+    },
+    {
+      "action": "disallow",
+      "page": "packageGoods/payResult/payResult"
+    },
+    {
+      "action": "disallow",
+      "page": "pages/user/index"
+    },    
+    {
+      "action": "allow",
+      "page": "*"
+    }
+  ]
+}

Разлика између датотеке није приказан због своје велике величине
+ 3512 - 0
static/css/animate.wxss


Разлика између датотеке није приказан због своје велике величине
+ 16 - 0
static/css/guildford.wxss


+ 48 - 0
static/css/login.wxss

@@ -0,0 +1,48 @@
+.login {
+  padding: 100rpx 80rpx 0;
+}
+
+.login .header {
+  margin-bottom: 64rpx;
+  line-height: 56rpx;
+  font-size: 48rpx;
+  font-weight: 500;
+  color: #060606;
+}
+
+.login .van-cell {
+  margin-bottom: 32rpx;
+  padding: 24rpx 0;
+}
+
+.login .van-cell::after {
+  left: 0;
+  right: 0;
+  transform: scaleY(1);
+  border-color: #DCDEE0;
+}
+
+.login .van-cell .van-field__placeholder {
+  line-height: 32rpx;
+  color: #C8C9CC;
+}
+
+.login .van-cell .van-field__icon-container .van-icon {
+  width: 48rpx;
+  height: 48rpx;
+}
+
+.login .btn {
+  margin-top: 64rpx;
+  margin-bottom: 32rpx;
+  background: #F6D5D5;
+  border-radius: 66rpx;
+  line-height: 88rpx;
+  text-align: center;
+  font-size: 32rpx;
+  color: #fff;
+}
+
+.login .active {
+  background: #D32D2F;
+}

Разлика између датотеке није приказан због своје велике величине
+ 17 - 0
static/font/iconfont.wxss


BIN
static/images/avatar.png


BIN
static/images/category.png


BIN
static/images/category@selected.png


BIN
static/images/empty_goods.png


BIN
static/images/home.png


BIN
static/images/home@selected.png


BIN
static/images/icon_close.png


BIN
static/images/icon_search_black.png


+ 0 - 0
static/images/index_shangcheng.png


Неке датотеке нису приказане због велике количине промена