소스 검색

2021--5-6

cmy 3 년 전
커밋
a7009586dc
100개의 변경된 파일15570개의 추가작업 그리고 0개의 파일을 삭제
  1. 11 0
      .hbuilderx/launch.json
  2. 6 0
      .idea/inspectionProfiles/profiles_settings.xml
  3. 8 0
      .idea/modules.xml
  4. 6 0
      .idea/vcs.xml
  5. 32 0
      .idea/workspace.xml
  6. 8 0
      .idea/zhiya.iml
  7. 228 0
      App.vue
  8. 46 0
      api/calculation.js
  9. 98 0
      api/finance.js
  10. 33 0
      api/index.js
  11. 31 0
      api/login.js
  12. 19 0
      api/new.js
  13. 37 0
      api/quotation.js
  14. 59 0
      api/set.js
  15. 10 0
      api/shareQrCode.js
  16. 31 0
      api/tranRecord.js
  17. 35 0
      api/user.js
  18. 37 0
      api/wx.js
  19. 1380 0
      components/Sansnn-uQRCode/uqrcode.js
  20. 229 0
      components/easy-select/easy-select.vue
  21. 20 0
      components/empty.vue
  22. 545 0
      components/lb-picker/README.md
  23. 87 0
      components/lb-picker/index.vue
  24. 0 0
      components/lb-picker/lib/custom-parse-format.min.js
  25. 0 0
      components/lb-picker/lib/dayjs.min.js
  26. 1 0
      components/lb-picker/lib/object-support.min.js
  27. 93 0
      components/lb-picker/mixins/index.js
  28. 378 0
      components/lb-picker/pickers/date-selector-picker.vue
  29. 135 0
      components/lb-picker/pickers/multi-selector-picker.vue
  30. 108 0
      components/lb-picker/pickers/selector-picker.vue
  31. 116 0
      components/lb-picker/pickers/unlinked-selector-picker.vue
  32. 40 0
      components/lb-picker/style/picker-item.scss
  33. 166 0
      components/lb-picker/style/picker.scss
  34. 121 0
      components/lb-picker/utils.js
  35. 216 0
      components/select.vue
  36. 196 0
      components/share.vue
  37. 1201 0
      components/tki-qrcode/qrcode.js
  38. 210 0
      components/tki-qrcode/tki-qrcode.vue
  39. 122 0
      components/uni-badge/uni-badge.vue
  40. 188 0
      components/uni-countdown/uni-countdown.vue
  41. 96 0
      components/uni-icons/icons.js
  42. 10 0
      components/uni-icons/uni-icons.vue
  43. 230 0
      components/uni-list-item/uni-list-item.vue
  44. 68 0
      components/uni-list/uni-list.vue
  45. 65 0
      components/uni-list/uni-refresh.vue
  46. 87 0
      components/uni-list/uni-refresh.wxs
  47. 194 0
      components/uni-load-more/uni-load-more.vue
  48. 396 0
      components/uni-notice-bar/uni-notice-bar.vue
  49. 196 0
      components/uni-number-box.vue
  50. 263 0
      components/uni-popup/uni-popup.vue
  51. 279 0
      components/uni-transition/uni-transition.vue
  52. 226 0
      components/upload-images.vue
  53. 34 0
      interceptor.js
  54. 33 0
      js_sdk/xb-copy/uni-copy.js
  55. 44 0
      main.js
  56. 118 0
      manifest.json
  57. 30 0
      node_modules/jweixin-module/README.md
  58. 0 0
      node_modules/jweixin-module/out/index.js
  59. 60 0
      node_modules/jweixin-module/package.json
  60. 11 0
      package-lock.json
  61. 13 0
      package.json
  62. 275 0
      pages.json
  63. 391 0
      pages/calculation/buyCalculation.vue
  64. 150 0
      pages/calculation/computer.vue
  65. 260 0
      pages/calculation/details.vue
  66. 260 0
      pages/calculation/index.vue
  67. 148 0
      pages/calculation/myCalculation.vue
  68. 168 0
      pages/finance/allMiner.vue
  69. 132 0
      pages/finance/computat.vue
  70. 325 0
      pages/finance/details.vue
  71. 355 0
      pages/finance/index.vue
  72. 485 0
      pages/finance/recharge.vue
  73. 219 0
      pages/finance/transfer.vue
  74. 219 0
      pages/finance/withdraw.vue
  75. 113 0
      pages/finance/xieyi.vue
  76. 304 0
      pages/index/index.vue
  77. 92 0
      pages/index/information.vue
  78. 84 0
      pages/index/informationDetails.vue
  79. 34 0
      pages/index/introduce.vue
  80. 112 0
      pages/index/notice.vue
  81. 92 0
      pages/index/pingtai.vue
  82. 162 0
      pages/index/share.vue
  83. 177 0
      pages/product/index.vue
  84. 205 0
      pages/public/forget.vue
  85. 141 0
      pages/public/login.vue
  86. 204 0
      pages/public/register.vue
  87. 83 0
      pages/public/wxLogin.vue
  88. 124 0
      pages/redirect/redirect.vue
  89. 103 0
      pages/set/set.vue
  90. 190 0
      pages/user/loginPass.vue
  91. 77 0
      pages/user/meaasge.vue
  92. 209 0
      pages/user/myTeam.vue
  93. 190 0
      pages/user/payment.vue
  94. 306 0
      pages/user/user.vue
  95. 441 0
      static/css/public.css
  96. BIN
      static/img/add.png
  97. BIN
      static/img/after.png
  98. BIN
      static/img/befor.png
  99. BIN
      static/img/img01.png
  100. BIN
      static/img/img02.png

+ 11 - 0
.hbuilderx/launch.json

@@ -0,0 +1,11 @@
+{ // launch.json 配置了启动调试时相关设置,configurations下节点名称可为 app-plus/h5/mp-weixin/mp-baidu/mp-alipay/mp-qq/mp-toutiao/mp-360/
+  // launchtype项可配置值为local或remote, local代表前端连本地云函数,remote代表前端连云端云函数
+    "version": "0.0",
+    "configurations": [{
+            "type": "uniCloud",
+            "default": {
+                "launchtype": "remote"
+            }
+        }
+    ]
+}

+ 6 - 0
.idea/inspectionProfiles/profiles_settings.xml

@@ -0,0 +1,6 @@
+<component name="InspectionProjectProfileManager">
+  <settings>
+    <option name="USE_PROJECT_PROFILE" value="false" />
+    <version value="1.0" />
+  </settings>
+</component>

+ 8 - 0
.idea/modules.xml

@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="ProjectModuleManager">
+    <modules>
+      <module fileurl="file://$PROJECT_DIR$/.idea/zhiya.iml" filepath="$PROJECT_DIR$/.idea/zhiya.iml" />
+    </modules>
+  </component>
+</project>

+ 6 - 0
.idea/vcs.xml

@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="VcsDirectoryMappings">
+    <mapping directory="$PROJECT_DIR$" vcs="Git" />
+  </component>
+</project>

+ 32 - 0
.idea/workspace.xml

@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="ChangeListManager">
+    <list default="true" id="5c7c7147-80f3-4209-a0fa-e05844dc7dd8" name="Default Changelist" comment="" />
+    <option name="SHOW_DIALOG" value="false" />
+    <option name="HIGHLIGHT_CONFLICTS" value="true" />
+    <option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
+    <option name="LAST_RESOLUTION" value="IGNORE" />
+  </component>
+  <component name="Git.Settings">
+    <option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$" />
+  </component>
+  <component name="ProjectId" id="1rjNgKygoQSpRn7JALrsirZ2NN9" />
+  <component name="ProjectViewState">
+    <option name="hideEmptyMiddlePackages" value="true" />
+    <option name="showLibraryContents" value="true" />
+  </component>
+  <component name="PropertiesComponent">
+    <property name="RunOnceActivity.OpenProjectViewOnStart" value="true" />
+  </component>
+  <component name="SpellCheckerSettings" RuntimeDictionaries="0" Folders="0" CustomDictionaries="0" DefaultDictionary="application-level" UseSingleDictionary="true" transferred="true" />
+  <component name="TaskManager">
+    <task active="true" id="Default" summary="Default task">
+      <changelist id="5c7c7147-80f3-4209-a0fa-e05844dc7dd8" name="Default Changelist" comment="" />
+      <created>1619485649515</created>
+      <option name="number" value="Default" />
+      <option name="presentableId" value="Default" />
+      <updated>1619485649515</updated>
+    </task>
+    <servers />
+  </component>
+</project>

+ 8 - 0
.idea/zhiya.iml

@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<module type="PYTHON_MODULE" version="4">
+  <component name="NewModuleRootManager">
+    <content url="file://$MODULE_DIR$" />
+    <orderEntry type="inheritedJdk" />
+    <orderEntry type="sourceFolder" forTests="false" />
+  </component>
+</module>

+ 228 - 0
App.vue

@@ -0,0 +1,228 @@
+<script>
+/**
+ * vuex管理登陆状态,具体可以参考官方登陆模板示例
+ */
+import { mapMutations } from 'vuex';
+import interceptor from './interceptor';
+// #ifdef H5
+import { weixindata } from './utils/wxAuthorized';
+// #endif
+export default {
+	data() {
+		return {
+			/* 保存微信信息 */
+			appData: {},
+			weixinObj: '' //保存微信对象
+		};
+	},
+	methods: {
+		...mapMutations('user', ['setUserInfo', 'login','hasLogin']),
+	},
+	onLaunch: function(urlObj) {
+		let obj = this;
+		// 加载缓存中的用户信息
+		let userInfo = uni.getStorageSync('userInfo') || '';
+		// 判断是否拥有用户信息
+		if (userInfo.uid) {
+			//更新登陆状态
+			uni.getStorage({
+				key: 'userInfo',
+				success: res => {
+					obj.setUserInfo(res.data);
+					obj.login(res.data);
+				}
+			});
+		}
+	},
+	onShow: function() {},
+	onHide: function() {}
+};
+</script>
+
+<style lang="scss">
+/*全局公共样式和字体图标*/
+@import '/static/css/public.css';
+view,
+scroll-view,
+swiper,
+swiper-item,
+cover-view,
+cover-image,
+icon,
+text,
+rich-text,
+progress,
+button,
+checkbox,
+form,
+input,
+label,
+radio,
+slider,
+switch,
+textarea,
+navigator,
+audio,
+camera,
+image,
+video {
+	box-sizing: border-box;
+}
+/* 骨架屏替代方案 */
+.Skeleton {
+	background: #f3f3f3;
+	padding: 20rpx 0;
+	border-radius: 8rpx;
+}
+
+/* 图片载入替代方案 */
+.image-wrapper {
+	font-size: 0;
+	background: #f3f3f3;
+	border-radius: 4px;
+	image {
+		width: 100%;
+		height: 100%;
+		transition: 0.6s;
+		opacity: 0;
+		&.loaded {
+			opacity: 1;
+		}
+	}
+}
+// 设置富文本中图片最大宽度
+uni-rich-text img {
+	max-width: 100% !important;
+}
+/*边框*/
+.b-b:after,
+.b-t:after {
+	position: absolute;
+	z-index: 3;
+	left: 0;
+	right: 0;
+	height: 0;
+	content: '';
+	transform: scaleY(0.5);
+	border-bottom: 1px solid $border-color-base;
+}
+
+.b-b:after {
+	bottom: 0;
+}
+
+.b-t:after {
+	top: 0;
+}
+
+/* button样式改写 */
+uni-button,
+button {
+	height: 80rpx;
+	line-height: 80rpx;
+	font-size: $font-lg + 2rpx;
+	font-weight: normal;
+
+	&.no-border:before,
+	&.no-border:after {
+		border: 0;
+	}
+}
+
+uni-button[type='default'],
+button[type='default'] {
+	color: $font-color-dark;
+}
+
+/* input 样式 */
+.input-placeholder {
+	color: #999999;
+}
+
+.placeholder {
+	color: #999999;
+}
+// 边距样式
+@for $i from 1 to 4 {
+	.margin-l-#{$i * 10} {
+		margin-left: $i * 10rpx !important;
+	}
+	.margin-r-#{$i * 10} {
+		margin-right: $i * 10rpx !important;
+	}
+	.margin-t-#{$i * 10} {
+		margin-top: $i * 10rpx !important;
+	}
+	.margin-b-#{$i * 10} {
+		margin-bottom: $i * 10rpx !important;
+	}
+	.margin-#{$i * 10} {
+		margin: $i * 10rpx !important;
+	}
+	.margin-v-#{$i * 10} {
+		margin-top: $i * 10rpx !important;
+		margin-bottom: $i * 10rpx !important;
+	}
+	.margin-c-#{$i * 10} {
+		margin-left: $i * 10rpx !important;
+		margin-right: $i * 10rpx !important;
+	}
+	.padding-l-#{$i * 10} {
+		padding-left: $i * 10rpx !important;
+	}
+	.padding-r-#{$i * 10} {
+		padding-right: $i * 10rpx !important;
+	}
+	.padding-t-#{$i * 10} {
+		padding-top: $i * 10rpx !important;
+	}
+	.padding-b-#{$i * 10} {
+		padding-bottom: $i * 10rpx !important;
+	}
+	.padding-#{$i * 10} {
+		padding: $i * 10rpx !important;
+	}
+	.padding-v-#{$i * 10} {
+		padding-top: $i * 10rpx !important;
+		padding-bottom: $i * 10rpx !important;
+	}
+	.padding-c-#{$i * 10} {
+		padding-left: $i * 10rpx !important;
+		padding-right: $i * 10rpx !important;
+	}
+}
+// 字体大小
+.font-size-sm {
+	font-size: $font-sm;
+}
+.font-size-base {
+	font-size: $font-base;
+}
+.font-size-lg {
+	font-size: $font-lg;
+}
+// 字体颜色
+.font-color-yellow {
+	color: $color-yellow;
+}
+.font-color-gray {
+	color: $color-gray;
+}
+.font-color-red {
+	color: $color-red;
+}
+// 边框颜色
+.border-color-yellow {
+	border: 1rpx solid $color-yellow;
+}
+
+// 修改默认背景颜色
+uni-page-wrapper {
+	background-color:#FFFFFF;
+}
+page{
+	background-color: #FFFFFF;
+	// 设置默认字体
+	font-family: PingFang SC,STHeitiSC-Light,Helvetica-Light,arial,sans-serif,Droid Sans Fallback;
+}
+</style>

+ 46 - 0
api/calculation.js

@@ -0,0 +1,46 @@
+
+import request from '@/utils/request'
+
+export function mining(data) {
+	return request({
+		url: '/api/mining',
+		method: 'get',
+		data
+	});
+}
+
+export function buyMining(data,id) {
+	return request({
+		url: '/api/mining/'+id,
+		method: 'post',
+		data
+	});
+}
+export function miningIndex(data) {
+	return request({
+		url: '/api/mining_index',
+		method: 'get',
+		data
+	});
+}
+export function mymining(data) {
+	return request({
+		url: '/api/my_mining',
+		method: 'get',
+		data
+	});
+}
+export function calculator(data) {
+	return request({
+		url: '/api/mining_calculator',
+		method: 'get',
+		data
+	});
+}
+export function miningDateils(data,id) {
+	return request({
+		url: '/api/mining/'+id,
+		method: 'get',
+		data
+	});
+}

+ 98 - 0
api/finance.js

@@ -0,0 +1,98 @@
+
+import request from '@/utils/request'
+import {upFilse} from '@/utils/request'
+
+export function recharge(data) {
+	return request({
+		url: '/api/recharge/money',
+		method: 'post',
+		data
+	});
+}
+//上传图片
+export function upload(data) {
+	return upFilse({
+		url: '/api/upload/image',
+		method: 'post',
+		data
+	});
+}
+
+export function money(data,id) {
+	return request({
+		url: '/api/recharge/money/'+id,
+		method: 'post',
+		data
+	});
+}
+export function wallet(data) {
+	return request({
+		url: '/api/wallet',
+		method: 'get',
+		data
+	});
+}
+export function moneyLog(data,code) {
+	return request({
+		url: '/api/money/log/'+code,
+		method: 'get',
+		data
+	});
+}
+export function cash(data) {
+	return request({
+		url: '/api/extract/cash',
+		method: 'POST',
+		data
+	});
+}
+export function spread(data) {
+	return request({
+		url: '/api/spread/people',
+		method: 'POST',
+		data
+	});
+}
+
+export function goPay(data) {
+	return request({
+		url: '/api/trade/go_pay',
+		method: 'POST',
+		data
+	});
+}
+export function trade(data) {
+	return request({
+		url: '/api/trade/money_type',
+		method: 'get',
+		data
+	});
+}
+export function cashmoney_type(data) {
+	return request({
+		url: '/api/cash/money_type',
+		method: 'get',
+		data
+	});
+}
+export function calculator(data) {
+	return request({
+		url: '/api/extract/calculator',
+		method: 'post',
+		data
+	});
+}
+export function edit(data,id) {
+	return request({
+		url: '/api/wallet/address/edit/'+id,
+		method: 'post',
+		data
+	});
+}
+export function miner(data) {
+	return request({
+		url: '/api/spread/people/all',
+		method: 'post',
+		data
+	})
+}

+ 33 - 0
api/index.js

@@ -0,0 +1,33 @@
+import request from '@/utils/request'
+
+// 获取首页信息
+export function loadIndexs(data) {
+	return request({
+		url: '/api/index',
+		method: 'get',
+		data
+	});
+}
+export function moneyType(data) {
+	return request({
+		url: '/api/all/money_type',
+		method: 'get',
+		data
+	});
+}
+export function article(data,cid) {
+	return request({
+		url: '/api/article/list/'+cid,
+		method: 'GET',
+		data
+	});
+}
+export function details(data,id) {
+	return request({
+		url: '/api/article/details/'+id,
+		method: 'GET',
+		data
+	});
+}
+
+

+ 31 - 0
api/login.js

@@ -0,0 +1,31 @@
+import request from '@/utils/request'
+
+// 登录
+export function login(data) {
+	return request({
+		url: '/api/login',
+		method: 'post',
+		data
+	});
+}
+// 注册
+export function register(data) {
+	return request({
+		url: '/api/register',
+		method: 'post',
+		data
+	});
+}
+// 验证码
+export function verify(data) {
+	// type=register为注册
+	// type=login为登录
+	return request({
+		url: '/api/register/verify',
+		method: 'post',
+		data
+	});
+}
+
+
+

+ 19 - 0
api/new.js

@@ -0,0 +1,19 @@
+import request from '@/utils/request'
+
+export function article(data,cid) {
+	return request({
+		url: '/api/article/list/'+cid,
+		method: 'get',
+		data
+	});
+}
+export function details(data,id) {
+	return request({
+		url: '/api/article/details/'+id,
+		method: 'get',
+		data
+	});
+}
+
+
+

+ 37 - 0
api/quotation.js

@@ -0,0 +1,37 @@
+import request from '@/utils/request'
+
+export function query(data) {
+	return request({
+		url: '/api/mine/query',
+		method: 'get',
+		data
+	});
+}
+export function order(data) {
+	return request({
+		url: '/api/mine/order',
+		method: 'post',
+		data
+	});
+}
+export function recharge(data) {
+	return request({
+		url: '/api/share',
+		method: 'get',
+		data
+	});
+}
+export function getbill(data) {
+	return request({
+		url: '/api/mine/getbill',
+		method: 'post',
+		data
+	});
+}
+export function ustd(data) {
+	return request({
+		url: '/api/recharge/ustd',
+		method: 'post',
+		data
+	});
+}

+ 59 - 0
api/set.js

@@ -0,0 +1,59 @@
+import request from '@/utils/request'
+import {upFilse} from '@/utils/request'
+
+// 修改用户信息
+export function userEdit(data) {
+	return request({
+		url: '/api/user/edit',
+		method: 'post',
+		data
+	});
+}
+
+//退出登录
+export function logout(data) {
+	return request({
+		url: '/api/logout',
+		method: 'get',
+		data
+	});
+}
+//修改登录密码
+export function updatalogin(data) {
+	return request({
+		url: '/api/register/reset',
+		method: 'post',
+		data
+	});
+}
+//修改交易密码
+export function updatatran(data) {
+	return request({
+		url: '/api/register/tradereset',
+		method: 'post',
+		data
+	});
+}
+export function addmsg(data) {
+	return request({
+		url: '/api/mine/addmsg',
+		method: 'post',
+		data
+	});
+}
+//上传图片
+export function upload(data) {
+	return upFilse({
+		url: '/api/upload/image',
+		method: 'post',
+		data
+	});
+}
+//上传图片
+export function mymsg(data) {
+	return request({
+		url: '/api/mine/mymsg',
+		method: 'post',
+		data
+	});
+}

+ 10 - 0
api/shareQrCode.js

@@ -0,0 +1,10 @@
+import request from '@/utils/request'
+
+// 修改用户信息
+export function spreadBanner(data) {
+	return request({
+		url: '/api/spread/banner',
+		method: 'get',
+		data
+	});
+}

+ 31 - 0
api/tranRecord.js

@@ -0,0 +1,31 @@
+import request from '@/utils/request'
+
+
+export function myrecharge(data) {
+	return request({
+		url: '/api/mine/myrecharge',
+		method: 'post',
+		data
+	});
+}
+export function mycash(data) {
+	return request({
+		url: '/api/mine/mycash',
+		method: 'post',
+		data
+	});
+}
+export function delRecharge(data) {
+	return request({
+		url: '/api/mine/delRecharge',
+		method: 'post',
+		data
+	});
+}
+export function delcash(data) {
+	return request({
+		url: '/api/mine/delcash',
+		method: 'post',
+		data
+	});
+}

+ 35 - 0
api/user.js

@@ -0,0 +1,35 @@
+import request from '@/utils/request'
+
+
+// 获取用户信息
+export function getUserInfo(data) {
+	return request({
+		url: '/api/userinfo',
+		method: 'get',
+		data
+	});
+}
+// 获取用户信息
+export function getUser(data) {
+	return request({
+		url: '/api/user',
+		method: 'get',
+		data
+	});
+}
+//推荐人
+export function spread_people(data) {
+	return request({
+		url: '/api/spread/people',
+		method: 'post',
+		data
+	});
+}
+//推荐人
+export function spread(data) {
+	return request({
+		url: '/api/spread/banner',
+		method: 'GET',
+		data
+	});
+}

+ 37 - 0
api/wx.js

@@ -0,0 +1,37 @@
+import request from '@/utils/request'
+// #ifdef H5
+// 微信分享信息
+export function share(data) {
+	return request({
+		url: '/api/share',
+		method: 'get',
+		data
+	});
+}
+//微信配置
+export function wechatConfig(data) {
+	return request({
+		url: '/api/wechat/config',
+		method: 'get',
+		data
+	});
+}
+// 微信code地址
+export function wechatAuth(data) {
+	return request({
+		url: '/api/wechat/auth',
+		method: 'get',
+		data
+	});
+}
+// #endif
+// #ifdef MP-WEIXIN
+// 微信code地址
+export function wechatMpAuth(data) {
+	return request({
+		url: '/api/wechat/mp_auth',
+		method: 'post',
+		data
+	});
+}
+// #endif

+ 1380 - 0
components/Sansnn-uQRCode/uqrcode.js

@@ -0,0 +1,1380 @@
+//---------------------------------------------------------------------
+// github https://github.com/Sansnn/uQRCode
+//---------------------------------------------------------------------
+
+let uQRCode = {};
+
+(function() {
+	//---------------------------------------------------------------------
+	// QRCode for JavaScript
+	//
+	// Copyright (c) 2009 Kazuhiko Arase
+	//
+	// URL: http://www.d-project.com/
+	//
+	// Licensed under the MIT license:
+	//   http://www.opensource.org/licenses/mit-license.php
+	//
+	// The word "QR Code" is registered trademark of 
+	// DENSO WAVE INCORPORATED
+	//   http://www.denso-wave.com/qrcode/faqpatent-e.html
+	//
+	//---------------------------------------------------------------------
+
+	//---------------------------------------------------------------------
+	// QR8bitByte
+	//---------------------------------------------------------------------
+
+	function QR8bitByte(data) {
+		this.mode = QRMode.MODE_8BIT_BYTE;
+		this.data = data;
+	}
+
+	QR8bitByte.prototype = {
+
+		getLength: function(buffer) {
+			return this.data.length;
+		},
+
+		write: function(buffer) {
+			for (var i = 0; i < this.data.length; i++) {
+				// not JIS ...
+				buffer.put(this.data.charCodeAt(i), 8);
+			}
+		}
+	};
+
+	//---------------------------------------------------------------------
+	// QRCode
+	//---------------------------------------------------------------------
+
+	function QRCode(typeNumber, errorCorrectLevel) {
+		this.typeNumber = typeNumber;
+		this.errorCorrectLevel = errorCorrectLevel;
+		this.modules = null;
+		this.moduleCount = 0;
+		this.dataCache = null;
+		this.dataList = new Array();
+	}
+
+	QRCode.prototype = {
+
+		addData: function(data) {
+			var newData = new QR8bitByte(data);
+			this.dataList.push(newData);
+			this.dataCache = null;
+		},
+
+		isDark: function(row, col) {
+			if (row < 0 || this.moduleCount <= row || col < 0 || this.moduleCount <= col) {
+				throw new Error(row + "," + col);
+			}
+			return this.modules[row][col];
+		},
+
+		getModuleCount: function() {
+			return this.moduleCount;
+		},
+
+		make: function() {
+			// Calculate automatically typeNumber if provided is < 1
+			if (this.typeNumber < 1) {
+				var typeNumber = 1;
+				for (typeNumber = 1; typeNumber < 40; typeNumber++) {
+					var rsBlocks = QRRSBlock.getRSBlocks(typeNumber, this.errorCorrectLevel);
+
+					var buffer = new QRBitBuffer();
+					var totalDataCount = 0;
+					for (var i = 0; i < rsBlocks.length; i++) {
+						totalDataCount += rsBlocks[i].dataCount;
+					}
+
+					for (var i = 0; i < this.dataList.length; i++) {
+						var data = this.dataList[i];
+						buffer.put(data.mode, 4);
+						buffer.put(data.getLength(), QRUtil.getLengthInBits(data.mode, typeNumber));
+						data.write(buffer);
+					}
+					if (buffer.getLengthInBits() <= totalDataCount * 8)
+						break;
+				}
+				this.typeNumber = typeNumber;
+			}
+			this.makeImpl(false, this.getBestMaskPattern());
+		},
+
+		makeImpl: function(test, maskPattern) {
+
+			this.moduleCount = this.typeNumber * 4 + 17;
+			this.modules = new Array(this.moduleCount);
+
+			for (var row = 0; row < this.moduleCount; row++) {
+
+				this.modules[row] = new Array(this.moduleCount);
+
+				for (var col = 0; col < this.moduleCount; col++) {
+					this.modules[row][col] = null; //(col + row) % 3;
+				}
+			}
+
+			this.setupPositionProbePattern(0, 0);
+			this.setupPositionProbePattern(this.moduleCount - 7, 0);
+			this.setupPositionProbePattern(0, this.moduleCount - 7);
+			this.setupPositionAdjustPattern();
+			this.setupTimingPattern();
+			this.setupTypeInfo(test, maskPattern);
+
+			if (this.typeNumber >= 7) {
+				this.setupTypeNumber(test);
+			}
+
+			if (this.dataCache == null) {
+				this.dataCache = QRCode.createData(this.typeNumber, this.errorCorrectLevel, this.dataList);
+			}
+
+			this.mapData(this.dataCache, maskPattern);
+		},
+
+		setupPositionProbePattern: function(row, col) {
+
+			for (var r = -1; r <= 7; r++) {
+
+				if (row + r <= -1 || this.moduleCount <= row + r) continue;
+
+				for (var c = -1; c <= 7; c++) {
+
+					if (col + c <= -1 || this.moduleCount <= col + c) continue;
+
+					if ((0 <= r && r <= 6 && (c == 0 || c == 6)) ||
+						(0 <= c && c <= 6 && (r == 0 || r == 6)) ||
+						(2 <= r && r <= 4 && 2 <= c && c <= 4)) {
+						this.modules[row + r][col + c] = true;
+					} else {
+						this.modules[row + r][col + c] = false;
+					}
+				}
+			}
+		},
+
+		getBestMaskPattern: function() {
+
+			var minLostPoint = 0;
+			var pattern = 0;
+
+			for (var i = 0; i < 8; i++) {
+
+				this.makeImpl(true, i);
+
+				var lostPoint = QRUtil.getLostPoint(this);
+
+				if (i == 0 || minLostPoint > lostPoint) {
+					minLostPoint = lostPoint;
+					pattern = i;
+				}
+			}
+
+			return pattern;
+		},
+
+		createMovieClip: function(target_mc, instance_name, depth) {
+
+			var qr_mc = target_mc.createEmptyMovieClip(instance_name, depth);
+			var cs = 1;
+
+			this.make();
+
+			for (var row = 0; row < this.modules.length; row++) {
+
+				var y = row * cs;
+
+				for (var col = 0; col < this.modules[row].length; col++) {
+
+					var x = col * cs;
+					var dark = this.modules[row][col];
+
+					if (dark) {
+						qr_mc.beginFill(0, 100);
+						qr_mc.moveTo(x, y);
+						qr_mc.lineTo(x + cs, y);
+						qr_mc.lineTo(x + cs, y + cs);
+						qr_mc.lineTo(x, y + cs);
+						qr_mc.endFill();
+					}
+				}
+			}
+
+			return qr_mc;
+		},
+
+		setupTimingPattern: function() {
+
+			for (var r = 8; r < this.moduleCount - 8; r++) {
+				if (this.modules[r][6] != null) {
+					continue;
+				}
+				this.modules[r][6] = (r % 2 == 0);
+			}
+
+			for (var c = 8; c < this.moduleCount - 8; c++) {
+				if (this.modules[6][c] != null) {
+					continue;
+				}
+				this.modules[6][c] = (c % 2 == 0);
+			}
+		},
+
+		setupPositionAdjustPattern: function() {
+
+			var pos = QRUtil.getPatternPosition(this.typeNumber);
+
+			for (var i = 0; i < pos.length; i++) {
+
+				for (var j = 0; j < pos.length; j++) {
+
+					var row = pos[i];
+					var col = pos[j];
+
+					if (this.modules[row][col] != null) {
+						continue;
+					}
+
+					for (var r = -2; r <= 2; r++) {
+
+						for (var c = -2; c <= 2; c++) {
+
+							if (r == -2 || r == 2 || c == -2 || c == 2 ||
+								(r == 0 && c == 0)) {
+								this.modules[row + r][col + c] = true;
+							} else {
+								this.modules[row + r][col + c] = false;
+							}
+						}
+					}
+				}
+			}
+		},
+
+		setupTypeNumber: function(test) {
+
+			var bits = QRUtil.getBCHTypeNumber(this.typeNumber);
+
+			for (var i = 0; i < 18; i++) {
+				var mod = (!test && ((bits >> i) & 1) == 1);
+				this.modules[Math.floor(i / 3)][i % 3 + this.moduleCount - 8 - 3] = mod;
+			}
+
+			for (var i = 0; i < 18; i++) {
+				var mod = (!test && ((bits >> i) & 1) == 1);
+				this.modules[i % 3 + this.moduleCount - 8 - 3][Math.floor(i / 3)] = mod;
+			}
+		},
+
+		setupTypeInfo: function(test, maskPattern) {
+
+			var data = (this.errorCorrectLevel << 3) | maskPattern;
+			var bits = QRUtil.getBCHTypeInfo(data);
+
+			// vertical		
+			for (var i = 0; i < 15; i++) {
+
+				var mod = (!test && ((bits >> i) & 1) == 1);
+
+				if (i < 6) {
+					this.modules[i][8] = mod;
+				} else if (i < 8) {
+					this.modules[i + 1][8] = mod;
+				} else {
+					this.modules[this.moduleCount - 15 + i][8] = mod;
+				}
+			}
+
+			// horizontal
+			for (var i = 0; i < 15; i++) {
+
+				var mod = (!test && ((bits >> i) & 1) == 1);
+
+				if (i < 8) {
+					this.modules[8][this.moduleCount - i - 1] = mod;
+				} else if (i < 9) {
+					this.modules[8][15 - i - 1 + 1] = mod;
+				} else {
+					this.modules[8][15 - i - 1] = mod;
+				}
+			}
+
+			// fixed module
+			this.modules[this.moduleCount - 8][8] = (!test);
+
+		},
+
+		mapData: function(data, maskPattern) {
+
+			var inc = -1;
+			var row = this.moduleCount - 1;
+			var bitIndex = 7;
+			var byteIndex = 0;
+
+			for (var col = this.moduleCount - 1; col > 0; col -= 2) {
+
+				if (col == 6) col--;
+
+				while (true) {
+
+					for (var c = 0; c < 2; c++) {
+
+						if (this.modules[row][col - c] == null) {
+
+							var dark = false;
+
+							if (byteIndex < data.length) {
+								dark = (((data[byteIndex] >>> bitIndex) & 1) == 1);
+							}
+
+							var mask = QRUtil.getMask(maskPattern, row, col - c);
+
+							if (mask) {
+								dark = !dark;
+							}
+
+							this.modules[row][col - c] = dark;
+							bitIndex--;
+
+							if (bitIndex == -1) {
+								byteIndex++;
+								bitIndex = 7;
+							}
+						}
+					}
+
+					row += inc;
+
+					if (row < 0 || this.moduleCount <= row) {
+						row -= inc;
+						inc = -inc;
+						break;
+					}
+				}
+			}
+
+		}
+
+	};
+
+	QRCode.PAD0 = 0xEC;
+	QRCode.PAD1 = 0x11;
+
+	QRCode.createData = function(typeNumber, errorCorrectLevel, dataList) {
+
+		var rsBlocks = QRRSBlock.getRSBlocks(typeNumber, errorCorrectLevel);
+
+		var buffer = new QRBitBuffer();
+
+		for (var i = 0; i < dataList.length; i++) {
+			var data = dataList[i];
+			buffer.put(data.mode, 4);
+			buffer.put(data.getLength(), QRUtil.getLengthInBits(data.mode, typeNumber));
+			data.write(buffer);
+		}
+
+		// calc num max data.
+		var totalDataCount = 0;
+		for (var i = 0; i < rsBlocks.length; i++) {
+			totalDataCount += rsBlocks[i].dataCount;
+		}
+
+		if (buffer.getLengthInBits() > totalDataCount * 8) {
+			throw new Error("code length overflow. (" +
+				buffer.getLengthInBits() +
+				">" +
+				totalDataCount * 8 +
+				")");
+		}
+
+		// end code
+		if (buffer.getLengthInBits() + 4 <= totalDataCount * 8) {
+			buffer.put(0, 4);
+		}
+
+		// padding
+		while (buffer.getLengthInBits() % 8 != 0) {
+			buffer.putBit(false);
+		}
+
+		// padding
+		while (true) {
+
+			if (buffer.getLengthInBits() >= totalDataCount * 8) {
+				break;
+			}
+			buffer.put(QRCode.PAD0, 8);
+
+			if (buffer.getLengthInBits() >= totalDataCount * 8) {
+				break;
+			}
+			buffer.put(QRCode.PAD1, 8);
+		}
+
+		return QRCode.createBytes(buffer, rsBlocks);
+	}
+
+	QRCode.createBytes = function(buffer, rsBlocks) {
+
+		var offset = 0;
+
+		var maxDcCount = 0;
+		var maxEcCount = 0;
+
+		var dcdata = new Array(rsBlocks.length);
+		var ecdata = new Array(rsBlocks.length);
+
+		for (var r = 0; r < rsBlocks.length; r++) {
+
+			var dcCount = rsBlocks[r].dataCount;
+			var ecCount = rsBlocks[r].totalCount - dcCount;
+
+			maxDcCount = Math.max(maxDcCount, dcCount);
+			maxEcCount = Math.max(maxEcCount, ecCount);
+
+			dcdata[r] = new Array(dcCount);
+
+			for (var i = 0; i < dcdata[r].length; i++) {
+				dcdata[r][i] = 0xff & buffer.buffer[i + offset];
+			}
+			offset += dcCount;
+
+			var rsPoly = QRUtil.getErrorCorrectPolynomial(ecCount);
+			var rawPoly = new QRPolynomial(dcdata[r], rsPoly.getLength() - 1);
+
+			var modPoly = rawPoly.mod(rsPoly);
+			ecdata[r] = new Array(rsPoly.getLength() - 1);
+			for (var i = 0; i < ecdata[r].length; i++) {
+				var modIndex = i + modPoly.getLength() - ecdata[r].length;
+				ecdata[r][i] = (modIndex >= 0) ? modPoly.get(modIndex) : 0;
+			}
+
+		}
+
+		var totalCodeCount = 0;
+		for (var i = 0; i < rsBlocks.length; i++) {
+			totalCodeCount += rsBlocks[i].totalCount;
+		}
+
+		var data = new Array(totalCodeCount);
+		var index = 0;
+
+		for (var i = 0; i < maxDcCount; i++) {
+			for (var r = 0; r < rsBlocks.length; r++) {
+				if (i < dcdata[r].length) {
+					data[index++] = dcdata[r][i];
+				}
+			}
+		}
+
+		for (var i = 0; i < maxEcCount; i++) {
+			for (var r = 0; r < rsBlocks.length; r++) {
+				if (i < ecdata[r].length) {
+					data[index++] = ecdata[r][i];
+				}
+			}
+		}
+
+		return data;
+
+	}
+
+	//---------------------------------------------------------------------
+	// QRMode
+	//---------------------------------------------------------------------
+
+	var QRMode = {
+		MODE_NUMBER: 1 << 0,
+		MODE_ALPHA_NUM: 1 << 1,
+		MODE_8BIT_BYTE: 1 << 2,
+		MODE_KANJI: 1 << 3
+	};
+
+	//---------------------------------------------------------------------
+	// QRErrorCorrectLevel
+	//---------------------------------------------------------------------
+
+	var QRErrorCorrectLevel = {
+		L: 1,
+		M: 0,
+		Q: 3,
+		H: 2
+	};
+
+	//---------------------------------------------------------------------
+	// QRMaskPattern
+	//---------------------------------------------------------------------
+
+	var QRMaskPattern = {
+		PATTERN000: 0,
+		PATTERN001: 1,
+		PATTERN010: 2,
+		PATTERN011: 3,
+		PATTERN100: 4,
+		PATTERN101: 5,
+		PATTERN110: 6,
+		PATTERN111: 7
+	};
+
+	//---------------------------------------------------------------------
+	// QRUtil
+	//---------------------------------------------------------------------
+
+	var QRUtil = {
+
+		PATTERN_POSITION_TABLE: [
+			[],
+			[6, 18],
+			[6, 22],
+			[6, 26],
+			[6, 30],
+			[6, 34],
+			[6, 22, 38],
+			[6, 24, 42],
+			[6, 26, 46],
+			[6, 28, 50],
+			[6, 30, 54],
+			[6, 32, 58],
+			[6, 34, 62],
+			[6, 26, 46, 66],
+			[6, 26, 48, 70],
+			[6, 26, 50, 74],
+			[6, 30, 54, 78],
+			[6, 30, 56, 82],
+			[6, 30, 58, 86],
+			[6, 34, 62, 90],
+			[6, 28, 50, 72, 94],
+			[6, 26, 50, 74, 98],
+			[6, 30, 54, 78, 102],
+			[6, 28, 54, 80, 106],
+			[6, 32, 58, 84, 110],
+			[6, 30, 58, 86, 114],
+			[6, 34, 62, 90, 118],
+			[6, 26, 50, 74, 98, 122],
+			[6, 30, 54, 78, 102, 126],
+			[6, 26, 52, 78, 104, 130],
+			[6, 30, 56, 82, 108, 134],
+			[6, 34, 60, 86, 112, 138],
+			[6, 30, 58, 86, 114, 142],
+			[6, 34, 62, 90, 118, 146],
+			[6, 30, 54, 78, 102, 126, 150],
+			[6, 24, 50, 76, 102, 128, 154],
+			[6, 28, 54, 80, 106, 132, 158],
+			[6, 32, 58, 84, 110, 136, 162],
+			[6, 26, 54, 82, 110, 138, 166],
+			[6, 30, 58, 86, 114, 142, 170]
+		],
+
+		G15: (1 << 10) | (1 << 8) | (1 << 5) | (1 << 4) | (1 << 2) | (1 << 1) | (1 << 0),
+		G18: (1 << 12) | (1 << 11) | (1 << 10) | (1 << 9) | (1 << 8) | (1 << 5) | (1 << 2) | (1 << 0),
+		G15_MASK: (1 << 14) | (1 << 12) | (1 << 10) | (1 << 4) | (1 << 1),
+
+		getBCHTypeInfo: function(data) {
+			var d = data << 10;
+			while (QRUtil.getBCHDigit(d) - QRUtil.getBCHDigit(QRUtil.G15) >= 0) {
+				d ^= (QRUtil.G15 << (QRUtil.getBCHDigit(d) - QRUtil.getBCHDigit(QRUtil.G15)));
+			}
+			return ((data << 10) | d) ^ QRUtil.G15_MASK;
+		},
+
+		getBCHTypeNumber: function(data) {
+			var d = data << 12;
+			while (QRUtil.getBCHDigit(d) - QRUtil.getBCHDigit(QRUtil.G18) >= 0) {
+				d ^= (QRUtil.G18 << (QRUtil.getBCHDigit(d) - QRUtil.getBCHDigit(QRUtil.G18)));
+			}
+			return (data << 12) | d;
+		},
+
+		getBCHDigit: function(data) {
+
+			var digit = 0;
+
+			while (data != 0) {
+				digit++;
+				data >>>= 1;
+			}
+
+			return digit;
+		},
+
+		getPatternPosition: function(typeNumber) {
+			return QRUtil.PATTERN_POSITION_TABLE[typeNumber - 1];
+		},
+
+		getMask: function(maskPattern, i, j) {
+
+			switch (maskPattern) {
+
+				case QRMaskPattern.PATTERN000:
+					return (i + j) % 2 == 0;
+				case QRMaskPattern.PATTERN001:
+					return i % 2 == 0;
+				case QRMaskPattern.PATTERN010:
+					return j % 3 == 0;
+				case QRMaskPattern.PATTERN011:
+					return (i + j) % 3 == 0;
+				case QRMaskPattern.PATTERN100:
+					return (Math.floor(i / 2) + Math.floor(j / 3)) % 2 == 0;
+				case QRMaskPattern.PATTERN101:
+					return (i * j) % 2 + (i * j) % 3 == 0;
+				case QRMaskPattern.PATTERN110:
+					return ((i * j) % 2 + (i * j) % 3) % 2 == 0;
+				case QRMaskPattern.PATTERN111:
+					return ((i * j) % 3 + (i + j) % 2) % 2 == 0;
+
+				default:
+					throw new Error("bad maskPattern:" + maskPattern);
+			}
+		},
+
+		getErrorCorrectPolynomial: function(errorCorrectLength) {
+
+			var a = new QRPolynomial([1], 0);
+
+			for (var i = 0; i < errorCorrectLength; i++) {
+				a = a.multiply(new QRPolynomial([1, QRMath.gexp(i)], 0));
+			}
+
+			return a;
+		},
+
+		getLengthInBits: function(mode, type) {
+
+			if (1 <= type && type < 10) {
+
+				// 1 - 9
+
+				switch (mode) {
+					case QRMode.MODE_NUMBER:
+						return 10;
+					case QRMode.MODE_ALPHA_NUM:
+						return 9;
+					case QRMode.MODE_8BIT_BYTE:
+						return 8;
+					case QRMode.MODE_KANJI:
+						return 8;
+					default:
+						throw new Error("mode:" + mode);
+				}
+
+			} else if (type < 27) {
+
+				// 10 - 26
+
+				switch (mode) {
+					case QRMode.MODE_NUMBER:
+						return 12;
+					case QRMode.MODE_ALPHA_NUM:
+						return 11;
+					case QRMode.MODE_8BIT_BYTE:
+						return 16;
+					case QRMode.MODE_KANJI:
+						return 10;
+					default:
+						throw new Error("mode:" + mode);
+				}
+
+			} else if (type < 41) {
+
+				// 27 - 40
+
+				switch (mode) {
+					case QRMode.MODE_NUMBER:
+						return 14;
+					case QRMode.MODE_ALPHA_NUM:
+						return 13;
+					case QRMode.MODE_8BIT_BYTE:
+						return 16;
+					case QRMode.MODE_KANJI:
+						return 12;
+					default:
+						throw new Error("mode:" + mode);
+				}
+
+			} else {
+				throw new Error("type:" + type);
+			}
+		},
+
+		getLostPoint: function(qrCode) {
+
+			var moduleCount = qrCode.getModuleCount();
+
+			var lostPoint = 0;
+
+			// LEVEL1
+
+			for (var row = 0; row < moduleCount; row++) {
+
+				for (var col = 0; col < moduleCount; col++) {
+
+					var sameCount = 0;
+					var dark = qrCode.isDark(row, col);
+
+					for (var r = -1; r <= 1; r++) {
+
+						if (row + r < 0 || moduleCount <= row + r) {
+							continue;
+						}
+
+						for (var c = -1; c <= 1; c++) {
+
+							if (col + c < 0 || moduleCount <= col + c) {
+								continue;
+							}
+
+							if (r == 0 && c == 0) {
+								continue;
+							}
+
+							if (dark == qrCode.isDark(row + r, col + c)) {
+								sameCount++;
+							}
+						}
+					}
+
+					if (sameCount > 5) {
+						lostPoint += (3 + sameCount - 5);
+					}
+				}
+			}
+
+			// LEVEL2
+
+			for (var row = 0; row < moduleCount - 1; row++) {
+				for (var col = 0; col < moduleCount - 1; col++) {
+					var count = 0;
+					if (qrCode.isDark(row, col)) count++;
+					if (qrCode.isDark(row + 1, col)) count++;
+					if (qrCode.isDark(row, col + 1)) count++;
+					if (qrCode.isDark(row + 1, col + 1)) count++;
+					if (count == 0 || count == 4) {
+						lostPoint += 3;
+					}
+				}
+			}
+
+			// LEVEL3
+
+			for (var row = 0; row < moduleCount; row++) {
+				for (var col = 0; col < moduleCount - 6; col++) {
+					if (qrCode.isDark(row, col) &&
+						!qrCode.isDark(row, col + 1) &&
+						qrCode.isDark(row, col + 2) &&
+						qrCode.isDark(row, col + 3) &&
+						qrCode.isDark(row, col + 4) &&
+						!qrCode.isDark(row, col + 5) &&
+						qrCode.isDark(row, col + 6)) {
+						lostPoint += 40;
+					}
+				}
+			}
+
+			for (var col = 0; col < moduleCount; col++) {
+				for (var row = 0; row < moduleCount - 6; row++) {
+					if (qrCode.isDark(row, col) &&
+						!qrCode.isDark(row + 1, col) &&
+						qrCode.isDark(row + 2, col) &&
+						qrCode.isDark(row + 3, col) &&
+						qrCode.isDark(row + 4, col) &&
+						!qrCode.isDark(row + 5, col) &&
+						qrCode.isDark(row + 6, col)) {
+						lostPoint += 40;
+					}
+				}
+			}
+
+			// LEVEL4
+
+			var darkCount = 0;
+
+			for (var col = 0; col < moduleCount; col++) {
+				for (var row = 0; row < moduleCount; row++) {
+					if (qrCode.isDark(row, col)) {
+						darkCount++;
+					}
+				}
+			}
+
+			var ratio = Math.abs(100 * darkCount / moduleCount / moduleCount - 50) / 5;
+			lostPoint += ratio * 10;
+
+			return lostPoint;
+		}
+
+	};
+
+
+	//---------------------------------------------------------------------
+	// QRMath
+	//---------------------------------------------------------------------
+
+	var QRMath = {
+
+		glog: function(n) {
+
+			if (n < 1) {
+				throw new Error("glog(" + n + ")");
+			}
+
+			return QRMath.LOG_TABLE[n];
+		},
+
+		gexp: function(n) {
+
+			while (n < 0) {
+				n += 255;
+			}
+
+			while (n >= 256) {
+				n -= 255;
+			}
+
+			return QRMath.EXP_TABLE[n];
+		},
+
+		EXP_TABLE: new Array(256),
+
+		LOG_TABLE: new Array(256)
+
+	};
+
+	for (var i = 0; i < 8; i++) {
+		QRMath.EXP_TABLE[i] = 1 << i;
+	}
+	for (var i = 8; i < 256; i++) {
+		QRMath.EXP_TABLE[i] = QRMath.EXP_TABLE[i - 4] ^
+			QRMath.EXP_TABLE[i - 5] ^
+			QRMath.EXP_TABLE[i - 6] ^
+			QRMath.EXP_TABLE[i - 8];
+	}
+	for (var i = 0; i < 255; i++) {
+		QRMath.LOG_TABLE[QRMath.EXP_TABLE[i]] = i;
+	}
+
+	//---------------------------------------------------------------------
+	// QRPolynomial
+	//---------------------------------------------------------------------
+
+	function QRPolynomial(num, shift) {
+
+		if (num.length == undefined) {
+			throw new Error(num.length + "/" + shift);
+		}
+
+		var offset = 0;
+
+		while (offset < num.length && num[offset] == 0) {
+			offset++;
+		}
+
+		this.num = new Array(num.length - offset + shift);
+		for (var i = 0; i < num.length - offset; i++) {
+			this.num[i] = num[i + offset];
+		}
+	}
+
+	QRPolynomial.prototype = {
+
+		get: function(index) {
+			return this.num[index];
+		},
+
+		getLength: function() {
+			return this.num.length;
+		},
+
+		multiply: function(e) {
+
+			var num = new Array(this.getLength() + e.getLength() - 1);
+
+			for (var i = 0; i < this.getLength(); i++) {
+				for (var j = 0; j < e.getLength(); j++) {
+					num[i + j] ^= QRMath.gexp(QRMath.glog(this.get(i)) + QRMath.glog(e.get(j)));
+				}
+			}
+
+			return new QRPolynomial(num, 0);
+		},
+
+		mod: function(e) {
+
+			if (this.getLength() - e.getLength() < 0) {
+				return this;
+			}
+
+			var ratio = QRMath.glog(this.get(0)) - QRMath.glog(e.get(0));
+
+			var num = new Array(this.getLength());
+
+			for (var i = 0; i < this.getLength(); i++) {
+				num[i] = this.get(i);
+			}
+
+			for (var i = 0; i < e.getLength(); i++) {
+				num[i] ^= QRMath.gexp(QRMath.glog(e.get(i)) + ratio);
+			}
+
+			// recursive call
+			return new QRPolynomial(num, 0).mod(e);
+		}
+	};
+
+	//---------------------------------------------------------------------
+	// QRRSBlock
+	//---------------------------------------------------------------------
+
+	function QRRSBlock(totalCount, dataCount) {
+		this.totalCount = totalCount;
+		this.dataCount = dataCount;
+	}
+
+	QRRSBlock.RS_BLOCK_TABLE = [
+
+		// L
+		// M
+		// Q
+		// H
+
+		// 1
+		[1, 26, 19],
+		[1, 26, 16],
+		[1, 26, 13],
+		[1, 26, 9],
+
+		// 2
+		[1, 44, 34],
+		[1, 44, 28],
+		[1, 44, 22],
+		[1, 44, 16],
+
+		// 3
+		[1, 70, 55],
+		[1, 70, 44],
+		[2, 35, 17],
+		[2, 35, 13],
+
+		// 4		
+		[1, 100, 80],
+		[2, 50, 32],
+		[2, 50, 24],
+		[4, 25, 9],
+
+		// 5
+		[1, 134, 108],
+		[2, 67, 43],
+		[2, 33, 15, 2, 34, 16],
+		[2, 33, 11, 2, 34, 12],
+
+		// 6
+		[2, 86, 68],
+		[4, 43, 27],
+		[4, 43, 19],
+		[4, 43, 15],
+
+		// 7		
+		[2, 98, 78],
+		[4, 49, 31],
+		[2, 32, 14, 4, 33, 15],
+		[4, 39, 13, 1, 40, 14],
+
+		// 8
+		[2, 121, 97],
+		[2, 60, 38, 2, 61, 39],
+		[4, 40, 18, 2, 41, 19],
+		[4, 40, 14, 2, 41, 15],
+
+		// 9
+		[2, 146, 116],
+		[3, 58, 36, 2, 59, 37],
+		[4, 36, 16, 4, 37, 17],
+		[4, 36, 12, 4, 37, 13],
+
+		// 10		
+		[2, 86, 68, 2, 87, 69],
+		[4, 69, 43, 1, 70, 44],
+		[6, 43, 19, 2, 44, 20],
+		[6, 43, 15, 2, 44, 16],
+
+		// 11
+		[4, 101, 81],
+		[1, 80, 50, 4, 81, 51],
+		[4, 50, 22, 4, 51, 23],
+		[3, 36, 12, 8, 37, 13],
+
+		// 12
+		[2, 116, 92, 2, 117, 93],
+		[6, 58, 36, 2, 59, 37],
+		[4, 46, 20, 6, 47, 21],
+		[7, 42, 14, 4, 43, 15],
+
+		// 13
+		[4, 133, 107],
+		[8, 59, 37, 1, 60, 38],
+		[8, 44, 20, 4, 45, 21],
+		[12, 33, 11, 4, 34, 12],
+
+		// 14
+		[3, 145, 115, 1, 146, 116],
+		[4, 64, 40, 5, 65, 41],
+		[11, 36, 16, 5, 37, 17],
+		[11, 36, 12, 5, 37, 13],
+
+		// 15
+		[5, 109, 87, 1, 110, 88],
+		[5, 65, 41, 5, 66, 42],
+		[5, 54, 24, 7, 55, 25],
+		[11, 36, 12],
+
+		// 16
+		[5, 122, 98, 1, 123, 99],
+		[7, 73, 45, 3, 74, 46],
+		[15, 43, 19, 2, 44, 20],
+		[3, 45, 15, 13, 46, 16],
+
+		// 17
+		[1, 135, 107, 5, 136, 108],
+		[10, 74, 46, 1, 75, 47],
+		[1, 50, 22, 15, 51, 23],
+		[2, 42, 14, 17, 43, 15],
+
+		// 18
+		[5, 150, 120, 1, 151, 121],
+		[9, 69, 43, 4, 70, 44],
+		[17, 50, 22, 1, 51, 23],
+		[2, 42, 14, 19, 43, 15],
+
+		// 19
+		[3, 141, 113, 4, 142, 114],
+		[3, 70, 44, 11, 71, 45],
+		[17, 47, 21, 4, 48, 22],
+		[9, 39, 13, 16, 40, 14],
+
+		// 20
+		[3, 135, 107, 5, 136, 108],
+		[3, 67, 41, 13, 68, 42],
+		[15, 54, 24, 5, 55, 25],
+		[15, 43, 15, 10, 44, 16],
+
+		// 21
+		[4, 144, 116, 4, 145, 117],
+		[17, 68, 42],
+		[17, 50, 22, 6, 51, 23],
+		[19, 46, 16, 6, 47, 17],
+
+		// 22
+		[2, 139, 111, 7, 140, 112],
+		[17, 74, 46],
+		[7, 54, 24, 16, 55, 25],
+		[34, 37, 13],
+
+		// 23
+		[4, 151, 121, 5, 152, 122],
+		[4, 75, 47, 14, 76, 48],
+		[11, 54, 24, 14, 55, 25],
+		[16, 45, 15, 14, 46, 16],
+
+		// 24
+		[6, 147, 117, 4, 148, 118],
+		[6, 73, 45, 14, 74, 46],
+		[11, 54, 24, 16, 55, 25],
+		[30, 46, 16, 2, 47, 17],
+
+		// 25
+		[8, 132, 106, 4, 133, 107],
+		[8, 75, 47, 13, 76, 48],
+		[7, 54, 24, 22, 55, 25],
+		[22, 45, 15, 13, 46, 16],
+
+		// 26
+		[10, 142, 114, 2, 143, 115],
+		[19, 74, 46, 4, 75, 47],
+		[28, 50, 22, 6, 51, 23],
+		[33, 46, 16, 4, 47, 17],
+
+		// 27
+		[8, 152, 122, 4, 153, 123],
+		[22, 73, 45, 3, 74, 46],
+		[8, 53, 23, 26, 54, 24],
+		[12, 45, 15, 28, 46, 16],
+
+		// 28
+		[3, 147, 117, 10, 148, 118],
+		[3, 73, 45, 23, 74, 46],
+		[4, 54, 24, 31, 55, 25],
+		[11, 45, 15, 31, 46, 16],
+
+		// 29
+		[7, 146, 116, 7, 147, 117],
+		[21, 73, 45, 7, 74, 46],
+		[1, 53, 23, 37, 54, 24],
+		[19, 45, 15, 26, 46, 16],
+
+		// 30
+		[5, 145, 115, 10, 146, 116],
+		[19, 75, 47, 10, 76, 48],
+		[15, 54, 24, 25, 55, 25],
+		[23, 45, 15, 25, 46, 16],
+
+		// 31
+		[13, 145, 115, 3, 146, 116],
+		[2, 74, 46, 29, 75, 47],
+		[42, 54, 24, 1, 55, 25],
+		[23, 45, 15, 28, 46, 16],
+
+		// 32
+		[17, 145, 115],
+		[10, 74, 46, 23, 75, 47],
+		[10, 54, 24, 35, 55, 25],
+		[19, 45, 15, 35, 46, 16],
+
+		// 33
+		[17, 145, 115, 1, 146, 116],
+		[14, 74, 46, 21, 75, 47],
+		[29, 54, 24, 19, 55, 25],
+		[11, 45, 15, 46, 46, 16],
+
+		// 34
+		[13, 145, 115, 6, 146, 116],
+		[14, 74, 46, 23, 75, 47],
+		[44, 54, 24, 7, 55, 25],
+		[59, 46, 16, 1, 47, 17],
+
+		// 35
+		[12, 151, 121, 7, 152, 122],
+		[12, 75, 47, 26, 76, 48],
+		[39, 54, 24, 14, 55, 25],
+		[22, 45, 15, 41, 46, 16],
+
+		// 36
+		[6, 151, 121, 14, 152, 122],
+		[6, 75, 47, 34, 76, 48],
+		[46, 54, 24, 10, 55, 25],
+		[2, 45, 15, 64, 46, 16],
+
+		// 37
+		[17, 152, 122, 4, 153, 123],
+		[29, 74, 46, 14, 75, 47],
+		[49, 54, 24, 10, 55, 25],
+		[24, 45, 15, 46, 46, 16],
+
+		// 38
+		[4, 152, 122, 18, 153, 123],
+		[13, 74, 46, 32, 75, 47],
+		[48, 54, 24, 14, 55, 25],
+		[42, 45, 15, 32, 46, 16],
+
+		// 39
+		[20, 147, 117, 4, 148, 118],
+		[40, 75, 47, 7, 76, 48],
+		[43, 54, 24, 22, 55, 25],
+		[10, 45, 15, 67, 46, 16],
+
+		// 40
+		[19, 148, 118, 6, 149, 119],
+		[18, 75, 47, 31, 76, 48],
+		[34, 54, 24, 34, 55, 25],
+		[20, 45, 15, 61, 46, 16]
+	];
+
+	QRRSBlock.getRSBlocks = function(typeNumber, errorCorrectLevel) {
+
+		var rsBlock = QRRSBlock.getRsBlockTable(typeNumber, errorCorrectLevel);
+
+		if (rsBlock == undefined) {
+			throw new Error("bad rs block @ typeNumber:" + typeNumber + "/errorCorrectLevel:" + errorCorrectLevel);
+		}
+
+		var length = rsBlock.length / 3;
+
+		var list = new Array();
+
+		for (var i = 0; i < length; i++) {
+
+			var count = rsBlock[i * 3 + 0];
+			var totalCount = rsBlock[i * 3 + 1];
+			var dataCount = rsBlock[i * 3 + 2];
+
+			for (var j = 0; j < count; j++) {
+				list.push(new QRRSBlock(totalCount, dataCount));
+			}
+		}
+
+		return list;
+	}
+
+	QRRSBlock.getRsBlockTable = function(typeNumber, errorCorrectLevel) {
+
+		switch (errorCorrectLevel) {
+			case QRErrorCorrectLevel.L:
+				return QRRSBlock.RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 0];
+			case QRErrorCorrectLevel.M:
+				return QRRSBlock.RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 1];
+			case QRErrorCorrectLevel.Q:
+				return QRRSBlock.RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 2];
+			case QRErrorCorrectLevel.H:
+				return QRRSBlock.RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 3];
+			default:
+				return undefined;
+		}
+	}
+
+	//---------------------------------------------------------------------
+	// QRBitBuffer
+	//---------------------------------------------------------------------
+
+	function QRBitBuffer() {
+		this.buffer = new Array();
+		this.length = 0;
+	}
+
+	QRBitBuffer.prototype = {
+
+		get: function(index) {
+			var bufIndex = Math.floor(index / 8);
+			return ((this.buffer[bufIndex] >>> (7 - index % 8)) & 1) == 1;
+		},
+
+		put: function(num, length) {
+			for (var i = 0; i < length; i++) {
+				this.putBit(((num >>> (length - i - 1)) & 1) == 1);
+			}
+		},
+
+		getLengthInBits: function() {
+			return this.length;
+		},
+
+		putBit: function(bit) {
+
+			var bufIndex = Math.floor(this.length / 8);
+			if (this.buffer.length <= bufIndex) {
+				this.buffer.push(0);
+			}
+
+			if (bit) {
+				this.buffer[bufIndex] |= (0x80 >>> (this.length % 8));
+			}
+
+			this.length++;
+		}
+	};
+
+	//---------------------------------------------------------------------
+	// Support Chinese
+	//---------------------------------------------------------------------
+	function utf16To8(text) {
+		var result = '';
+		var c;
+		for (var i = 0; i < text.length; i++) {
+			c = text.charCodeAt(i);
+			if (c >= 0x0001 && c <= 0x007F) {
+				result += text.charAt(i);
+			} else if (c > 0x07FF) {
+				result += String.fromCharCode(0xE0 | c >> 12 & 0x0F);
+				result += String.fromCharCode(0x80 | c >> 6 & 0x3F);
+				result += String.fromCharCode(0x80 | c >> 0 & 0x3F);
+			} else {
+				result += String.fromCharCode(0xC0 | c >> 6 & 0x1F);
+				result += String.fromCharCode(0x80 | c >> 0 & 0x3F);
+			}
+		}
+		return result;
+	}
+
+	uQRCode = {
+		
+		defaults: {
+			size: 258,
+			margin: 0,
+			backgroundColor: '#ffffff',
+			foregroundColor: '#000000',
+			fileType: 'png', // 'jpg', 'png'
+			correctLevel: 3,
+			typeNumber: -1
+		},
+
+		make: function(options) {
+			var defaultOptions = {
+				canvasId: options.canvasId,
+				componentInstance: options.componentInstance,
+				text: options.text,
+				size: this.defaults.size,
+				margin: this.defaults.margin,
+				backgroundColor: this.defaults.backgroundColor,
+				foregroundColor: this.defaults.foregroundColor,
+				fileType: this.defaults.fileType,
+				correctLevel: this.defaults.correctLevel,
+				typeNumber: this.defaults.typeNumber
+			};
+			if (options) {
+				for (var i in options) {
+					defaultOptions[i] = options[i];
+				}
+			}
+			options = defaultOptions;
+			if (!options.canvasId) {
+				console.error('uQRCode: Please set canvasId!');
+				return;
+			}
+
+			function createCanvas() {
+				var qrcode = new QRCode(options.typeNumber, options.correctLevel);
+				qrcode.addData(utf16To8(options.text));
+				qrcode.make();
+
+				var ctx = uni.createCanvasContext(options.canvasId, options.componentInstance);
+				ctx.setFillStyle(options.backgroundColor);
+				ctx.fillRect(0, 0, options.size, options.size);
+
+				var tileW = (options.size - options.margin * 2) / qrcode.getModuleCount();
+				var tileH = tileW;
+
+				for (var row = 0; row < qrcode.getModuleCount(); row++) {
+					for (var col = 0; col < qrcode.getModuleCount(); col++) {
+						var style = qrcode.isDark(row, col) ? options.foregroundColor : options.backgroundColor;
+						ctx.setFillStyle(style);
+						var x = Math.round(col * tileW) + options.margin;
+						var y = Math.round(row * tileH) + options.margin;
+						var w = Math.ceil((col + 1) * tileW) - Math.floor(col * tileW);
+						var h = Math.ceil((row + 1) * tileW) - Math.floor(row * tileW);
+						ctx.fillRect(x, y, w, h);
+					}
+				}
+
+				setTimeout(function() {
+					ctx.draw(false, function() {
+						setTimeout(function() {
+							uni.canvasToTempFilePath({
+								canvasId: options.canvasId,
+								fileType: options.fileType,
+								width: options.size,
+								height: options.size,
+								destWidth: options.size,
+								destHeight: options.size,
+								success: function(res) {
+									options.success && options.success(res.tempFilePath);
+								},
+								fail: function(error) {
+									options.fail && options.fail(error);
+								},
+								complete: function(res) {
+									options.complete && options.complete(res);
+								}
+							}, options.componentInstance);
+						}, options.text.length + 100);
+					});
+				}, 150);
+			}
+			
+			createCanvas();
+		}
+
+	}
+
+})()
+
+export default uQRCode

+ 229 - 0
components/easy-select/easy-select.vue

@@ -0,0 +1,229 @@
+<template>
+	<view class="easy-select" @click.stop="trigger" :style="[easySelectSize]">
+		<input type="text" v-model="value" :placeholder="placeholder" disabled clearable>
+		<!-- <view class="easy-select-suffix" :style="{border: '1px solid rgba(0,0,0,0)'}" :class="[showSuffix]">
+			<view class="easy-select-down-tag"></view>
+		</view> -->
+		<view class="easy-select-options" v-if="showOptions" :style="{'min-width': boundingClientRect.width + 'px', top: optionsGroupTop, margin: optionsGroupMargin}">
+			<view class="easy-select-options-item" v-for="item in options" :key="item.code" @click.stop="select(item)" :class="{active: currentSelect.name === item.name}">
+				<text>{{item.name}}</text>
+			</view>
+		</view>
+	</view>
+</template>
+
+<script>
+	/**
+	 * easy-select
+	 * @author Snoop zhang
+	 * @description Select Component
+	 * */
+	const COMPONENT_NAME = 'easy-select'
+	const MAX_OPTIONS_HEIGHT = 137 // 修改务必也修改easy-select-options的css部分
+	const OPTIONS_ITEM_HEIGHT = 33 // 修改务必也修改easy-select-options-item的css部分
+	const OPTIONS_MARGIN = 10
+	const OPTIONS_PADDING = 6 * 2 + 2 // + 2是border
+	const OPTIONS_OTHER_HEIGHT = OPTIONS_MARGIN + OPTIONS_PADDING
+	const STORAGE_KEY = '_easyWindowHeight'
+	const SIZE = {
+		'medium': {
+			width: '150px',
+			height: '40px'
+		},
+		'small': {
+			width: '200px',
+			height: '30px'
+		},
+		'mini': {
+			width: '160px',
+			height: '30px'
+		}
+	}
+	
+	export default {
+		name: COMPONENT_NAME,
+		props: {
+			windowHeight: {
+				type: [Number, String],
+				default: 0
+			},
+			placeholder: {
+				type: String,
+				default: '请选择'
+			},
+			value: {
+				type: String,
+				default: '双皮奶'
+			},
+			size: {
+				type: String,
+				default: 'medium'
+			},
+			options: {
+				type: Array,
+				default () {
+					return []
+				}
+			}
+		},
+		data() {
+			return {
+				showOptions: false,
+				boundingClientRect: {},
+				currentSelect: {},
+				optionsGroupTop: 'auto',
+				optionsGroupMargin: ''
+			}
+		},
+		computed: {
+			showSuffix() {
+				return this.showOptions ? 'showOptions' : 'no-showOptions'
+			},
+			easySelectSize() {
+				let size = this.size.toLowerCase()
+				if (size in SIZE) {
+					return {
+						width: SIZE[size].width,
+						height: SIZE[size].height
+					}
+				} else {
+					return {}
+				}
+			}
+		},
+		mounted() {
+			const elQuery = uni.createSelectorQuery().in(this)
+			elQuery.select('.easy-select').boundingClientRect(data => {
+				this.boundingClientRect = data
+			}).exec();
+			try {
+				if (!this.windowHeight) {
+					const storageHeihgt = uni.getStorageSync(STORAGE_KEY)
+					if (storageHeihgt) {
+						this.easyWindowHeight = storageHeihgt
+						return
+					}
+					const res = uni.getSystemInfoSync();
+					this.easyWindowHeight = res.windowHeight
+					uni.setStorageSync(STORAGE_KEY, this.easyWindowHeight)
+				}
+			} catch (e) {
+			    // error
+			}
+		},
+		methods: {
+			trigger(e) {
+				const view = uni.createSelectorQuery().in(this)
+				view.select('.easy-select').fields({rect: true}, data => {
+					let {	top, bottom } = data
+					const thresholdHeight = Math.min(MAX_OPTIONS_HEIGHT + OPTIONS_MARGIN, (this.options.length * OPTIONS_ITEM_HEIGHT) +
+						OPTIONS_OTHER_HEIGHT)
+					bottom = Number(this.windowHeight || this.easyWindowHeight) - (top + this.boundingClientRect.height) // 距离底部的距离等于视口的高度减上top加select组件的高度
+
+					// judge direction
+					if (bottom < thresholdHeight) {
+						this.optionsGroupDirection = 'up'
+						this.optionsGroupTop = -thresholdHeight - 12 + 'px'
+						this.optionsGroupMargin = '0'
+					} else {
+						this.optionsGroupDirection = 'down'
+						this.optionsGroupTop = 'auto'
+						this.optionsGroupMargin = '10px 0 0 0'
+					}
+
+					// if (this.scrollTop < )
+					this.showOptions = !this.showOptions
+				}).exec();
+			},
+			select(options) {
+				this.showOptions = false
+				this.currentSelect = options
+				this.$emit('selectOne', options)
+			},
+			hideOptions() {
+				this.showOptions = false
+			}
+		}
+	}
+</script>
+
+<style lang="scss" scoped>
+	.easy-select {
+		position: relative;
+		border-radius: 4px;
+		color: #606266;
+		outline: none;
+		box-sizing: content-box;
+		padding: 50rpx 0rpx;
+		height: 30px;
+		input{
+			width: 100%;
+			height: 80rpx;
+			border: 2rpx solid #999999;
+			padding-left: 25rpx;
+			box-shadow:0px 3px 5px 0px rgba(0, 0, 0, 0.27);
+			border-radius:11rpx;
+		}
+	}
+
+	.easy-select input {
+		padding: 0 18rpx;
+		padding-right: 60rpx;
+		overflow: hidden;
+		white-space: nowrap;
+		text-overflow: ellipsis;
+		height: 100% !important;
+		min-height: 100% !important;
+	}
+
+	.easy-select .easy-select-suffix {
+		position: absolute;
+		box-sizing: border-box;
+		height: 100%;
+		right: 5px;
+		top: 0;
+		display: flex;
+		align-items: center;
+		transform: rotate(180deg);
+		transition: all .3s;
+		transform-origin: center;
+	}
+
+	.easy-select .showOptions {
+		transform: rotate(0) !important;
+	}
+
+	.easy-select .no-showOptions {
+		transform: rotate(180deg) !important;
+	}
+
+	.easy-select .easy-select-options {
+		position: absolute;
+		padding: 6px 0;
+		margin-top: 10px;
+		border: 1px solid #e4e7ed;
+		border-radius: 4px;
+		background-color: #fff;
+		box-shadow: 0 2px 12px 0 rgba(0, 0, 0, .1);
+		box-sizing: border-box;
+		transform-origin: center top;
+		z-index: 2238;
+		overflow: scroll;
+		max-height: 274rpx;
+	}
+
+	.easy-select .easy-select-options-item {
+		padding: 0 20rpx;
+		position: relative;
+		white-space: nowrap;
+		font-size: 14px;
+		color: #606266;
+		height: 33px;
+		line-height: 33px;
+		box-sizing: border-box;
+	}
+
+	.easy-select .active {
+		background-color: #F5F7FA
+	}
+</style>

파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 20 - 0
components/empty.vue


+ 545 - 0
components/lb-picker/README.md

@@ -0,0 +1,545 @@
+<p align="center">
+  <a href="https://github.com/liub1934/uni-lb-picker">
+    <img src="https://img.shields.io/github/stars/liub1934/uni-lb-picker">
+  </a>
+  <a href="https://github.com/liub1934/uni-lb-picker/fork">
+    <img src="https://img.shields.io/github/forks/liub1934/uni-lb-picker">
+  </a>
+  <a href="https://github.com/liub1934/uni-lb-picker/issues">
+    <img src="https://img.shields.io/github/issues/liub1934/uni-lb-picker">
+  </a>
+  <a href="https://www.npmjs.com/package/uni-lb-picker">
+    <img src="https://img.shields.io/npm/v/uni-lb-picker">
+  </a>
+  <a href="https://npmcharts.com/compare/uni-lb-picker?minimal=true">
+    <img src="https://img.shields.io/npm/dm/uni-lb-picker">
+  </a>
+  <a href="https://standardjs.com">
+    <img src="https://img.shields.io/badge/code%20style-standard-brightgreen">
+  </a>
+  <a href="https://github.com/liub1934/uni-lb-picker/blob/master/LICENSE">
+    <img src="https://img.shields.io/github/license/liub1934/uni-lb-picker">
+  </a>
+</p>
+
+插件市场里面的 picker 选择器不满足自己的需求,所以自己写了一个简单的 picker 选择器,可扩展、可自定义,一般满足日常需要。  
+Github:[点击前往](https://github.com/liub1934/uni-lb-picker)  
+插件市场:[点击前往](https://ext.dcloud.net.cn/plugin?id=1111)  
+H5 Demo:[点击预览](https://github.liubing.me/uni-lb-picker)
+
+> 如果问题最好去 github 反馈,插件市场评论区留下五星好评即可, [点我去反馈](https://github.com/liub1934/uni-lb-picker/issues/new)  
+> 最好提供一下使用的什么端,数据结构及大概的代码,我好复现找问题,不要直接提`怎么xxx报错了`等没意义的问题,神仙也不知道你为啥报错了。
+
+> **由于之前`cancel`拼写失误,写成了`cancle`,`v1.08`现已修正,如果之前版本有使用`cancel`事件的,更新后请及时修正。**
+
+## 兼容性
+
+App + Nvue + H5 + 各平台小程序(快应用及 360 未测试)
+
+## 功能
+
+- 单选
+- 多级联动,非多级联动,理论支持任意级数
+- 省市区选择,基于多级联动
+- 日期选择器,年月日时分秒可自由组合选择(引入了`dayjs`方便处理日期)
+- 自定义选择器头部确定取消按钮颜色及插槽支持
+- 选择器可视区自定义滚动个数
+- 自定义数据字段,满足不同人的需求
+- 自定义选择器样式
+- formatter 格式化自定义显示
+- 单选及非联动选择支持扁平化的简单数据,如下形式:
+
+```javascript
+// 单选列表
+list1: ['选项1', '选项2', '选项2'],
+// 非联动选择列表
+list2: [
+  ['选项1', '选项2', '选项3'],
+  ['选项11', '选项22', '选项33'],
+  ['选项111', '选项222', '选项333']
+]
+```
+
+## 引入插件
+
+单独引入,在需要使用的页面上 import 引入即可
+
+```html
+<template>
+  <view>
+    <lb-picker></lb-picker>
+  </view>
+</template>
+
+<script>
+  import LbPicker from '@/components/lb-picker'
+  export default {
+    components: {
+      LbPicker
+    }
+  }
+</script>
+```
+
+全局引入,`main.js`中 import 引入并注册即可全局使用
+
+```jsvascript
+import LbPicker from '@/components/lb-picker'
+Vue.component("lb-picker", LbPicker)
+```
+
+easycom 引入(推荐使用此方式)
+
+`pages.json`加上如下配置:
+
+```json
+"easycom": {
+  "autoscan": true,
+  "custom": {
+    "lb-picker": "@/components/lb-picker/index.vue"
+  }
+}
+```
+
+npm 安装引入:
+
+```shell
+npm install uni-lb-picker
+```
+
+```jsvascript
+import LbPicker from 'uni-lb-picker'
+```
+
+## 选择器数据格式
+
+### 单选
+
+常规数据
+
+```javascript
+list: [
+  {
+    label: '选项1',
+    value: '1'
+  },
+  {
+    label: '选项2',
+    value: '2'
+  }
+]
+```
+
+扁平化简单数据
+
+```javascript
+list: ['选项1', '选项2']
+```
+
+### 多级联动
+
+```javascript
+list: [
+  {
+    label: '选项1',
+    value: '1',
+    children: [
+      {
+        label: '选项1-1',
+        value: '1-1',
+        children: [
+          {
+            label: '选项1-1-1',
+            value: '1-1-1'
+          }
+        ]
+      }
+    ]
+  }
+]
+```
+
+### 非联动选择
+
+常规数据
+
+```javascript
+list: [
+  [
+    { label: '选项1', value: '1' },
+    { label: '选项2', value: '2' },
+    { label: '选项3', value: '3' }
+  ],
+  [
+    { label: '选项11', value: '11' },
+    { label: '选项22', value: '22' },
+    { label: '选项33', value: '33' }
+  ],
+  [
+    { label: '选项111', value: '111' },
+    { label: '选项222', value: '222' },
+    { label: '选项333', value: '333' }
+  ]
+]
+```
+
+扁平化简单数据
+
+```javascript
+list: [
+  ['选项1', '选项2', '选项3'],
+  ['选项11', '选项22', '选项33'],
+  ['选项111', '选项222', '选项333']
+]
+```
+
+## 调用显示选择器
+
+通过`ref`形式手动调用`show`方法显示,隐藏同理调用`hide`
+
+```html
+<lb-picker ref="picker"></lb-picker>
+```
+
+```javascript
+this.$refs.picker.show() // 显示
+this.$refs.picker.hide() // 隐藏
+```
+
+`v1.1.3`新增,将需要点击的元素包裹在`lb-picker`中即可。
+
+```html
+<lb-picker>
+  <button>点我直接打开选择器</button>
+</lb-picker>
+```
+
+## 绑定值及设置默认值
+
+支持 vue 中`v-model`写法绑定值,无需自己维护选中值的索引。
+
+```javascript
+<lb-picker v-model="value1"></lb-picker>
+<lb-picker v-model="value2"></lb-picker>
+<lb-picker v-model="value3"></lb-picker>
+
+data () {
+  return {
+    value1: '', // 单选
+    value2: [], // 多列联动选择
+    value2: '2021-01-05', // 日期,设置一个具体的日期,留空则默认选中当前日期
+  }
+}
+```
+
+## 多个选择器
+
+通过设置不同的`ref`,然后调用即可
+
+```javascript
+<lb-picker ref="picker1"></lb-picker>
+<lb-picker ref="picker2"></lb-picker>
+
+this.$refs.picker1.show() // picker1显示
+this.$refs.picker2.show() // picker2显示
+```
+
+## 省市区选择
+
+省市区选择是基于多列联动选择,数据来源:[https://github.com/modood/Administrative-divisions-of-China](https://github.com/modood/Administrative-divisions-of-China),  
+省市区文件位于`/pages/demos/area-data-min.js`,自行引入即可,可参考`demo3省市区选择`,  
+也可使用自己已有的省市区数据,如果数据字段不一样,也可以自定义,参考下方自定义数据字段。
+
+## 自定义数据字段
+
+为了满足不同人的需求,插件支持自定义数据字段名称, 插件默认的数据字段如下形式:
+
+```javascript
+list: [
+  {
+    label: '选择1',
+    value: 1,
+    children: []
+  },
+  {
+    label: '选择1',
+    value: 1,
+    children: []
+  }
+]
+```
+
+如果你的数据字段和上面不一样,如下形式:
+
+```javascript
+list: [
+  {
+    text: '选择1',
+    id: 1,
+    child: []
+  },
+  {
+    text: '选择1',
+    id: 1,
+    child: []
+  }
+]
+```
+
+通过设置参数中的`props`即可,如下所示:
+
+```javascript
+<lb-picker :props="myProps"></lb-picker>
+
+data () {
+  return {
+    myProps: {
+      label: 'text',
+      value: 'id',
+      children: 'child'
+    }
+  }
+}
+```
+
+## 插槽使用
+
+选择器支持一些可自定义化的插槽,如选择器的取消和确定文字按钮,如果需要对其自定义处理的话,比如加个 icon 图标之类的,可使用插槽,使用方法如下:
+
+```html
+<lb-picker>
+  <view slot="cancel-text">我是自定义取消</view>
+  <view slot="confirm-text">我是自定义确定</view>
+</lb-picker>
+```
+
+也可参考示例中的`demo5`,自定义插槽元素样式交给开发者自由调整,插槽仅提供预留位置。
+
+其他插槽见下。
+
+## 参数及事件
+
+### Props
+
+#### 通用 Props
+
+| 参数                   | 说明                                                                                                                                                                                                                                                                                                                                                                                                                                                                      | 类型                                      | 可选值                                                                                                | 默认值             |
+| :--------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | :---------------------------------------- | :---------------------------------------------------------------------------------------------------- | :----------------- |
+| value/v-model          | 绑定值,联动选择为 Array 类型                                                                                                                                                                                                                                                                                                                                                                                                                                             | String/Number/Array                       | -                                                                                                     | 日期类型为当前日期 |
+| mode                   | 选择器类型                                                                                                                                                                                                                                                                                                                                                                                                                                                                | String                                    | selector 单选/multiSelector 多级联动/unlinkedSelector 多级非联动/dateSelector 日期选择`(v1.1.9 新增)` | selector           |
+| cancel-text            | 取消文字                                                                                                                                                                                                                                                                                                                                                                                                                                                                  | String                                    | -                                                                                                     | 取消               |
+| cancel-color           | 取消文字颜色                                                                                                                                                                                                                                                                                                                                                                                                                                                              | String                                    | -                                                                                                     | #999               |
+| confirm-text           | 确定文字                                                                                                                                                                                                                                                                                                                                                                                                                                                                  | String                                    | -                                                                                                     | 确定               |
+| confirm-color          | 确定文字颜色                                                                                                                                                                                                                                                                                                                                                                                                                                                              | String                                    | -                                                                                                     | #007aff            |
+| empty-text             | `(v1.0.7 新增)`选择器列表为空的时候显示的文字                                                                                                                                                                                                                                                                                                                                                                                                                             | String                                    | -                                                                                                     | 暂无数据           |
+| empty-color            | `(v1.0.7 新增)`暂无数据文字颜色                                                                                                                                                                                                                                                                                                                                                                                                                                           | String                                    | -                                                                                                     | #999               |
+| column-num             | 可视滚动区域内滚动个数,最好设置奇数值                                                                                                                                                                                                                                                                                                                                                                                                                                    | Number                                    | -                                                                                                     | 5                  |
+| radius                 | 选择器顶部圆角,支持 rpx,如 radius="10rpx"                                                                                                                                                                                                                                                                                                                                                                                                                               | String                                    | -                                                                                                     | -                  |
+| column-style           | `(v1.1.6 重新新增)`选择器默认样式,仅`nvue`支持,其他端见下`选择器自定义样式`说明                                                                                                                                                                                                                                                                                                                                                                                         | Object                                    | -                                                                                                     | -                  |
+| active-column-style    | `(v1.1.6 重新新增)`选择器选中样式,仅`nvue`支持,其他端见下`选择器自定义样式`说明                                                                                                                                                                                                                                                                                                                                                                                         | Object                                    | -                                                                                                     | -                  |
+| loading                | 选择器是否显示加载中,可使用 loading 插槽自定义加载效果                                                                                                                                                                                                                                                                                                                                                                                                                   | Boolean                                   | -                                                                                                     | -                  |
+| mask-color             | 遮罩层颜色                                                                                                                                                                                                                                                                                                                                                                                                                                                                | String                                    | -                                                                                                     | rgba(0, 0, 0, 0.4) |
+| show-mask              | `(v1.1.0 新增)`是否显示遮罩层                                                                                                                                                                                                                                                                                                                                                                                                                                             | Boolean                                   | true/false                                                                                            | true               |
+| close-on-click-mask    | 点击遮罩层是否关闭选择器                                                                                                                                                                                                                                                                                                                                                                                                                                                  | Boolean                                   | true/false                                                                                            | true               |
+| ~~change-on-init~~     | ~~(v1.0.7 已弃用)初始化时是否触发 change 事件~~                                                                                                                                                                                                                                                                                                                                                                                                                           | Boolean                                   | true/false                                                                                            | -                  |
+| dataset                | `(v1.0.7 新增)`可以向组件中传递任意的自定义的数据(对象形式数据),如`:dataset="{name:'test'}"`,在`confirm`或`change`事件中可以取到                                                                                                                                                                                                                                                                                                                                      | Object                                    | -                                                                                                     | -                  |
+| show-header            | `(v1.0.8 新增)`是否显示选择器头部                                                                                                                                                                                                                                                                                                                                                                                                                                         | Boolean                                   | -                                                                                                     | true               |
+| inline                 | `(v1.0.8 新增)`inline 模式,开启后默认显示选择器,无需点击弹出,可以配合`show-header`一起使用                                                                                                                                                                                                                                                                                                                                                                             | Boolean                                   | -                                                                                                     | -                  |
+| z-index                | `(v1.0.9 新增)`选择器层级,遮罩层默认-1                                                                                                                                                                                                                                                                                                                                                                                                                                   | Number                                    | -                                                                                                     | 999                |
+| safe-area-inset-bottom | `(v1.1.4 新增)`是否留出底部安全距离(nvue 无效)                                                                                                                                                                                                                                                                                                                                                                                                                          | Boolean                                   | true/false                                                                                            | true               |
+| disabled               | `(v1.1.4 新增)`是否禁用选择器,禁用后无法弹出选择器                                                                                                                                                                                                                                                                                                                                                                                                                       | Boolean                                   | -                                                                                                     | -                  |
+| align                  | `(v1.1.6 新增)`选择器中文字对齐方式,默认居中                                                                                                                                                                                                                                                                                                                                                                                                                             | String                                    | left/center/right                                                                                     | center             |
+| press-enable           | `(v1.1.6 新增)`是否开启长按选择器数据`showtoast`弹出`label`提示,部分情况下选择器数据文字过长会显示省略号,如需查看完整的文字内容,可开启此选项,长按后会`showtoast`弹出完整的文字内容,默认不开启(支付宝小程序暂不支持[详情](https://ask.dcloud.net.cn/question/106237))                                                                                                                                                                                               | Boolean                                   | -                                                                                                     | -                  |
+| press-time             | `(v1.1.6 新增)`长按触发时间,单位毫秒 ms                                                                                                                                                                                                                                                                                                                                                                                                                                  | Number                                    | -                                                                                                     | 500                |
+| formatter              | `(v1.1.7 新增)`格式化自定义选择器文字内容,`Function`类型,`return`一个字符串(日期选择器`百度、支付宝、头条小程序`不支持,其他选择器仅`app` `nvue` `h5`支持),`item`当前项信息,`rowIndex`当前数据所在行数,`columnIndex`当前数据所在列数,写法参考[demo14](https://github.com/liub1934/uni-lb-picker/blob/master/pages/demos/demo14/demo14.vue#L206),日期选择器可参考[demo16](https://github.com/liub1934/uni-lb-picker/blob/master/pages/demos/demo16/demo16.vue#L245) | Function({ item, rowIndex, columnIndex }) | -                                                                                                     |
+
+#### 单选、多级联动、非联动选择 Props
+
+| 参数  | 说明                                                                  | 类型   | 可选值 | 默认值                                            |
+| :---- | :-------------------------------------------------------------------- | :----- | :----- | :------------------------------------------------ |
+| list  | 选择器数据(v1.0.7 单选及非联动多选支持扁平数据:['选项 1', '选项 2']) | Array  | -      | -                                                 |
+| level | 多列联动层级,仅 mode 为 multiSelector 有效                           | Number | -      | 1                                                 |
+| props | 自定义数据字段                                                        | Object | -      | {label:'label',value:'value',children:'children'} |
+
+#### 日期选择 Props
+
+| 参数               | 说明                                                                                                                                                                                                                | 类型    | 可选值     | 默认值                                                                       |
+| :----------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | :------ | :--------- | :--------------------------------------------------------------------------- |
+| display-format     | 日期选择显示的颗粒格式,见下方`displayFormat、format说明`,可自由组合,如`YYYY-MM-DD`,显示的就是选择`年月日`。`重要说明:始终是以-为分隔符,始终是以-为分隔符, 始终是以-为分隔符`                                 | String  | -          | YYYY-MM-DD                                                                   |
+| format             | 选择器返回的日期格式,见下方`displayFormat、format说明`,如配置`YYYY年MM月DD日`选择器确定后返回显示的值为`2021年01月05号`或者`YYYY-MM-DD`返回的就是`2021-01-05`,可以自由组合,需要和`display-format`参数配合使用。 | String  | -          | YYYY-MM-DD                                                                   |
+| start-date         | 开始日期,可精确到秒,如`2018-08-08 08:08:08`                                                                                                                                                                       | String  | -          | -                                                                            |
+| end-date           | 结束日期,可精确到秒,如`2021-08-08 08:08:08`                                                                                                                                                                       | String  | -          | -                                                                            |
+| default-time-limit | 默认显示的日期选择范围,默认当前日期前 20 年和后 20 年,配置`start-date`或`end-date`后失效                                                                                                                          | Number  | -          | 20                                                                           |
+| is-show-chinese    | 是否显示日期选择器年月日时分秒中文文字,默认显示                                                                                                                                                                    | Boolean | true/false | true                                                                         |
+| ch-config          | 显示的日期选择器年月日时分秒文字配置                                                                                                                                                                                | Object  | -          | {year: '年', month: '月', day: '日', hour: '时', minute: '分', second: '秒'} |
+
+### displayFormat、format 说明
+
+| 标识 | 示例  | 描述            |
+| :--- | :---- | :-------------- |
+| YY   | 18    | 年,两位数      |
+| YYYY | 2018  | 年,四位数      |
+| M    | 1-12  | 月,从 1 开始   |
+| MM   | 01-12 | 月,两位数字    |
+| D    | 1-31  | 日              |
+| DD   | 01-31 | 日,两位数      |
+| H    | 0-23  | 24 小时         |
+| HH   | 00-23 | 24 小时,两位数 |
+| h    | 1-12  | 12 小时         |
+| hh   | 01-12 | 12 小时,两位数 |
+| m    | 0-59  | 分钟            |
+| mm   | 00-59 | 分钟,两位数    |
+| s    | 0-59  | 秒              |
+| ss   | 00-59 | 秒,两位数      |
+
+### 方法
+
+| 方法名         | 说明                                   | 参数            | 返回值                                                                                                       |
+| :------------- | :------------------------------------- | :-------------- | :----------------------------------------------------------------------------------------------------------- |
+| show           | 打开选择器                             | -               |                                                                                                              |
+| hide           | 关闭选择器                             | -               |                                                                                                              |
+| getColumnsInfo | (v1.1.0 新增)根据 value 获取选择器信息 | 绑定值的`value` | 同`change` `confirm`回调参数,如果传入的`value`获取不到信息则只返回一个含有`dataset`的对象,具体自行打印查看 |
+
+`getColumnsInfo`注意事项:
+
+- 需要组件加载完成后调用才有效,即`console.log(this.$refs.picker)`打印有内容,否则会报错,可在`onReady`中进行调用。
+- 如果动态设置`list`后马上调用`getColumnsInfo`会无法取到相关信息,可以加个`setTimeout`解决,如下形式:
+
+```javascript
+onReady () {
+  this.list = [{ label: '测试', value: 1 }] // 动态设置一个list
+  setTimeout(() => {
+    const info = that.$refs.picker.getColumnsInfo(xx)
+    console.log(info)
+  }, 0)
+}
+```
+
+### Events
+
+| 事件名称 | 说明                                     | 回调参数                                                                                                                                                                                                                                                                                                                                                         |
+| :------- | :--------------------------------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| show     | 选择器打开时触发                         | -                                                                                                                                                                                                                                                                                                                                                                |
+| hide     | 选择器隐藏时触发                         | -                                                                                                                                                                                                                                                                                                                                                                |
+| change   | 选择器滚动时触发,此时不会改变绑定的值   | `{ index, item, value, change }` `index`触发滚动后新的索引,单选时是具体的索引值,多列联动选择时为数组。`item`触发滚动后新的的完整内容,包括`label`、`value`等,日期选择器则为日期相关内容,单选时为对象,多列选择时为数组对象。`value`触发滚动后新的 value 值,单列选择时为具体值,多列联动选择时为数组。`change`触发事件的类型,详情参考下面的 change 事件备注 |
+| confirm  | 点击选择器确定时触发,此时会改变绑定的值 | 同上`change`事件说明                                                                                                                                                                                                                                                                                                                                             |
+| cancel   | 点击选择器取消时触发                     | 同上`change`事件说明                                                                                                                                                                                                                                                                                                                                             |
+
+### `change` 事件备注
+
+如果绑定的值是空的,`change`触发后里面的内容都是列表的第一项。  
+`change`事件会在以下情况触发:
+
+- 初始化
+- 绑定值 value 变化
+- 选择器 list 列表变化
+- 滚动选择器
+
+以上情况会在回调函数中都可以取到`change`变化的类型,对应上面的情况包括以下:
+
+- `init`
+- `value`
+- `list`
+- `scroll`
+
+根据这些类型大家可以在`change`的时候按需处理自己的业务逻辑,`init`现在指挥在调用选择器弹出的时候触发。  
+下面的说明情况已失效,如需要在页面显示的时候根据`value`的值显示相应的中文,调用`v1.10`新增的方法`getColumnsInfo`,传入绑定的值即可获取到你想要的所有信息。  
+~~比如一种常见的情况,有默认值的时候需要显示默认值的文字,此时可以`change`事件中判断`change`的类型是否是`init`,如果是的话可以取事件回调中的`item`进行显示绑定值对应的文字信息。~~
+
+```javascript
+handleChange (e) {
+  if (e.change === 'init') {
+    console.log(e.item.label) // 单选 选项1
+    console.log(e.item.map(item => item.label).join('-')) // 多选 选项1-选项11
+  }
+}
+```
+
+### 插槽
+
+| 插槽名        | 说明                   |
+| :------------ | :--------------------- |
+| cancel-text   | 选择器取消文字插槽     |
+| action-center | 选择器顶部中间插槽     |
+| confirm-text  | 选择器确定文字插槽     |
+| loading       | 选择器 loading 插槽    |
+| empty         | 选择器 空数据 插槽     |
+| header-top    | 选择器头部顶部插槽     |
+| header-bottom | 选择器头部底部插槽     |
+| picker-top    | 选择器滚动部分顶部插槽 |
+| picker-bottom | 选择器滚动部分底部插槽 |
+
+### 选择器自定义样式
+
+> nvue 专属写法,需要定义`column-style`和`active-column-style`,写法如下:
+
+```html
+<lb-picker
+  :column-style="columnStyle"
+  :active-column-style="activeColumnStyle"
+></lb-picker>
+```
+
+```javascript
+data () {
+  return {
+    // 默认样式
+    columnStyle: {
+      color: '#f0ad4e'
+    },
+    // 选择样式
+    activeColumnStyle: {
+      color: '#007aff',
+      fontWeight: 700
+    }
+  }
+}
+```
+
+> 其他端写法,覆盖默认样式即可。
+
+```css
+<style lang="scss" scoped>
+/deep/ .lb-picker {
+  .lb-picker-column-label {
+    color: #f0ad4e;
+  }
+  .lb-picker-column-active {
+    .lb-picker-column-label {
+      color: #007aff;
+      font-weight: 700;
+    }
+  }
+}
+</style>
+```
+
+完整代码可以参考`demo9`。
+
+### 获取选中值的文字
+
+`@confirm`事件中可以拿到:
+
+单选:
+
+```javascript
+handleConfirm (e) {
+  console.log(e.item.label) // 选项1
+}
+```
+
+联动选择:
+
+```javascript
+handleConfirm (e) {
+  console.log(e.item.map(item => item.label).join('-')) // 选项1-选项11
+}
+```
+
+## Tips
+
+微信小程序端,滚动时在 iOS 自带振动反馈,可在系统设置 -> 声音与触感 -> 系统触感反馈中关闭
+
+## 其他
+
+其他功能参考示例 Demo 代码。

파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 87 - 0
components/lb-picker/index.vue


파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 0 - 0
components/lb-picker/lib/custom-parse-format.min.js


파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 0 - 0
components/lb-picker/lib/dayjs.min.js


+ 1 - 0
components/lb-picker/lib/object-support.min.js

@@ -0,0 +1 @@
+!function(t,n){"object"==typeof exports&&"undefined"!=typeof module?module.exports=n():"function"==typeof define&&define.amd?define(n):t.dayjs_plugin_objectSupport=n()}(this,function(){"use strict";return function(t,n,e){var i=n.prototype,r=function(t){var n,r=t.date,o=t.utc,a={};if(!((n=r)instanceof Date)&&!(n instanceof Array)&&n instanceof Object){if(!Object.keys(r).length)return new Date;var u=o?e.utc():e();Object.keys(r).forEach(function(t){var n,e;a[(n=t,e=i.$utils().p(n),"date"===e?"day":e)]=r[t]});var c=a.day||(a.year||a.month>=0?1:u.date()),d=a.year||u.year(),f=a.month>=0?a.month:a.year||a.day?0:u.month(),s=a.hour||0,h=a.minute||0,b=a.second||0,y=a.millisecond||0;return o?new Date(Date.UTC(d,f,c,s,h,b,y)):new Date(d,f,c,s,h,b,y)}return r},o=i.parse;i.parse=function(t){t.date=r.bind(this)(t),o.bind(this)(t)};var a=i.set,u=i.add,c=function(t,n,e,i){if(void 0===i&&(i=1),n instanceof Object){var r=this;return Object.keys(n).forEach(function(e){r=t.bind(r)(n[e]*i,e)}),r}return t.bind(this)(n*i,e)};i.set=function(t,n){return n=void 0===n?t:n,c.bind(this)(function(t,n){return a.bind(this)(n,t)},n,t)},i.add=function(t,n){return c.bind(this)(u,t,n)},i.subtract=function(t,n){return c.bind(this)(u,t,n,-1)}}});

+ 93 - 0
components/lb-picker/mixins/index.js

@@ -0,0 +1,93 @@
+import { getColumns, isObject, isFunction } from '../utils'
+export const commonMixin = {
+  data () {
+    return {
+      isConfirmChange: false,
+      indicatorStyle: `height: 34px`,
+      pressTimeout: null
+    }
+  },
+  created () {
+    this.init('init')
+  },
+  methods: {
+    init (changeType) {
+      if (this.list && this.list.length) {
+        const column = getColumns({
+          value: this.value,
+          list: this.list,
+          mode: this.mode,
+          props: this.props,
+          level: this.level
+        })
+        const { columns, value, item, index } = column
+        this.selectValue = value
+        this.selectItem = item
+        this.pickerColumns = columns
+        this.pickerValue = index
+        this.$emit('change', {
+          value: this.selectValue,
+          item: this.selectItem,
+          index: this.pickerValue,
+          change: changeType
+        })
+      }
+    },
+    touchstart (e) {
+      if (!this.pressEnable) return
+      clearTimeout(this.pressTimeout)
+      this.pressTimeout = setTimeout(() => {
+        let item = {}
+        let toastTitle = ''
+        // #ifdef APP-NVUE
+        item = e.target.dataset.item
+        // #endif
+
+        // #ifdef H5
+        item = JSON.parse(e.currentTarget.dataset.item)
+        // #endif
+
+        // #ifndef APP-NVUE || H5
+        item = e.currentTarget.dataset.item
+        // #endif
+
+        // #ifdef APP-PLUS || H5
+        toastTitle = this.getLabel(item)
+        // #endif
+
+        // #ifndef APP-PLUS || H5
+        toastTitle = item[this.props.label] || item
+        // #endif
+        uni.showToast({
+          title: toastTitle,
+          icon: 'none'
+        })
+      }, this.pressTime)
+    },
+    touchmove () {
+      if (!this.pressEnable) return
+      clearTimeout(this.pressTimeout)
+    },
+    touchend () {
+      if (!this.pressEnable) return
+      clearTimeout(this.pressTimeout)
+    },
+    getLabel (item, rowIndex, columnIndex) {
+      if (this.formatter && isFunction(this.formatter)) {
+        return this.formatter({ item, rowIndex, columnIndex })
+      } else {
+        return item[this.props.label] || item
+      }
+    }
+  },
+  watch: {
+    value () {
+      if (!this.isConfirmChange) {
+        this.init('value')
+      }
+    },
+    list () {
+      this.init('list')
+    }
+  }
+}

+ 378 - 0
components/lb-picker/pickers/date-selector-picker.vue

@@ -0,0 +1,378 @@
+<template>
+  <view class="lb-selector-picker lb-picker-item"
+    :style="{ height: height }">
+    <picker-view :value="pickerValue"
+      :style="{ height: height }"
+      :indicator-style="indicatorStyle"
+      @change="handleChange">
+      <picker-view-column v-for="(column, index) in pickerColumns"
+        :key="column.name">
+        <view v-for="item in column.list || []"
+          :class="[
+            'lb-picker-column',
+            item.value === selectValue[index]
+              ? 'lb-picker-column-active'
+              : ''
+          ]"
+          :key="item.value">
+          <!-- #ifdef APP-PLUS || H5 -->
+          <text :class="[
+              'lb-picker-column-label',
+              `lb-picker-column-label-${align}`
+            ]"
+            :style="[
+              item.value === selectValue[index]
+                ? activeColumnStyle
+                : columnStyle
+            ]">{{ item.label }}</text>
+          <!-- #endif -->
+
+          <!-- #ifndef APP-PLUS || H5 -->
+          <text :class="[
+              'lb-picker-column-label',
+              `lb-picker-column-label-${align}`
+            ]">{{ item.label }}</text>
+          <!-- #endif -->
+        </view>
+      </picker-view-column>
+    </picker-view>
+  </view>
+</template>
+
+<script>
+import { isFunction } from '../utils'
+const INVALID_DATE = 'Invalid Date'
+const dayjs = require('../lib/dayjs.min.js')
+const objectSupport = require('../lib/object-support.min.js')
+const customParseFormat = require('../lib/custom-parse-format.min.js')
+dayjs.extend(objectSupport)
+dayjs.extend(customParseFormat)
+export default {
+  props: {
+    value: String,
+    mode: String,
+    visible: Boolean,
+    height: String,
+    columnStyle: Object,
+    activeColumnStyle: Object,
+    align: String,
+    formatter: Function,
+    format: String,
+    displayFormat: String,
+    startDate: String,
+    endDate: String,
+    defaultTimeLimit: Number,
+    isShowChinese: Boolean,
+    chConfig: Object,
+    filter: Function
+  },
+  data () {
+    return {
+      pickerValue: [],
+      pickerColumns: [],
+      selectValue: [],
+      selectItem: null,
+      isConfirmChange: false,
+      indicatorStyle: `height: 34px`,
+      dayjs: dayjs,
+      startInfo: {},
+      endInfo: {}
+    }
+  },
+  created () {
+    this.init('init')
+  },
+  methods: {
+    init (changeType) {
+      this.startInfo = this.toObject(
+        this.startDate
+          ? this.startDate
+          : this.dayjs().subtract(this.defaultTimeLimit, 'year').$d
+      )
+      this.endInfo = this.toObject(
+        this.endDate
+          ? this.endDate
+          : this.dayjs().add(this.defaultTimeLimit, 'year').$d
+      )
+      this.selectDate = this.value
+        ? this.dayjs(this.value, this.format)
+        : new Date()
+      if (!this.validate('date')) {
+        throw new Error('日期格式不合法')
+      }
+      if (!this.validate('displayFormat')) {
+        throw new Error('display-format参数异常')
+      }
+      if (this.startInfo.timestamp > this.endInfo.timestamp) {
+        throw new Error('开始结束日期异常,startDate不得大于endDate')
+      }
+      this.selectItem = this.toObject(this.selectDate)
+      this.setColumnData()
+      const value = this.getValueDate()
+      this.$emit('change', {
+        value: value.format(this.format),
+        valueArr: this.selectValue,
+        item: this.selectItem,
+        index: this.pickerValue,
+        change: changeType
+      })
+    },
+    handleChange (item) {
+      const pickerValue = item.detail.value
+      const columnIndex = pickerValue.findIndex(
+        (item, i) => item !== this.pickerValue[i]
+      )
+      if (columnIndex > -1) {
+        const valueIndex = pickerValue[columnIndex]
+        const columnItem = this.pickerColumns[columnIndex]
+        const columnName = columnItem.name
+        const valueItem = columnItem.list[valueIndex]
+        this.pickerValue = pickerValue
+        this.$set(this.selectValue, columnIndex, valueItem.value)
+        this.$set(this.selectItem, columnName, valueItem.value)
+        this.setColumnData(columnIndex)
+        const value = this.getValueDate()
+        this.$emit('change', {
+          value: value.format(this.format),
+          valueArr: this.selectValue,
+          item: this.selectItem,
+          index: this.pickerValue,
+          change: 'scroll'
+        })
+      }
+    },
+    getLabel (value, name, format, $d, rowIndex, columnIndex) {
+      const ch = this.isShowChinese ? this.chConfig[name] || '' : ''
+      let label =
+        value < 10 && format.length > 1 ? `0${value}${ch}` : value + ch
+      if (this.formatter && isFunction(this.formatter)) {
+        const item = { name, format, value, $d }
+        label = this.formatter({ item, rowIndex, columnIndex }) || label
+      }
+      return label
+    },
+    getValueDate (dateObj = {}) {
+      let selectItem = {
+        ...this.selectItem,
+        ...dateObj
+      }
+      selectItem.month = selectItem.month - 1
+      return this.dayjs(selectItem)
+    },
+    setColumnData (n = 0) {
+      const formatArr = this.displayFormat.split('-')
+      const formatObj = {
+        YY: 'year',
+        YYYY: 'year',
+        M: 'month',
+        MM: 'month',
+        D: 'day',
+        DD: 'day',
+        h: 'hour',
+        HH: 'hour',
+        h: 'hour',
+        hh: 'hour',
+        m: 'minute',
+        mm: 'minute',
+        s: 'second',
+        ss: 'second'
+      }
+      formatArr.forEach((item, index) => {
+        if (index >= n) {
+          const name = formatObj[item]
+          const obj = {
+            name: name,
+            list: this.getColumnData(name, item, index)
+          }
+          let value = this.selectItem[name]
+          if (index !== n) {
+            this.$set(this.pickerColumns, index, obj)
+          }
+          let n = obj.list.findIndex(l => l.value === value)
+          if (n < 0) {
+            const l = obj.list.length - 1
+            const firstValue = obj.list[0].value
+            const lastValue = obj.list[l].value
+            if (value < firstValue) {
+              n = 0
+              value = firstValue
+            }
+            if (value > lastValue) {
+              n = l
+              value = lastValue
+            }
+            if (n < 0) {
+              n = 0
+              value = firstValue
+            }
+          }
+          this.$set(this.pickerValue, index, n)
+          this.$set(this.selectValue, index, value)
+          this.$set(this.selectItem, name, value)
+        }
+      })
+    },
+    isSame (name, type = 'startInfo') {
+      let same = true
+      const arr = ['year', 'month', 'day', 'hour', 'minute', 'second']
+      const index = arr.findIndex(item => item === name)
+      if (index > -1) {
+        const slice = arr.slice(0, index + 1)
+        for (let i = 0; i < slice.length; i++) {
+          same = same && this.selectItem[slice[i]] === this[type][slice[i]]
+        }
+      }
+      return same
+    },
+    getColumnData (name, format, index) {
+      let list = []
+      let start = 0
+      let end = 0
+      let n = 0
+      const obj = {
+        month: 'year',
+        day: 'month',
+        hour: 'day',
+        minute: 'hour',
+        second: 'minute'
+      }
+      switch (name) {
+        case 'year':
+          start = this.startInfo[name]
+          end = this.endInfo[name]
+          break
+        case 'month':
+          start = 1
+          end = 12
+          break
+        case 'day':
+          start = 1
+          end = new Date(
+            this.selectItem.year,
+            this.selectItem.month,
+            0
+          ).getDate()
+          break
+        case 'hour':
+          start = 0
+          end = 23
+          break
+        case 'minute':
+          start = 0
+          end = 59
+          break
+        case 'second':
+          start = 0
+          end = 59
+          break
+      }
+      if (this.isSame(obj[name], 'startInfo')) {
+        start = this.startInfo[name]
+      }
+      if (this.isSame(obj[name], 'endInfo')) {
+        end = this.endInfo[name]
+      }
+      for (let i = start; i <= end; i++) {
+        n++
+        list.push({
+          label: this.getLabel(
+            i,
+            name,
+            format,
+            this.getValueDate({ [name]: i }),
+            n,
+            index
+          ),
+          value: i
+        })
+      }
+      if (this.filter && isFunction(this.filter)) {
+        list = this.filter(name, list) || list
+      }
+      return list
+    },
+    validate (type) {
+      let valid = true
+      switch (type) {
+        case 'date':
+          valid = this.dayjs(this.selectDate).isValid()
+          break
+        case 'displayFormat':
+          if (this[type]) {
+            const arr = [
+              'YY',
+              'YYYY',
+              'M',
+              'MM',
+              'D',
+              'DD',
+              'H',
+              'HH',
+              'h',
+              'hh',
+              'm',
+              'mm',
+              's',
+              'ss'
+            ]
+            const formatArr = this.displayFormat.split('-')
+            for (let i = 0; i < formatArr.length; i++) {
+              const val = formatArr[i]
+              const isIn = arr.includes(val)
+              if (!isIn) {
+                valid = false
+                break
+              }
+            }
+          } else {
+            valid = false
+          }
+          break
+      }
+      return valid
+    },
+    toObject (val) {
+      const d = this.dayjs(val)
+      return {
+        year: d.$y,
+        month: d.$M + 1,
+        day: d.$D,
+        hour: d.$H,
+        minute: d.$m,
+        second: d.$s,
+        timestamp: d.valueOf(),
+        $d: d
+      }
+    }
+  },
+  watch: {
+    value () {
+      if (!this.isConfirmChange) {
+        this.init('value')
+      }
+    },
+    displayFormat () {
+      this.init('displayFormat')
+    },
+    startDate () {
+      this.init('startDate')
+    },
+    endDate () {
+      this.init('endDate')
+    },
+    defaultTimeLimit () {
+      this.init('defaultTimeLimit')
+    },
+    isShowChinese () {
+      this.init('isShowChinese')
+    },
+    chConfig () {
+      this.init('chConfig')
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+@import "../style/picker-item.scss";
+</style>

+ 135 - 0
components/lb-picker/pickers/multi-selector-picker.vue

@@ -0,0 +1,135 @@
+<template>
+  <view class="lb-multi-selector lb-picker-item"
+    :style="{ height: height }">
+    <picker-view :value="pickerValue"
+      :indicator-style="indicatorStyle"
+      :style="{ height: height }"
+      @change="handleChange">
+      <picker-view-column v-for="(column, index) in pickerColumns"
+        :key="index">
+        <!-- #ifdef H5 -->
+        <view v-for="(item, i) in column || []"
+          :class="[
+            'lb-picker-column',
+            item[props.value] === selectValue[index]
+              ? 'lb-picker-column-active'
+              : ''
+          ]"
+          :key="i"
+          :data-item="pressEnable ? JSON.stringify(item) : ''"
+          @touchstart="touchstart"
+          @touchmove="touchmove"
+          @touchend="touchend">
+          <!-- #endif -->
+          <!-- #ifndef H5 -->
+          <view v-for="(item, i) in column || []"
+            :class="[
+            'lb-picker-column',
+            item[props.value] === selectValue[index]
+              ? 'lb-picker-column-active'
+              : ''
+          ]"
+            :key="i"
+            :data-item="item"
+            @touchstart="touchstart"
+            @touchmove="touchmove"
+            @touchend="touchend">
+            <!-- #endif -->
+            <!-- #ifdef APP-PLUS || H5 -->
+            <text :class="[
+              'lb-picker-column-label',
+              `lb-picker-column-label-${align}`
+            ]"
+              :style="[
+              item[props.value] === selectValue[index]
+              ? activeColumnStyle
+              : columnStyle
+            ]">{{ getLabel(item, i, index) }}</text>
+            <!-- #endif -->
+
+            <!-- #ifndef APP-PLUS || H5 -->
+            <text :class="[
+              'lb-picker-column-label',
+              `lb-picker-column-label-${align}`
+            ]">{{ item[props.label] || item }}</text>
+            <!-- #endif -->
+          </view>
+      </picker-view-column>
+    </picker-view>
+  </view>
+</template>
+
+<script>
+import { commonMixin } from '../mixins'
+export default {
+  props: {
+    value: Array,
+    list: Array,
+    mode: String,
+    props: Object,
+    level: Number,
+    visible: Boolean,
+    height: String,
+    columnStyle: Object,
+    activeColumnStyle: Object,
+    align: String,
+    pressEnable: Boolean,
+    pressTime: Number,
+    formatter: Function
+  },
+  mixins: [commonMixin],
+  data () {
+    return {
+      pickerValue: [],
+      pickerColumns: [],
+      selectValue: [],
+      selectItem: []
+    }
+  },
+  methods: {
+    handleChange (item) {
+      const pickerValue = item.detail.value
+      const columnIndex = pickerValue.findIndex(
+        (item, i) => item !== this.pickerValue[i]
+      )
+      const valueIndex = pickerValue[columnIndex]
+      this.setPickerChange(pickerValue, valueIndex, columnIndex)
+    },
+    setPickerChange (pickerValue, valueIndex, columnIndex) {
+      for (let i = 0; i < this.level; i++) {
+        if (i > columnIndex) {
+          pickerValue[i] = 0
+          const column =
+            this.pickerColumns[i - 1][valueIndex] ||
+            this.pickerColumns[i - 1][0]
+          this.$set(this.pickerColumns, i, column[this.props.children] || [])
+          valueIndex = 0
+        }
+        this.$set(this.pickerValue, i, pickerValue[i])
+        const selectItem = this.pickerColumns[i][pickerValue[i]]
+        if (selectItem) {
+          this.selectItem[i] = selectItem
+          this.selectValue[i] = selectItem[this.props.value]
+        } else {
+          const spliceNum = this.level - i
+          this.pickerValue.splice(i, spliceNum)
+          this.selectValue.splice(i, spliceNum)
+          this.selectItem.splice(i, spliceNum)
+          this.pickerColumns.splice(i, spliceNum)
+          break
+        }
+      }
+      this.$emit('change', {
+        value: this.selectValue,
+        item: this.selectItem,
+        index: this.pickerValue,
+        change: 'scroll'
+      })
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+@import "../style/picker-item.scss";
+</style>

+ 108 - 0
components/lb-picker/pickers/selector-picker.vue

@@ -0,0 +1,108 @@
+<template>
+  <view class="lb-selector-picker lb-picker-item"
+    :style="{ height: height }">
+    <picker-view :value="pickerValue"
+      :style="{ height: height }"
+      :indicator-style="indicatorStyle"
+      @change="handleChange">
+      <picker-view-column>
+        <!-- #ifdef H5 -->
+        <view v-for="(item, i) in list"
+          :class="[
+            'lb-picker-column',
+            (item[props.value] || item) === selectValue
+              ? 'lb-picker-column-active'
+              : ''
+          ]"
+          :key="i"
+          :data-item="pressEnable ? JSON.stringify(item) : ''"
+          @touchstart="touchstart"
+          @touchmove="touchmove"
+          @touchend="touchend">
+          <!-- #endif -->
+          <!-- #ifndef H5 -->
+          <view v-for="(item, i) in list"
+            :class="[
+            'lb-picker-column',
+            (item[props.value] || item) === selectValue
+              ? 'lb-picker-column-active'
+              : ''
+          ]"
+            :key="i"
+            :data-item="item"
+            @touchstart="touchstart"
+            @touchmove="touchmove"
+            @touchend="touchend">
+            <!-- #endif -->
+            <!-- #ifdef APP-PLUS || H5 -->
+            <text :class="[
+              'lb-picker-column-label',
+              `lb-picker-column-label-${align}`
+            ]"
+              :style="[
+              (item[props.value] || item) === selectValue
+                ? activeColumnStyle
+                : columnStyle
+            ]">{{ getLabel(item.title, i, 0) }}</text>
+            <!-- #endif -->
+
+            <!-- #ifndef APP-PLUS || H5 -->
+            <text :class="[
+              'lb-picker-column-label',
+              `lb-picker-column-label-${align}`
+            ]">{{ item[props.label] || item }}</text>
+            <!-- #endif -->
+          </view>
+      </picker-view-column>
+    </picker-view>
+  </view>
+</template>
+
+<script>
+import { isObject } from '../utils'
+import { commonMixin } from '../mixins'
+export default {
+  props: {
+    value: [String, Number],
+    list: Array,
+    mode: String,
+    props: Object,
+    visible: Boolean,
+    height: String,
+    columnStyle: Object,
+    activeColumnStyle: Object,
+    align: String,
+    pressEnable: Boolean,
+    pressTime: Number,
+    formatter: Function
+  },
+  mixins: [commonMixin],
+  data () {
+    return {
+      pickerValue: [],
+      selectValue: '',
+      selectItem: null
+    }
+  },
+  methods: {
+    handleChange (item) {
+      const index = item.detail.value[0] || 0
+      this.selectItem = this.list[index]
+      this.selectValue = isObject(this.selectItem)
+        ? this.selectItem[this.props.value]
+        : this.selectItem
+      this.pickerValue = item.detail.value
+      this.$emit('change', {
+        value: this.selectValue,
+        item: this.selectItem,
+        index: index,
+        change: 'scroll'
+      })
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+@import "../style/picker-item.scss";
+</style>

+ 116 - 0
components/lb-picker/pickers/unlinked-selector-picker.vue

@@ -0,0 +1,116 @@
+<template>
+  <view class="lb-selector-picker lb-picker-item"
+    :style="{ height: height }">
+    <picker-view :value="pickerValue"
+      :indicator-style="indicatorStyle"
+      :style="{ height: height }"
+      @change="handleChange">
+      <picker-view-column v-for="(column, index) in pickerColumns"
+        :key="index">
+        <!-- #ifdef H5 -->
+        <view v-for="(item, i) in column || []"
+          :class="[
+            'lb-picker-column',
+            (item[props.value] || item) === selectValue[index]
+              ? 'lb-picker-column-active'
+              : ''
+          ]"
+          :key="i"
+          :data-item="pressEnable ? JSON.stringify(item) : ''"
+          @touchstart="touchstart"
+          @touchmove="touchmove"
+          @touchend="touchend">
+          <!-- #endif -->
+          <!-- #ifndef H5 -->
+          <view v-for="(item, i) in column || []"
+            :class="[
+            'lb-picker-column',
+            (item[props.value] || item) === selectValue[index]
+              ? 'lb-picker-column-active'
+              : ''
+          ]"
+            :key="i"
+            :data-item="item"
+            @touchstart="touchstart"
+            @touchmove="touchmove"
+            @touchend="touchend">
+            <!-- #endif -->
+            <!-- #ifdef APP-PLUS || H5 -->
+            <text :class="[
+              'lb-picker-column-label',
+              `lb-picker-column-label-${align}`
+            ]"
+              :style="[
+              (item[props.value] || item) === selectValue[index]
+              ? activeColumnStyle
+              : columnStyle
+            ]">{{ getLabel(item, i, index) }}</text>
+            <!-- #endif -->
+
+            <!-- #ifndef APP-PLUS || H5 -->
+            <text :class="[
+              'lb-picker-column-label',
+              `lb-picker-column-label-${align}`
+            ]">{{ item[props.label] || item }}</text>
+            <!-- #endif -->
+          </view>
+      </picker-view-column>
+    </picker-view>
+  </view>
+</template>
+
+<script>
+import { isObject } from '../utils'
+import { commonMixin } from '../mixins'
+export default {
+  props: {
+    value: Array,
+    list: Array,
+    mode: String,
+    props: Object,
+    visible: Boolean,
+    height: String,
+    columnStyle: Object,
+    activeColumnStyle: Object,
+    align: String,
+    pressEnable: Boolean,
+    pressTime: Number,
+    formatter: Function
+  },
+  mixins: [commonMixin],
+  data () {
+    return {
+      pickerValue: [],
+      pickerColumns: [],
+      selectValue: [],
+      selectItem: []
+    }
+  },
+  methods: {
+    handleChange (item) {
+      const pickerValue = item.detail.value
+      const columnIndex = pickerValue.findIndex((item, i) => item !== this.pickerValue[i])
+      if (columnIndex > -1) {
+        const valueIndex = pickerValue[columnIndex]
+        const columnItem = this.list[columnIndex][valueIndex]
+        const valueItem = isObject(columnItem)
+          ? columnItem[this.props.value]
+          : columnItem
+        this.pickerValue = pickerValue
+        this.$set(this.selectValue, columnIndex, valueItem)
+        this.$set(this.selectItem, columnIndex, columnItem)
+        this.$emit('change', {
+          value: this.selectValue,
+          item: this.selectItem,
+          index: this.pickerValue,
+          change: 'scroll'
+        })
+      }
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+@import "../style/picker-item.scss";
+</style>

+ 40 - 0
components/lb-picker/style/picker-item.scss

@@ -0,0 +1,40 @@
+.lb-picker-column {
+  height: 34px;
+  padding: 0 10px;
+  /* #ifndef APP-NVUE */
+  display: flex;
+  box-sizing: border-box;
+  white-space: nowrap;
+  overflow: hidden;
+  /* #endif */
+  flex-direction: row;
+  align-items: center;
+}
+
+.lb-picker-column-label {
+  font-size: 16px;
+  text-align: center;
+  flex: 1;
+  /* #ifdef APP-NVUE */
+  lines: 1;
+  /* #endif */
+  text-overflow: ellipsis;
+  transition-property: color;
+  transition-duration: 0.3s;
+  /* #ifndef APP-NVUE */
+  overflow: hidden;
+  white-space: nowrap;
+  /* #endif */
+}
+
+.lb-picker-column-label-left {
+  text-align: left;
+}
+
+.lb-picker-column-label-center {
+  text-align: center;
+}
+
+.lb-picker-column-label-right {
+  text-align: right;
+}

+ 166 - 0
components/lb-picker/style/picker.scss

@@ -0,0 +1,166 @@
+.lb-picker {
+	position: relative;
+}
+
+.lb-picker-mask {
+	background-color: rgba(0, 0, 0, 0.0);
+	position: fixed;
+	top: 0;
+	right: 0;
+	left: 0;
+	bottom: 0;
+}
+
+.lb-picker-mask-animation {
+	transition-property: background-color;
+	transition-duration: 0.3s;
+}
+
+.lb-picker-container {
+	position: relative;
+}
+
+.lb-picker-container-fixed {
+	position: fixed;
+	left: 0;
+	right: 0;
+	bottom: 0;
+	transform: translateY(100%);
+	/* #ifndef APP-NVUE */
+	overflow: hidden;
+	/* #endif */
+}
+
+/* #ifndef APP-NVUE */
+.lb-picker-container-animation {
+	transition-property: transform;
+	transition-duration: 0.3s;
+}
+
+.lb-picker-container-show {
+	transform: translateY(0);
+}
+
+/* #endif */
+
+.lb-picker-header {
+	position: relative;
+	background-color: #fff;
+	/* #ifdef APP-NVUE */
+	border-bottom-width: 1px;
+	border-bottom-style: solid;
+	border-bottom-color: #e5e5e5;
+	border-top-width: 1px;
+	border-top-style: solid;
+	border-top-color: #e5e5e5;
+	/* #endif */
+	/* #ifndef APP-NVUE */
+	box-sizing: border-box;
+	/* #endif */
+
+}
+
+/* #ifndef APP-NVUE */
+
+.lb-picker-header::after {
+	content: "";
+	position: absolute;
+	left: 0;
+	bottom: 0;
+	right: 0;
+	height: 1px;
+	clear: both;
+	border-bottom: 1px solid #e5e5e5;
+	color: #e5e5e5;
+	transform-origin: 0 100%;
+	transform: scaleY(0.5);
+}
+
+/* #endif */
+
+.lb-picker-header-actions {
+	height: 45px;
+	/* #ifndef APP-NVUE */
+	box-sizing: border-box;
+	display: flex;
+	/* #endif */
+	flex-direction: row;
+	justify-content: space-between;
+	flex-wrap: nowrap;
+}
+
+.lb-picker-action {
+	padding-left: 10px;
+	padding-right: 10px;
+	/* #ifndef APP-NVUE */
+	display: flex;
+	/* #endif */
+	flex-direction: row;
+	align-items: center;
+	justify-content: center;
+}
+
+.lb-picker-action-cancel-text {
+	font-size: 16px;
+}
+
+.lb-picker-action-confirm-text {
+	font-size: 16px;
+}
+
+.lb-picker-content {
+	position: relative;
+	background-color: #fff;
+}
+
+/* #ifndef APP-NVUE */
+.lb-picker-content-safe-buttom {
+	padding-bottom: 0;
+	padding-bottom: constant(safe-area-inset-bottom);
+	padding-bottom: env(safe-area-inset-bottom);
+}
+
+/* #endif */
+
+.lb-picker-content-main {
+	position: relative;
+	/* #ifndef APP-NVUE */
+	display: flex;
+	/* #endif */
+	justify-content: center;
+	flex-direction: column;
+}
+
+.lb-picker-loading,
+.lb-picker-empty {
+	/* #ifndef APP-NVUE */
+	display: flex;
+	/* #endif */
+	justify-content: center;
+	align-items: center;
+}
+
+.lb-picker-empty-text {
+	font-size: 16px;
+}
+
+.lb-picker-loading-img {
+	width: 25px;
+	height: 25px;
+	/* #ifndef APP-NVUE */
+	animation: rotating 2s linear infinite;
+	/* #endif */
+}
+
+/* #ifndef APP-NVUE */
+@keyframes rotating {
+	0% {
+		transform: rotate(0deg)
+	}
+
+	100% {
+		transform: rotate(1turn)
+	}
+}
+
+/* #endif */

+ 121 - 0
components/lb-picker/utils.js

@@ -0,0 +1,121 @@
+/**
+ * 判断是否是对象
+ *
+ * @export
+ * @param {*} val
+ * @returns true/false
+ */
+export function isObject (val) {
+  return Object.prototype.toString.call(val) === '[object Object]'
+}
+
+/**
+ * 判断是否是Function
+ *
+ * @export
+ * @param {*} val
+ * @returns true/false
+ */
+export function isFunction (val) {
+  return Object.prototype.toString.call(val) === '[object Function]'
+}
+
+/**
+ * 根据value获取columns信息
+ *
+ * @export
+ * @param {*} { value, list, mode, props, level }
+ * @param {number} [type=2] 查询不到value数据返回数据类型 1空值null 2默认第一个选项
+ * @returns
+ */
+export function getColumns ({ value, list, mode, props, level }, type = 2) {
+  let pickerValue = []
+  let pickerColumns = []
+  let selectValue = []
+  let selectItem = []
+  let columnsInfo = null
+  switch (mode) {
+    case 'selector':
+      let index = list.findIndex(item => {
+        return isObject(item) ? item[props.value] === value : item === value
+      })
+      if (index === -1 && type === 1) {
+        columnsInfo = null
+      } else {
+        index = index > -1 ? index : 0
+        selectItem = list[index]
+        selectValue = isObject(selectItem)
+          ? selectItem[props.value]
+          : selectItem
+        pickerColumns = list
+        pickerValue = [index]
+        columnsInfo = {
+          index: pickerValue,
+          value: selectValue,
+          item: selectItem,
+          columns: pickerColumns
+        }
+      }
+      break
+    case 'multiSelector':
+      const setPickerItems = (data = [], index = 0) => {
+        if (!data.length) return
+        const defaultValue = value || []
+        if (index < level) {
+          const value = defaultValue[index] || ''
+          let i = data.findIndex(item => item[props.value] === value)
+          if (i === -1 && type === 1) return
+          i = i > -1 ? i : 0
+          pickerValue[index] = i
+          pickerColumns[index] = data
+          if (data[i]) {
+            selectValue[index] = data[i][props.value]
+            selectItem[index] = data[i]
+            setPickerItems(data[i][props.children] || [], index + 1)
+          }
+        }
+      }
+      setPickerItems(list)
+      if (!selectValue.length && type === 1) {
+        columnsInfo = null
+      } else {
+        columnsInfo = {
+          index: pickerValue,
+          value: selectValue,
+          item: selectItem,
+          columns: pickerColumns
+        }
+      }
+      break
+    case 'unlinkedSelector':
+      list.forEach((item, i) => {
+        let index = item.findIndex(item => {
+          return isObject(item)
+            ? item[props.value] === value[i]
+            : item === value[i]
+        })
+        if (index === -1 && type === 1) return
+        index = index > -1 ? index : 0
+        const columnItem = list[i][index]
+        const valueItem = isObject(columnItem)
+          ? columnItem[props.value]
+          : columnItem
+        pickerValue[i] = index
+        selectValue[i] = valueItem
+        selectItem[i] = columnItem
+      })
+      pickerColumns = list
+      if (!selectValue.length && type === 1) {
+        columnsInfo = null
+      } else {
+        columnsInfo = {
+          index: pickerValue,
+          value: selectValue,
+          item: selectItem,
+          columns: pickerColumns
+        }
+      }
+      break
+  }
+  return columnsInfo
+}

+ 216 - 0
components/select.vue

@@ -0,0 +1,216 @@
+<template>
+	<view class="easy-select" @click.stop="trigger" :style="[easySelectSize]">
+		<input type="text" v-model="value" :placeholder="placeholder" disabled clearable>
+		<!-- <view class="easy-select-suffix" :style="{border: '1px solid rgba(0,0,0,0)'}" :class="[showSuffix]">
+			<view class="easy-select-down-tag"></view>
+		</view> -->
+		<view class="easy-select-options" v-if="showOptions" :style="{'min-width': boundingClientRect.width + 'px', top: optionsGroupTop, margin: optionsGroupMargin}">
+			<view class="easy-select-options-item" v-for="item in options" :key="item.code" @click.stop="select(item)" :class="{active: currentSelect.name === item.name}">
+				<text>{{item.name}}</text>
+			</view>
+		</view>
+	</view>
+</template>
+
+<script>
+	/**
+	 * easy-select
+	 * @author Snoop zhang
+	 * @description Select Component
+	 * */
+	const COMPONENT_NAME = 'easy-select'
+	const MAX_OPTIONS_HEIGHT = 137 // 修改务必也修改easy-select-options的css部分
+	const OPTIONS_ITEM_HEIGHT = 33 // 修改务必也修改easy-select-options-item的css部分
+	const OPTIONS_MARGIN = 10
+	const OPTIONS_PADDING = 6 * 2 + 2 // + 2是border
+	const OPTIONS_OTHER_HEIGHT = OPTIONS_MARGIN + OPTIONS_PADDING
+	const STORAGE_KEY = '_easyWindowHeight'
+	const SIZE = {
+		'medium': {
+			width: '150px',
+			height: '40px'
+		},
+		'small': {
+			width: '200px',
+			height: '30px'
+		},
+		'mini': {
+			width: '160px',
+			height: '30px'
+		}
+	}
+	
+	export default {
+		name: COMPONENT_NAME,
+		props: {
+			windowHeight: {
+				type: [Number, String],
+				default: 0
+			},
+			placeholder: {
+				type: String,
+				default: '选择币种'
+			},
+			value: {
+				type: String,
+				default: '双皮奶'
+			},
+			size: {
+				type: String,
+				default: 'medium'
+			},
+			options: {
+				type: Array,
+				default () {
+					return []
+				}
+			}
+		},
+		data() {
+			return {
+				showOptions: false,
+				boundingClientRect: {},
+				currentSelect: {},
+				optionsGroupTop: 'auto',
+				optionsGroupMargin: ''
+			}
+		},
+		computed: {
+			showSuffix() {
+				return this.showOptions ? 'showOptions' : 'no-showOptions'
+			},
+			easySelectSize() {
+				let size = this.size.toLowerCase()
+				if (size in SIZE) {
+					return {
+						width: SIZE[size].width,
+						height: SIZE[size].height
+					}
+				} else {
+					return {}
+				}
+			}
+		},
+		mounted() {
+			const elQuery = uni.createSelectorQuery().in(this)
+			elQuery.select('.easy-select').boundingClientRect(data => {
+				this.boundingClientRect = data
+			}).exec();
+			try {
+				if (!this.windowHeight) {
+					const storageHeihgt = uni.getStorageSync(STORAGE_KEY)
+					if (storageHeihgt) {
+						this.easyWindowHeight = storageHeihgt
+						return
+					}
+					const res = uni.getSystemInfoSync();
+					this.easyWindowHeight = res.windowHeight
+					uni.setStorageSync(STORAGE_KEY, this.easyWindowHeight)
+				}
+			} catch (e) {
+			    // error
+			}
+		},
+		methods: {
+			trigger(e) {
+				const view = uni.createSelectorQuery().in(this)
+				view.select('.easy-select').fields({rect: true}, data => {
+					let {	top, bottom } = data
+					const thresholdHeight = Math.min(MAX_OPTIONS_HEIGHT + OPTIONS_MARGIN, (this.options.length * OPTIONS_ITEM_HEIGHT) +
+						OPTIONS_OTHER_HEIGHT)
+					bottom = Number(this.windowHeight || this.easyWindowHeight) - (top + this.boundingClientRect.height) // 距离底部的距离等于视口的高度减上top加select组件的高度
+
+					// judge direction
+					if (bottom < thresholdHeight) {
+						this.optionsGroupDirection = 'up'
+						this.optionsGroupTop = -thresholdHeight - 12 + 'px'
+						this.optionsGroupMargin = '0'
+					} else {
+						this.optionsGroupDirection = 'down'
+						this.optionsGroupTop = 'auto'
+						this.optionsGroupMargin = '10px 0 0 0'
+					}
+
+					// if (this.scrollTop < )
+					this.showOptions = !this.showOptions
+				}).exec();
+			},
+			select(options) {
+				this.showOptions = false
+				this.currentSelect = options
+				this.$emit('selectOne', options)
+			},
+			hideOptions() {
+				this.showOptions = false
+			}
+		}
+	}
+</script>
+
+<style lang="scss" scoped>
+	.easy-select {
+		position: relative;
+		color: #606266;
+		input{
+			text-align: right;
+		}
+	}
+	.easy-select input {
+		overflow: hidden;
+		white-space: nowrap;
+		text-overflow: ellipsis;
+		height: 100% !important;
+		min-height: 100% !important;
+	}
+
+	.easy-select .easy-select-suffix {
+		position: absolute;
+		box-sizing: border-box;
+		height: 100%;
+		right: 5px;
+		top: 0;
+		display: flex;
+		align-items: center;
+		transform: rotate(180deg);
+		transition: all .3s;
+		transform-origin: center;
+	}
+
+	.easy-select .showOptions {
+		transform: rotate(0) !important;
+	}
+
+	.easy-select .no-showOptions {
+		transform: rotate(180deg) !important;
+	}
+
+	.easy-select .easy-select-options {
+		position: absolute;
+		padding: 6px 0;
+		margin-top: 10px;
+		border: 1px solid #e4e7ed;
+		border-radius: 4px;
+		background-color: #fff;
+		box-shadow: 0 2px 12px 0 rgba(0, 0, 0, .1);
+		box-sizing: border-box;
+		transform-origin: center top;
+		z-index: 2238;
+		overflow: scroll;
+		max-height: 274rpx;
+	}
+
+	.easy-select .easy-select-options-item {
+		padding: 0 20rpx;
+		position: relative;
+		white-space: nowrap;
+		font-size: 14px;
+		color: #606266;
+		height: 33px;
+		line-height: 33px;
+		box-sizing: border-box;
+	}
+
+	.easy-select .active {
+		background-color: #F5F7FA
+	}
+</style>

+ 196 - 0
components/share.vue

@@ -0,0 +1,196 @@
+<template>
+	<view v-if="show" class="mask" @click="toggleMask" @touchmove.stop.prevent="stopPrevent" :style="{ backgroundColor: backgroundColor }">
+		<view
+			class="mask-content"
+			@click.stop.prevent="stopPrevent"
+			:style="[
+				{
+					height: config.height,
+					transform: transform
+				}
+			]"
+		>
+			<scroll-view class="view-content" scroll-y>
+				<view class="share-header">分享到</view>
+				<view class="share-list">
+					<view v-for="(item, index) in shareList" :key="index" class="share-item" @click="shareToFriend(item.text)">
+						<image class="itemImage" :src="item.icon" mode=""></image>
+						<text class="itemText">{{ item.text }}</text>
+					</view>
+				</view>
+			</scroll-view>
+			<view class="bottomButtom b-t" @click="toggleMask">取消</view>
+		</view>
+	</view>
+</template>
+
+<script>
+export default {
+	data() {
+		return {
+			transform: 'translateY(50vh)',
+			timer: 0,
+			backgroundColor: 'rgba(0,0,0,0)',
+			show: false,
+			config: {}
+		};
+	},
+	props: {
+		contentHeight: {
+			type: Number,
+			default: 0
+		},
+		//是否是tabbar页面
+		hasTabbar: {
+			type: Boolean,
+			default: false
+		},
+		shareList: {
+			type: Array,
+			default: function() {
+				return [];
+			}
+		}
+	},
+	created() {
+		const height = uni.upx2px(this.contentHeight) + 'px';
+		this.config = {
+			height: height,
+			transform: `translateY(${height})`,
+			backgroundColor: 'rgba(0,0,0,.4)'
+		};
+		this.transform = this.config.transform;
+	},
+	methods: {
+		toggleMask() {
+			//防止高频点击
+			if (this.timer == 1) {
+				return;
+			}
+			this.timer = 1;
+			setTimeout(() => {
+				this.timer = 0;
+			}, 500);
+
+			if (this.show) {
+				this.transform = this.config.transform;
+				this.backgroundColor = 'rgba(0,0,0,0)';
+				setTimeout(() => {
+					this.show = false;
+					this.hasTabbar && uni.showTabBar();
+				}, 200);
+				return;
+			}
+
+			this.show = true;
+			//等待mask重绘完成执行
+			if (this.hasTabbar) {
+				uni.hideTabBar({
+					success: () => {
+						setTimeout(() => {
+							this.backgroundColor = this.config.backgroundColor;
+							this.transform = 'translateY(0px)';
+						}, 10);
+					}
+				});
+			} else {
+				setTimeout(() => {
+					this.backgroundColor = this.config.backgroundColor;
+					this.transform = 'translateY(0px)';
+				}, 10);
+			}
+		},
+		//防止冒泡和滚动穿透
+		stopPrevent() {},
+		//分享操作
+		shareToFriend(type) {
+			this.$api.msg(`分享给${type}`);
+			this.toggleMask();
+		}
+	}
+};
+</script>
+
+<style lang="scss">
+.mask {
+	position: fixed;
+	left: 0;
+	top: 0;
+	right: 0;
+	bottom: 0;
+	display: flex;
+	justify-content: center;
+	align-items: flex-end;
+	z-index: 998;
+	transition: 0.3s;
+	.bottomButtom {
+		position: absolute;
+		left: 0;
+		bottom: 0;
+		display: flex;
+		justify-content: center;
+		align-items: center;
+		width: 100%;
+		height: 90rpx;
+		background: #fff;
+		z-index: 9;
+		font-size: $font-base + 2rpx;
+		color: $font-color-dark;
+	}
+}
+.mask-content {
+	width: 100%;
+	height: 580rpx;
+	transition: 0.3s;
+	background: #fff;
+	&.has-bottom {
+		padding-bottom: 90rpx;
+	}
+	.view-content {
+		height: 100%;
+	}
+}
+.share-header {
+	height: 110rpx;
+	font-size: $font-base + 2rpx;
+	color: font-color-dark;
+	display: flex;
+	align-items: center;
+	justify-content: center;
+	padding-top: 10rpx;
+	&:before,
+	&:after {
+		content: '';
+		width: 240rpx;
+		heighg: 0;
+		border-top: 1px solid $border-color-base;
+		transform: scaleY(0.5);
+		margin-right: 30rpx;
+	}
+	&:after {
+		margin-left: 30rpx;
+		margin-right: 0;
+	}
+}
+.share-list {
+	display: flex;
+	flex-wrap: wrap;
+}
+.share-item {
+	min-width: 33.33%;
+	display: flex;
+	flex-direction: column;
+	justify-content: center;
+	align-items: center;
+	height: 180rpx;
+	.itemImage {
+		width: 80rpx;
+		height: 80rpx;
+		margin-bottom: 16rpx;
+	}
+	.itemText {
+		font-size: $font-base;
+		color: $font-color-base;
+	}
+}
+</style>

+ 1201 - 0
components/tki-qrcode/qrcode.js

@@ -0,0 +1,1201 @@
+let QRCode = {};
+(function () {
+    /**
+     * 获取单个字符的utf8编码
+     * unicode BMP平面约65535个字符
+     * @param {num} code
+     * return {array}
+     */
+    function unicodeFormat8(code) {
+        // 1 byte
+        var c0, c1, c2;
+        if (code < 128) {
+            return [code];
+            // 2 bytes
+        } else if (code < 2048) {
+            c0 = 192 + (code >> 6);
+            c1 = 128 + (code & 63);
+            return [c0, c1];
+            // 3 bytes
+        } else {
+            c0 = 224 + (code >> 12);
+            c1 = 128 + (code >> 6 & 63);
+            c2 = 128 + (code & 63);
+            return [c0, c1, c2];
+        }
+    }
+    /**
+     * 获取字符串的utf8编码字节串
+     * @param {string} string
+     * @return {array}
+     */
+    function getUTF8Bytes(string) {
+        var utf8codes = [];
+        for (var i = 0; i < string.length; i++) {
+            var code = string.charCodeAt(i);
+            var utf8 = unicodeFormat8(code);
+            for (var j = 0; j < utf8.length; j++) {
+                utf8codes.push(utf8[j]);
+            }
+        }
+        return utf8codes;
+    }
+    /**
+     * 二维码算法实现
+     * @param {string} data              要编码的信息字符串
+     * @param {num} errorCorrectLevel 纠错等级
+     */
+    function QRCodeAlg(data, errorCorrectLevel) {
+        this.typeNumber = -1; //版本
+        this.errorCorrectLevel = errorCorrectLevel;
+        this.modules = null; //二维矩阵,存放最终结果
+        this.moduleCount = 0; //矩阵大小
+        this.dataCache = null; //数据缓存
+        this.rsBlocks = null; //版本数据信息
+        this.totalDataCount = -1; //可使用的数据量
+        this.data = data;
+        this.utf8bytes = getUTF8Bytes(data);
+        this.make();
+    }
+    QRCodeAlg.prototype = {
+        constructor: QRCodeAlg,
+        /**
+         * 获取二维码矩阵大小
+         * @return {num} 矩阵大小
+         */
+        getModuleCount: function () {
+            return this.moduleCount;
+        },
+        /**
+         * 编码
+         */
+        make: function () {
+            this.getRightType();
+            this.dataCache = this.createData();
+            this.createQrcode();
+        },
+        /**
+         * 设置二位矩阵功能图形
+         * @param  {bool} test 表示是否在寻找最好掩膜阶段
+         * @param  {num} maskPattern 掩膜的版本
+         */
+        makeImpl: function (maskPattern) {
+            this.moduleCount = this.typeNumber * 4 + 17;
+            this.modules = new Array(this.moduleCount);
+            for (var row = 0; row < this.moduleCount; row++) {
+                this.modules[row] = new Array(this.moduleCount);
+            }
+            this.setupPositionProbePattern(0, 0);
+            this.setupPositionProbePattern(this.moduleCount - 7, 0);
+            this.setupPositionProbePattern(0, this.moduleCount - 7);
+            this.setupPositionAdjustPattern();
+            this.setupTimingPattern();
+            this.setupTypeInfo(true, maskPattern);
+            if (this.typeNumber >= 7) {
+                this.setupTypeNumber(true);
+            }
+            this.mapData(this.dataCache, maskPattern);
+        },
+        /**
+         * 设置二维码的位置探测图形
+         * @param  {num} row 探测图形的中心横坐标
+         * @param  {num} col 探测图形的中心纵坐标
+         */
+        setupPositionProbePattern: function (row, col) {
+            for (var r = -1; r <= 7; r++) {
+                if (row + r <= -1 || this.moduleCount <= row + r) continue;
+                for (var c = -1; c <= 7; c++) {
+                    if (col + c <= -1 || this.moduleCount <= col + c) continue;
+                    if ((0 <= r && r <= 6 && (c == 0 || c == 6)) || (0 <= c && c <= 6 && (r == 0 || r == 6)) || (2 <= r && r <= 4 && 2 <= c && c <= 4)) {
+                        this.modules[row + r][col + c] = true;
+                    } else {
+                        this.modules[row + r][col + c] = false;
+                    }
+                }
+            }
+        },
+        /**
+         * 创建二维码
+         * @return {[type]} [description]
+         */
+        createQrcode: function () {
+            var minLostPoint = 0;
+            var pattern = 0;
+            var bestModules = null;
+            for (var i = 0; i < 8; i++) {
+                this.makeImpl(i);
+                var lostPoint = QRUtil.getLostPoint(this);
+                if (i == 0 || minLostPoint > lostPoint) {
+                    minLostPoint = lostPoint;
+                    pattern = i;
+                    bestModules = this.modules;
+                }
+            }
+            this.modules = bestModules;
+            this.setupTypeInfo(false, pattern);
+            if (this.typeNumber >= 7) {
+                this.setupTypeNumber(false);
+            }
+        },
+        /**
+         * 设置定位图形
+         * @return {[type]} [description]
+         */
+        setupTimingPattern: function () {
+            for (var r = 8; r < this.moduleCount - 8; r++) {
+                if (this.modules[r][6] != null) {
+                    continue;
+                }
+                this.modules[r][6] = (r % 2 == 0);
+                if (this.modules[6][r] != null) {
+                    continue;
+                }
+                this.modules[6][r] = (r % 2 == 0);
+            }
+        },
+        /**
+         * 设置矫正图形
+         * @return {[type]} [description]
+         */
+        setupPositionAdjustPattern: function () {
+            var pos = QRUtil.getPatternPosition(this.typeNumber);
+            for (var i = 0; i < pos.length; i++) {
+                for (var j = 0; j < pos.length; j++) {
+                    var row = pos[i];
+                    var col = pos[j];
+                    if (this.modules[row][col] != null) {
+                        continue;
+                    }
+                    for (var r = -2; r <= 2; r++) {
+                        for (var c = -2; c <= 2; c++) {
+                            if (r == -2 || r == 2 || c == -2 || c == 2 || (r == 0 && c == 0)) {
+                                this.modules[row + r][col + c] = true;
+                            } else {
+                                this.modules[row + r][col + c] = false;
+                            }
+                        }
+                    }
+                }
+            }
+        },
+        /**
+         * 设置版本信息(7以上版本才有)
+         * @param  {bool} test 是否处于判断最佳掩膜阶段
+         * @return {[type]}      [description]
+         */
+        setupTypeNumber: function (test) {
+            var bits = QRUtil.getBCHTypeNumber(this.typeNumber);
+            for (var i = 0; i < 18; i++) {
+                var mod = (!test && ((bits >> i) & 1) == 1);
+                this.modules[Math.floor(i / 3)][i % 3 + this.moduleCount - 8 - 3] = mod;
+                this.modules[i % 3 + this.moduleCount - 8 - 3][Math.floor(i / 3)] = mod;
+            }
+        },
+        /**
+         * 设置格式信息(纠错等级和掩膜版本)
+         * @param  {bool} test
+         * @param  {num} maskPattern 掩膜版本
+         * @return {}
+         */
+        setupTypeInfo: function (test, maskPattern) {
+            var data = (QRErrorCorrectLevel[this.errorCorrectLevel] << 3) | maskPattern;
+            var bits = QRUtil.getBCHTypeInfo(data);
+            // vertical
+            for (var i = 0; i < 15; i++) {
+                var mod = (!test && ((bits >> i) & 1) == 1);
+                if (i < 6) {
+                    this.modules[i][8] = mod;
+                } else if (i < 8) {
+                    this.modules[i + 1][8] = mod;
+                } else {
+                    this.modules[this.moduleCount - 15 + i][8] = mod;
+                }
+                // horizontal
+                var mod = (!test && ((bits >> i) & 1) == 1);
+                if (i < 8) {
+                    this.modules[8][this.moduleCount - i - 1] = mod;
+                } else if (i < 9) {
+                    this.modules[8][15 - i - 1 + 1] = mod;
+                } else {
+                    this.modules[8][15 - i - 1] = mod;
+                }
+            }
+            // fixed module
+            this.modules[this.moduleCount - 8][8] = (!test);
+        },
+        /**
+         * 数据编码
+         * @return {[type]} [description]
+         */
+        createData: function () {
+            var buffer = new QRBitBuffer();
+            var lengthBits = this.typeNumber > 9 ? 16 : 8;
+            buffer.put(4, 4); //添加模式
+            buffer.put(this.utf8bytes.length, lengthBits);
+            for (var i = 0, l = this.utf8bytes.length; i < l; i++) {
+                buffer.put(this.utf8bytes[i], 8);
+            }
+            if (buffer.length + 4 <= this.totalDataCount * 8) {
+                buffer.put(0, 4);
+            }
+            // padding
+            while (buffer.length % 8 != 0) {
+                buffer.putBit(false);
+            }
+            // padding
+            while (true) {
+                if (buffer.length >= this.totalDataCount * 8) {
+                    break;
+                }
+                buffer.put(QRCodeAlg.PAD0, 8);
+                if (buffer.length >= this.totalDataCount * 8) {
+                    break;
+                }
+                buffer.put(QRCodeAlg.PAD1, 8);
+            }
+            return this.createBytes(buffer);
+        },
+        /**
+         * 纠错码编码
+         * @param  {buffer} buffer 数据编码
+         * @return {[type]}
+         */
+        createBytes: function (buffer) {
+            var offset = 0;
+            var maxDcCount = 0;
+            var maxEcCount = 0;
+            var length = this.rsBlock.length / 3;
+            var rsBlocks = new Array();
+            for (var i = 0; i < length; i++) {
+                var count = this.rsBlock[i * 3 + 0];
+                var totalCount = this.rsBlock[i * 3 + 1];
+                var dataCount = this.rsBlock[i * 3 + 2];
+                for (var j = 0; j < count; j++) {
+                    rsBlocks.push([dataCount, totalCount]);
+                }
+            }
+            var dcdata = new Array(rsBlocks.length);
+            var ecdata = new Array(rsBlocks.length);
+            for (var r = 0; r < rsBlocks.length; r++) {
+                var dcCount = rsBlocks[r][0];
+                var ecCount = rsBlocks[r][1] - dcCount;
+                maxDcCount = Math.max(maxDcCount, dcCount);
+                maxEcCount = Math.max(maxEcCount, ecCount);
+                dcdata[r] = new Array(dcCount);
+                for (var i = 0; i < dcdata[r].length; i++) {
+                    dcdata[r][i] = 0xff & buffer.buffer[i + offset];
+                }
+                offset += dcCount;
+                var rsPoly = QRUtil.getErrorCorrectPolynomial(ecCount);
+                var rawPoly = new QRPolynomial(dcdata[r], rsPoly.getLength() - 1);
+                var modPoly = rawPoly.mod(rsPoly);
+                ecdata[r] = new Array(rsPoly.getLength() - 1);
+                for (var i = 0; i < ecdata[r].length; i++) {
+                    var modIndex = i + modPoly.getLength() - ecdata[r].length;
+                    ecdata[r][i] = (modIndex >= 0) ? modPoly.get(modIndex) : 0;
+                }
+            }
+            var data = new Array(this.totalDataCount);
+            var index = 0;
+            for (var i = 0; i < maxDcCount; i++) {
+                for (var r = 0; r < rsBlocks.length; r++) {
+                    if (i < dcdata[r].length) {
+                        data[index++] = dcdata[r][i];
+                    }
+                }
+            }
+            for (var i = 0; i < maxEcCount; i++) {
+                for (var r = 0; r < rsBlocks.length; r++) {
+                    if (i < ecdata[r].length) {
+                        data[index++] = ecdata[r][i];
+                    }
+                }
+            }
+            return data;
+
+        },
+        /**
+         * 布置模块,构建最终信息
+         * @param  {} data
+         * @param  {} maskPattern
+         * @return {}
+         */
+        mapData: function (data, maskPattern) {
+            var inc = -1;
+            var row = this.moduleCount - 1;
+            var bitIndex = 7;
+            var byteIndex = 0;
+            for (var col = this.moduleCount - 1; col > 0; col -= 2) {
+                if (col == 6) col--;
+                while (true) {
+                    for (var c = 0; c < 2; c++) {
+                        if (this.modules[row][col - c] == null) {
+                            var dark = false;
+                            if (byteIndex < data.length) {
+                                dark = (((data[byteIndex] >>> bitIndex) & 1) == 1);
+                            }
+                            var mask = QRUtil.getMask(maskPattern, row, col - c);
+                            if (mask) {
+                                dark = !dark;
+                            }
+                            this.modules[row][col - c] = dark;
+                            bitIndex--;
+                            if (bitIndex == -1) {
+                                byteIndex++;
+                                bitIndex = 7;
+                            }
+                        }
+                    }
+                    row += inc;
+                    if (row < 0 || this.moduleCount <= row) {
+                        row -= inc;
+                        inc = -inc;
+                        break;
+                    }
+                }
+            }
+        }
+    };
+    /**
+     * 填充字段
+     */
+    QRCodeAlg.PAD0 = 0xEC;
+    QRCodeAlg.PAD1 = 0x11;
+    //---------------------------------------------------------------------
+    // 纠错等级对应的编码
+    //---------------------------------------------------------------------
+    var QRErrorCorrectLevel = [1, 0, 3, 2];
+    //---------------------------------------------------------------------
+    // 掩膜版本
+    //---------------------------------------------------------------------
+    var QRMaskPattern = {
+        PATTERN000: 0,
+        PATTERN001: 1,
+        PATTERN010: 2,
+        PATTERN011: 3,
+        PATTERN100: 4,
+        PATTERN101: 5,
+        PATTERN110: 6,
+        PATTERN111: 7
+    };
+    //---------------------------------------------------------------------
+    // 工具类
+    //---------------------------------------------------------------------
+    var QRUtil = {
+        /*
+        每个版本矫正图形的位置
+         */
+        PATTERN_POSITION_TABLE: [
+            [],
+            [6, 18],
+            [6, 22],
+            [6, 26],
+            [6, 30],
+            [6, 34],
+            [6, 22, 38],
+            [6, 24, 42],
+            [6, 26, 46],
+            [6, 28, 50],
+            [6, 30, 54],
+            [6, 32, 58],
+            [6, 34, 62],
+            [6, 26, 46, 66],
+            [6, 26, 48, 70],
+            [6, 26, 50, 74],
+            [6, 30, 54, 78],
+            [6, 30, 56, 82],
+            [6, 30, 58, 86],
+            [6, 34, 62, 90],
+            [6, 28, 50, 72, 94],
+            [6, 26, 50, 74, 98],
+            [6, 30, 54, 78, 102],
+            [6, 28, 54, 80, 106],
+            [6, 32, 58, 84, 110],
+            [6, 30, 58, 86, 114],
+            [6, 34, 62, 90, 118],
+            [6, 26, 50, 74, 98, 122],
+            [6, 30, 54, 78, 102, 126],
+            [6, 26, 52, 78, 104, 130],
+            [6, 30, 56, 82, 108, 134],
+            [6, 34, 60, 86, 112, 138],
+            [6, 30, 58, 86, 114, 142],
+            [6, 34, 62, 90, 118, 146],
+            [6, 30, 54, 78, 102, 126, 150],
+            [6, 24, 50, 76, 102, 128, 154],
+            [6, 28, 54, 80, 106, 132, 158],
+            [6, 32, 58, 84, 110, 136, 162],
+            [6, 26, 54, 82, 110, 138, 166],
+            [6, 30, 58, 86, 114, 142, 170]
+        ],
+        G15: (1 << 10) | (1 << 8) | (1 << 5) | (1 << 4) | (1 << 2) | (1 << 1) | (1 << 0),
+        G18: (1 << 12) | (1 << 11) | (1 << 10) | (1 << 9) | (1 << 8) | (1 << 5) | (1 << 2) | (1 << 0),
+        G15_MASK: (1 << 14) | (1 << 12) | (1 << 10) | (1 << 4) | (1 << 1),
+        /*
+        BCH编码格式信息
+         */
+        getBCHTypeInfo: function (data) {
+            var d = data << 10;
+            while (QRUtil.getBCHDigit(d) - QRUtil.getBCHDigit(QRUtil.G15) >= 0) {
+                d ^= (QRUtil.G15 << (QRUtil.getBCHDigit(d) - QRUtil.getBCHDigit(QRUtil.G15)));
+            }
+            return ((data << 10) | d) ^ QRUtil.G15_MASK;
+        },
+        /*
+        BCH编码版本信息
+         */
+        getBCHTypeNumber: function (data) {
+            var d = data << 12;
+            while (QRUtil.getBCHDigit(d) - QRUtil.getBCHDigit(QRUtil.G18) >= 0) {
+                d ^= (QRUtil.G18 << (QRUtil.getBCHDigit(d) - QRUtil.getBCHDigit(QRUtil.G18)));
+            }
+            return (data << 12) | d;
+        },
+        /*
+        获取BCH位信息
+         */
+        getBCHDigit: function (data) {
+            var digit = 0;
+            while (data != 0) {
+                digit++;
+                data >>>= 1;
+            }
+            return digit;
+        },
+        /*
+        获取版本对应的矫正图形位置
+         */
+        getPatternPosition: function (typeNumber) {
+            return QRUtil.PATTERN_POSITION_TABLE[typeNumber - 1];
+        },
+        /*
+        掩膜算法
+         */
+        getMask: function (maskPattern, i, j) {
+            switch (maskPattern) {
+                case QRMaskPattern.PATTERN000:
+                    return (i + j) % 2 == 0;
+                case QRMaskPattern.PATTERN001:
+                    return i % 2 == 0;
+                case QRMaskPattern.PATTERN010:
+                    return j % 3 == 0;
+                case QRMaskPattern.PATTERN011:
+                    return (i + j) % 3 == 0;
+                case QRMaskPattern.PATTERN100:
+                    return (Math.floor(i / 2) + Math.floor(j / 3)) % 2 == 0;
+                case QRMaskPattern.PATTERN101:
+                    return (i * j) % 2 + (i * j) % 3 == 0;
+                case QRMaskPattern.PATTERN110:
+                    return ((i * j) % 2 + (i * j) % 3) % 2 == 0;
+                case QRMaskPattern.PATTERN111:
+                    return ((i * j) % 3 + (i + j) % 2) % 2 == 0;
+                default:
+                    throw new Error("bad maskPattern:" + maskPattern);
+            }
+        },
+        /*
+        获取RS的纠错多项式
+         */
+        getErrorCorrectPolynomial: function (errorCorrectLength) {
+            var a = new QRPolynomial([1], 0);
+            for (var i = 0; i < errorCorrectLength; i++) {
+                a = a.multiply(new QRPolynomial([1, QRMath.gexp(i)], 0));
+            }
+            return a;
+        },
+        /*
+        获取评价
+         */
+        getLostPoint: function (qrCode) {
+            var moduleCount = qrCode.getModuleCount(),
+                lostPoint = 0,
+                darkCount = 0;
+            for (var row = 0; row < moduleCount; row++) {
+                var sameCount = 0;
+                var head = qrCode.modules[row][0];
+                for (var col = 0; col < moduleCount; col++) {
+                    var current = qrCode.modules[row][col];
+                    //level 3 评价
+                    if (col < moduleCount - 6) {
+                        if (current && !qrCode.modules[row][col + 1] && qrCode.modules[row][col + 2] && qrCode.modules[row][col + 3] && qrCode.modules[row][col + 4] && !qrCode.modules[row][col + 5] && qrCode.modules[row][col + 6]) {
+                            if (col < moduleCount - 10) {
+                                if (qrCode.modules[row][col + 7] && qrCode.modules[row][col + 8] && qrCode.modules[row][col + 9] && qrCode.modules[row][col + 10]) {
+                                    lostPoint += 40;
+                                }
+                            } else if (col > 3) {
+                                if (qrCode.modules[row][col - 1] && qrCode.modules[row][col - 2] && qrCode.modules[row][col - 3] && qrCode.modules[row][col - 4]) {
+                                    lostPoint += 40;
+                                }
+                            }
+                        }
+                    }
+                    //level 2 评价
+                    if ((row < moduleCount - 1) && (col < moduleCount - 1)) {
+                        var count = 0;
+                        if (current) count++;
+                        if (qrCode.modules[row + 1][col]) count++;
+                        if (qrCode.modules[row][col + 1]) count++;
+                        if (qrCode.modules[row + 1][col + 1]) count++;
+                        if (count == 0 || count == 4) {
+                            lostPoint += 3;
+                        }
+                    }
+                    //level 1 评价
+                    if (head ^ current) {
+                        sameCount++;
+                    } else {
+                        head = current;
+                        if (sameCount >= 5) {
+                            lostPoint += (3 + sameCount - 5);
+                        }
+                        sameCount = 1;
+                    }
+                    //level 4 评价
+                    if (current) {
+                        darkCount++;
+                    }
+                }
+            }
+            for (var col = 0; col < moduleCount; col++) {
+                var sameCount = 0;
+                var head = qrCode.modules[0][col];
+                for (var row = 0; row < moduleCount; row++) {
+                    var current = qrCode.modules[row][col];
+                    //level 3 评价
+                    if (row < moduleCount - 6) {
+                        if (current && !qrCode.modules[row + 1][col] && qrCode.modules[row + 2][col] && qrCode.modules[row + 3][col] && qrCode.modules[row + 4][col] && !qrCode.modules[row + 5][col] && qrCode.modules[row + 6][col]) {
+                            if (row < moduleCount - 10) {
+                                if (qrCode.modules[row + 7][col] && qrCode.modules[row + 8][col] && qrCode.modules[row + 9][col] && qrCode.modules[row + 10][col]) {
+                                    lostPoint += 40;
+                                }
+                            } else if (row > 3) {
+                                if (qrCode.modules[row - 1][col] && qrCode.modules[row - 2][col] && qrCode.modules[row - 3][col] && qrCode.modules[row - 4][col]) {
+                                    lostPoint += 40;
+                                }
+                            }
+                        }
+                    }
+                    //level 1 评价
+                    if (head ^ current) {
+                        sameCount++;
+                    } else {
+                        head = current;
+                        if (sameCount >= 5) {
+                            lostPoint += (3 + sameCount - 5);
+                        }
+                        sameCount = 1;
+                    }
+                }
+            }
+            // LEVEL4
+            var ratio = Math.abs(100 * darkCount / moduleCount / moduleCount - 50) / 5;
+            lostPoint += ratio * 10;
+            return lostPoint;
+        }
+
+    };
+    //---------------------------------------------------------------------
+    // QRMath使用的数学工具
+    //---------------------------------------------------------------------
+    var QRMath = {
+        /*
+        将n转化为a^m
+         */
+        glog: function (n) {
+            if (n < 1) {
+                throw new Error("glog(" + n + ")");
+            }
+            return QRMath.LOG_TABLE[n];
+        },
+        /*
+        将a^m转化为n
+         */
+        gexp: function (n) {
+            while (n < 0) {
+                n += 255;
+            }
+            while (n >= 256) {
+                n -= 255;
+            }
+            return QRMath.EXP_TABLE[n];
+        },
+        EXP_TABLE: new Array(256),
+        LOG_TABLE: new Array(256)
+
+    };
+    for (var i = 0; i < 8; i++) {
+        QRMath.EXP_TABLE[i] = 1 << i;
+    }
+    for (var i = 8; i < 256; i++) {
+        QRMath.EXP_TABLE[i] = QRMath.EXP_TABLE[i - 4] ^ QRMath.EXP_TABLE[i - 5] ^ QRMath.EXP_TABLE[i - 6] ^ QRMath.EXP_TABLE[i - 8];
+    }
+    for (var i = 0; i < 255; i++) {
+        QRMath.LOG_TABLE[QRMath.EXP_TABLE[i]] = i;
+    }
+    //---------------------------------------------------------------------
+    // QRPolynomial 多项式
+    //---------------------------------------------------------------------
+    /**
+     * 多项式类
+     * @param {Array} num   系数
+     * @param {num} shift a^shift
+     */
+    function QRPolynomial(num, shift) {
+        if (num.length == undefined) {
+            throw new Error(num.length + "/" + shift);
+        }
+        var offset = 0;
+        while (offset < num.length && num[offset] == 0) {
+            offset++;
+        }
+        this.num = new Array(num.length - offset + shift);
+        for (var i = 0; i < num.length - offset; i++) {
+            this.num[i] = num[i + offset];
+        }
+    }
+    QRPolynomial.prototype = {
+        get: function (index) {
+            return this.num[index];
+        },
+        getLength: function () {
+            return this.num.length;
+        },
+        /**
+         * 多项式乘法
+         * @param  {QRPolynomial} e 被乘多项式
+         * @return {[type]}   [description]
+         */
+        multiply: function (e) {
+            var num = new Array(this.getLength() + e.getLength() - 1);
+            for (var i = 0; i < this.getLength(); i++) {
+                for (var j = 0; j < e.getLength(); j++) {
+                    num[i + j] ^= QRMath.gexp(QRMath.glog(this.get(i)) + QRMath.glog(e.get(j)));
+                }
+            }
+            return new QRPolynomial(num, 0);
+        },
+        /**
+         * 多项式模运算
+         * @param  {QRPolynomial} e 模多项式
+         * @return {}
+         */
+        mod: function (e) {
+            var tl = this.getLength(),
+                el = e.getLength();
+            if (tl - el < 0) {
+                return this;
+            }
+            var num = new Array(tl);
+            for (var i = 0; i < tl; i++) {
+                num[i] = this.get(i);
+            }
+            while (num.length >= el) {
+                var ratio = QRMath.glog(num[0]) - QRMath.glog(e.get(0));
+
+                for (var i = 0; i < e.getLength(); i++) {
+                    num[i] ^= QRMath.gexp(QRMath.glog(e.get(i)) + ratio);
+                }
+                while (num[0] == 0) {
+                    num.shift();
+                }
+            }
+            return new QRPolynomial(num, 0);
+        }
+    };
+
+    //---------------------------------------------------------------------
+    // RS_BLOCK_TABLE
+    //---------------------------------------------------------------------
+    /*
+    二维码各个版本信息[块数, 每块中的数据块数, 每块中的信息块数]
+     */
+    var RS_BLOCK_TABLE = [
+        // L
+        // M
+        // Q
+        // H
+        // 1
+        [1, 26, 19],
+        [1, 26, 16],
+        [1, 26, 13],
+        [1, 26, 9],
+
+        // 2
+        [1, 44, 34],
+        [1, 44, 28],
+        [1, 44, 22],
+        [1, 44, 16],
+
+        // 3
+        [1, 70, 55],
+        [1, 70, 44],
+        [2, 35, 17],
+        [2, 35, 13],
+
+        // 4
+        [1, 100, 80],
+        [2, 50, 32],
+        [2, 50, 24],
+        [4, 25, 9],
+
+        // 5
+        [1, 134, 108],
+        [2, 67, 43],
+        [2, 33, 15, 2, 34, 16],
+        [2, 33, 11, 2, 34, 12],
+
+        // 6
+        [2, 86, 68],
+        [4, 43, 27],
+        [4, 43, 19],
+        [4, 43, 15],
+
+        // 7
+        [2, 98, 78],
+        [4, 49, 31],
+        [2, 32, 14, 4, 33, 15],
+        [4, 39, 13, 1, 40, 14],
+
+        // 8
+        [2, 121, 97],
+        [2, 60, 38, 2, 61, 39],
+        [4, 40, 18, 2, 41, 19],
+        [4, 40, 14, 2, 41, 15],
+
+        // 9
+        [2, 146, 116],
+        [3, 58, 36, 2, 59, 37],
+        [4, 36, 16, 4, 37, 17],
+        [4, 36, 12, 4, 37, 13],
+
+        // 10
+        [2, 86, 68, 2, 87, 69],
+        [4, 69, 43, 1, 70, 44],
+        [6, 43, 19, 2, 44, 20],
+        [6, 43, 15, 2, 44, 16],
+
+        // 11
+        [4, 101, 81],
+        [1, 80, 50, 4, 81, 51],
+        [4, 50, 22, 4, 51, 23],
+        [3, 36, 12, 8, 37, 13],
+
+        // 12
+        [2, 116, 92, 2, 117, 93],
+        [6, 58, 36, 2, 59, 37],
+        [4, 46, 20, 6, 47, 21],
+        [7, 42, 14, 4, 43, 15],
+
+        // 13
+        [4, 133, 107],
+        [8, 59, 37, 1, 60, 38],
+        [8, 44, 20, 4, 45, 21],
+        [12, 33, 11, 4, 34, 12],
+
+        // 14
+        [3, 145, 115, 1, 146, 116],
+        [4, 64, 40, 5, 65, 41],
+        [11, 36, 16, 5, 37, 17],
+        [11, 36, 12, 5, 37, 13],
+
+        // 15
+        [5, 109, 87, 1, 110, 88],
+        [5, 65, 41, 5, 66, 42],
+        [5, 54, 24, 7, 55, 25],
+        [11, 36, 12],
+
+        // 16
+        [5, 122, 98, 1, 123, 99],
+        [7, 73, 45, 3, 74, 46],
+        [15, 43, 19, 2, 44, 20],
+        [3, 45, 15, 13, 46, 16],
+
+        // 17
+        [1, 135, 107, 5, 136, 108],
+        [10, 74, 46, 1, 75, 47],
+        [1, 50, 22, 15, 51, 23],
+        [2, 42, 14, 17, 43, 15],
+
+        // 18
+        [5, 150, 120, 1, 151, 121],
+        [9, 69, 43, 4, 70, 44],
+        [17, 50, 22, 1, 51, 23],
+        [2, 42, 14, 19, 43, 15],
+
+        // 19
+        [3, 141, 113, 4, 142, 114],
+        [3, 70, 44, 11, 71, 45],
+        [17, 47, 21, 4, 48, 22],
+        [9, 39, 13, 16, 40, 14],
+
+        // 20
+        [3, 135, 107, 5, 136, 108],
+        [3, 67, 41, 13, 68, 42],
+        [15, 54, 24, 5, 55, 25],
+        [15, 43, 15, 10, 44, 16],
+
+        // 21
+        [4, 144, 116, 4, 145, 117],
+        [17, 68, 42],
+        [17, 50, 22, 6, 51, 23],
+        [19, 46, 16, 6, 47, 17],
+
+        // 22
+        [2, 139, 111, 7, 140, 112],
+        [17, 74, 46],
+        [7, 54, 24, 16, 55, 25],
+        [34, 37, 13],
+
+        // 23
+        [4, 151, 121, 5, 152, 122],
+        [4, 75, 47, 14, 76, 48],
+        [11, 54, 24, 14, 55, 25],
+        [16, 45, 15, 14, 46, 16],
+
+        // 24
+        [6, 147, 117, 4, 148, 118],
+        [6, 73, 45, 14, 74, 46],
+        [11, 54, 24, 16, 55, 25],
+        [30, 46, 16, 2, 47, 17],
+
+        // 25
+        [8, 132, 106, 4, 133, 107],
+        [8, 75, 47, 13, 76, 48],
+        [7, 54, 24, 22, 55, 25],
+        [22, 45, 15, 13, 46, 16],
+
+        // 26
+        [10, 142, 114, 2, 143, 115],
+        [19, 74, 46, 4, 75, 47],
+        [28, 50, 22, 6, 51, 23],
+        [33, 46, 16, 4, 47, 17],
+
+        // 27
+        [8, 152, 122, 4, 153, 123],
+        [22, 73, 45, 3, 74, 46],
+        [8, 53, 23, 26, 54, 24],
+        [12, 45, 15, 28, 46, 16],
+
+        // 28
+        [3, 147, 117, 10, 148, 118],
+        [3, 73, 45, 23, 74, 46],
+        [4, 54, 24, 31, 55, 25],
+        [11, 45, 15, 31, 46, 16],
+
+        // 29
+        [7, 146, 116, 7, 147, 117],
+        [21, 73, 45, 7, 74, 46],
+        [1, 53, 23, 37, 54, 24],
+        [19, 45, 15, 26, 46, 16],
+
+        // 30
+        [5, 145, 115, 10, 146, 116],
+        [19, 75, 47, 10, 76, 48],
+        [15, 54, 24, 25, 55, 25],
+        [23, 45, 15, 25, 46, 16],
+
+        // 31
+        [13, 145, 115, 3, 146, 116],
+        [2, 74, 46, 29, 75, 47],
+        [42, 54, 24, 1, 55, 25],
+        [23, 45, 15, 28, 46, 16],
+
+        // 32
+        [17, 145, 115],
+        [10, 74, 46, 23, 75, 47],
+        [10, 54, 24, 35, 55, 25],
+        [19, 45, 15, 35, 46, 16],
+
+        // 33
+        [17, 145, 115, 1, 146, 116],
+        [14, 74, 46, 21, 75, 47],
+        [29, 54, 24, 19, 55, 25],
+        [11, 45, 15, 46, 46, 16],
+
+        // 34
+        [13, 145, 115, 6, 146, 116],
+        [14, 74, 46, 23, 75, 47],
+        [44, 54, 24, 7, 55, 25],
+        [59, 46, 16, 1, 47, 17],
+
+        // 35
+        [12, 151, 121, 7, 152, 122],
+        [12, 75, 47, 26, 76, 48],
+        [39, 54, 24, 14, 55, 25],
+        [22, 45, 15, 41, 46, 16],
+
+        // 36
+        [6, 151, 121, 14, 152, 122],
+        [6, 75, 47, 34, 76, 48],
+        [46, 54, 24, 10, 55, 25],
+        [2, 45, 15, 64, 46, 16],
+
+        // 37
+        [17, 152, 122, 4, 153, 123],
+        [29, 74, 46, 14, 75, 47],
+        [49, 54, 24, 10, 55, 25],
+        [24, 45, 15, 46, 46, 16],
+
+        // 38
+        [4, 152, 122, 18, 153, 123],
+        [13, 74, 46, 32, 75, 47],
+        [48, 54, 24, 14, 55, 25],
+        [42, 45, 15, 32, 46, 16],
+
+        // 39
+        [20, 147, 117, 4, 148, 118],
+        [40, 75, 47, 7, 76, 48],
+        [43, 54, 24, 22, 55, 25],
+        [10, 45, 15, 67, 46, 16],
+
+        // 40
+        [19, 148, 118, 6, 149, 119],
+        [18, 75, 47, 31, 76, 48],
+        [34, 54, 24, 34, 55, 25],
+        [20, 45, 15, 61, 46, 16]
+    ];
+
+    /**
+     * 根据数据获取对应版本
+     * @return {[type]} [description]
+     */
+    QRCodeAlg.prototype.getRightType = function () {
+        for (var typeNumber = 1; typeNumber < 41; typeNumber++) {
+            var rsBlock = RS_BLOCK_TABLE[(typeNumber - 1) * 4 + this.errorCorrectLevel];
+            if (rsBlock == undefined) {
+                throw new Error("bad rs block @ typeNumber:" + typeNumber + "/errorCorrectLevel:" + this.errorCorrectLevel);
+            }
+            var length = rsBlock.length / 3;
+            var totalDataCount = 0;
+            for (var i = 0; i < length; i++) {
+                var count = rsBlock[i * 3 + 0];
+                var dataCount = rsBlock[i * 3 + 2];
+                totalDataCount += dataCount * count;
+            }
+            var lengthBytes = typeNumber > 9 ? 2 : 1;
+            if (this.utf8bytes.length + lengthBytes < totalDataCount || typeNumber == 40) {
+                this.typeNumber = typeNumber;
+                this.rsBlock = rsBlock;
+                this.totalDataCount = totalDataCount;
+                break;
+            }
+        }
+    };
+
+    //---------------------------------------------------------------------
+    // QRBitBuffer
+    //---------------------------------------------------------------------
+    function QRBitBuffer() {
+        this.buffer = new Array();
+        this.length = 0;
+    }
+    QRBitBuffer.prototype = {
+        get: function (index) {
+            var bufIndex = Math.floor(index / 8);
+            return ((this.buffer[bufIndex] >>> (7 - index % 8)) & 1);
+        },
+        put: function (num, length) {
+            for (var i = 0; i < length; i++) {
+                this.putBit(((num >>> (length - i - 1)) & 1));
+            }
+        },
+        putBit: function (bit) {
+            var bufIndex = Math.floor(this.length / 8);
+            if (this.buffer.length <= bufIndex) {
+                this.buffer.push(0);
+            }
+            if (bit) {
+                this.buffer[bufIndex] |= (0x80 >>> (this.length % 8));
+            }
+            this.length++;
+        }
+    };
+
+
+
+    // xzedit
+    let qrcodeAlgObjCache = [];
+    /**
+     * 二维码构造函数,主要用于绘制
+     * @param  {参数列表} opt 传递参数
+     * @return {}
+     */
+    QRCode = function (opt) {
+        //设置默认参数
+        this.options = {
+            text: '',
+            size: 256,
+            correctLevel: 3,
+            background: '#ffffff',
+            foreground: '#000000',
+            pdground: '#000000',
+            image: '',
+            imageSize: 30,
+            canvasId: opt.canvasId,
+            context: opt.context,
+            usingComponents: opt.usingComponents,
+            showLoading: opt.showLoading,
+            loadingText: opt.loadingText,
+        };
+        if (typeof opt === 'string') { // 只编码ASCII字符串
+            opt = {
+                text: opt
+            };
+        }
+        if (opt) {
+            for (var i in opt) {
+                this.options[i] = opt[i];
+            }
+        }
+        //使用QRCodeAlg创建二维码结构
+        var qrCodeAlg = null;
+        for (var i = 0, l = qrcodeAlgObjCache.length; i < l; i++) {
+            if (qrcodeAlgObjCache[i].text == this.options.text && qrcodeAlgObjCache[i].text.correctLevel == this.options.correctLevel) {
+                qrCodeAlg = qrcodeAlgObjCache[i].obj;
+                break;
+            }
+        }
+        if (i == l) {
+            qrCodeAlg = new QRCodeAlg(this.options.text, this.options.correctLevel);
+            qrcodeAlgObjCache.push({
+                text: this.options.text,
+                correctLevel: this.options.correctLevel,
+                obj: qrCodeAlg
+            });
+        }
+        /**
+         * 计算矩阵点的前景色
+         * @param {Obj} config
+         * @param {Number} config.row 点x坐标
+         * @param {Number} config.col 点y坐标
+         * @param {Number} config.count 矩阵大小
+         * @param {Number} config.options 组件的options
+         * @return {String}
+         */
+        let getForeGround = function (config) {
+            var options = config.options;
+            if (options.pdground && (
+                (config.row > 1 && config.row < 5 && config.col > 1 && config.col < 5) ||
+                (config.row > (config.count - 6) && config.row < (config.count - 2) && config.col > 1 && config.col < 5) ||
+                (config.row > 1 && config.row < 5 && config.col > (config.count - 6) && config.col < (config.count - 2))
+            )) {
+                return options.pdground;
+            }
+            return options.foreground;
+        }
+        // 创建canvas
+        let createCanvas = function (options) {
+            if (options.showLoading) {
+                uni.showLoading({
+                    title: options.loadingText,
+                    mask: true
+                });
+            }
+            var ctx = uni.createCanvasContext(options.canvasId, options.context);
+            var count = qrCodeAlg.getModuleCount();
+            var ratioSize = options.size;
+            var ratioImgSize = options.imageSize;
+            //计算每个点的长宽
+            var tileW = (ratioSize / count).toPrecision(4);
+            var tileH = (ratioSize / count).toPrecision(4);
+            //绘制
+            for (var row = 0; row < count; row++) {
+                for (var col = 0; col < count; col++) {
+                    var w = (Math.ceil((col + 1) * tileW) - Math.floor(col * tileW));
+                    var h = (Math.ceil((row + 1) * tileW) - Math.floor(row * tileW));
+                    var foreground = getForeGround({
+                        row: row,
+                        col: col,
+                        count: count,
+                        options: options
+                    });
+                    ctx.setFillStyle(qrCodeAlg.modules[row][col] ? foreground : options.background);
+                    ctx.fillRect(Math.round(col * tileW), Math.round(row * tileH), w, h);
+                }
+            }
+            if (options.image) {
+                var x = Number(((ratioSize - ratioImgSize) / 2).toFixed(2));
+                var y = Number(((ratioSize - ratioImgSize) / 2).toFixed(2));
+                drawRoundedRect(ctx, x, y, ratioImgSize, ratioImgSize, 2, 6, true, true)
+                ctx.drawImage(options.image, x, y, ratioImgSize, ratioImgSize);
+                // 画圆角矩形
+                function drawRoundedRect(ctxi, x, y, width, height, r, lineWidth, fill, stroke) {
+                    ctxi.setLineWidth(lineWidth);
+                    ctxi.setFillStyle(options.background);
+                    ctxi.setStrokeStyle(options.background);
+                    ctxi.beginPath(); // draw top and top right corner 
+                    ctxi.moveTo(x + r, y);
+                    ctxi.arcTo(x + width, y, x + width, y + r, r); // draw right side and bottom right corner 
+                    ctxi.arcTo(x + width, y + height, x + width - r, y + height, r); // draw bottom and bottom left corner 
+                    ctxi.arcTo(x, y + height, x, y + height - r, r); // draw left and top left corner 
+                    ctxi.arcTo(x, y, x + r, y, r);
+                    ctxi.closePath();
+                    if (fill) {
+                        ctxi.fill();
+                    }
+                    if (stroke) {
+                        ctxi.stroke();
+                    }
+                }
+            }
+            setTimeout(() => {
+                ctx.draw(true, () => {
+                    // 保存到临时区域
+                    setTimeout(() => {
+                        uni.canvasToTempFilePath({
+                            width: options.width,
+                            height: options.height,
+                            destWidth: options.width,
+                            destHeight: options.height,
+                            canvasId: options.canvasId,
+                            quality: Number(1),
+                            success: function (res) {
+                                if (options.cbResult) {
+                                    options.cbResult(res.tempFilePath)
+                                }
+                            },
+                            fail: function (res) {
+                                if (options.cbResult) {
+                                    options.cbResult(res)
+                                }
+                            },
+                            complete: function () {
+                                if (options.showLoading){
+                                    uni.hideLoading();
+                                }
+                            },
+                        }, options.context);
+                    }, options.text.length + 100);
+                });
+            }, options.usingComponents ? 0 : 150);
+        }
+        createCanvas(this.options);
+        // 空判定
+        let empty = function (v) {
+            let tp = typeof v,
+                rt = false;
+            if (tp == "number" && String(v) == "") {
+                rt = true
+            } else if (tp == "undefined") {
+                rt = true
+            } else if (tp == "object") {
+                if (JSON.stringify(v) == "{}" || JSON.stringify(v) == "[]" || v == null) rt = true
+            } else if (tp == "string") {
+                if (v == "" || v == "undefined" || v == "null" || v == "{}" || v == "[]") rt = true
+            } else if (tp == "function") {
+                rt = false
+            }
+            return rt
+        }
+    };
+    QRCode.prototype.clear = function (fn) {
+        var ctx = uni.createCanvasContext(this.options.canvasId, this.options.context)
+        ctx.clearRect(0, 0, this.options.size, this.options.size)
+        ctx.draw(false, () => {
+            if (fn) {
+                fn()
+            }
+        })
+    };
+})()
+
+export default QRCode

+ 210 - 0
components/tki-qrcode/tki-qrcode.vue

@@ -0,0 +1,210 @@
+<template xlang="wxml" minapp="mpvue">
+	<view class="tki-qrcode">
+		<!-- #ifndef MP-ALIPAY -->
+		<canvas class="tki-qrcode-canvas" :canvas-id="cid" :style="{width:cpSize+'px',height:cpSize+'px'}" />
+		<!-- #endif -->
+		<!-- #ifdef MP-ALIPAY -->
+		<canvas :id="cid" :width="cpSize" :height="cpSize" class="tki-qrcode-canvas" />
+		<!-- #endif -->
+		<image v-show="show" :src="result" :style="{width:cpSize+'px',height:cpSize+'px'}" />
+	</view>
+</template>
+
+<script>
+import QRCode from "./qrcode.js"
+let qrcode
+export default {
+	name: "tki-qrcode",
+	props: {
+		cid: {
+			type: String,
+			default: 'tki-qrcode-canvas'
+		},
+		size: {
+			type: Number,
+			default: 200
+		},
+		unit: {
+			type: String,
+			default: 'upx'
+		},
+		show: {
+			type: Boolean,
+			default: true
+		},
+		val: {
+			type: String,
+			default: ''
+		},
+		background: {
+			type: String,
+			default: '#ffffff'
+		},
+		foreground: {
+			type: String,
+			default: '#000000'
+		},
+		pdground: {
+			type: String,
+			default: '#000000'
+		},
+		icon: {
+			type: String,
+			default: ''
+		},
+		iconSize: {
+			type: Number,
+			default: 40
+		},
+		lv: {
+			type: Number,
+			default: 3
+		},
+		onval: {
+			type: Boolean,
+			default: false
+		},
+		loadMake: {
+			type: Boolean,
+			default: false
+		},
+		usingComponents: {
+			type: Boolean,
+			default: true
+		},
+		showLoading: {
+			type: Boolean,
+			default: true
+		},
+		loadingText: {
+			type: String,
+			default: '二维码生成中'
+		},
+	},
+	data() {
+		return {
+			result: '',
+		}
+	},
+	methods: {
+		_makeCode() {
+			let that = this
+			if (!this._empty(this.val)) {
+				qrcode = new QRCode({
+					context: that, // 上下文环境
+					canvasId:that.cid, // canvas-id
+					usingComponents: that.usingComponents, // 是否是自定义组件
+					showLoading: that.showLoading, // 是否显示loading
+					loadingText: that.loadingText, // loading文字
+					text: that.val, // 生成内容
+					size: that.cpSize, // 二维码大小
+					background: that.background, // 背景色
+					foreground: that.foreground, // 前景色
+					pdground: that.pdground, // 定位角点颜色
+					correctLevel: that.lv, // 容错级别
+					image: that.icon, // 二维码图标
+					imageSize: that.iconSize,// 二维码图标大小
+					cbResult: function (res) { // 生成二维码的回调
+						that._result(res)
+					},
+				});
+			} else {
+				uni.showToast({
+					title: '二维码内容不能为空',
+					icon: 'none',
+					duration: 2000
+				});
+			}
+		},
+		_clearCode() {
+			this._result('')
+			qrcode.clear()
+		},
+		_saveCode() {
+			let that = this;
+			if (this.result != "") {
+				uni.saveImageToPhotosAlbum({
+					filePath: that.result,
+					success: function () {
+						uni.showToast({
+							title: '二维码保存成功',
+							icon: 'success',
+							duration: 2000
+						});
+					}
+				});
+			}
+		},
+		_result(res) {
+			this.result = res;
+			this.$emit('result', res)
+		},
+		_empty(v) {
+			let tp = typeof v,
+				rt = false;
+			if (tp == "number" && String(v) == "") {
+				rt = true
+			} else if (tp == "undefined") {
+				rt = true
+			} else if (tp == "object") {
+				if (JSON.stringify(v) == "{}" || JSON.stringify(v) == "[]" || v == null) rt = true
+			} else if (tp == "string") {
+				if (v == "" || v == "undefined" || v == "null" || v == "{}" || v == "[]") rt = true
+			} else if (tp == "function") {
+				rt = false
+			}
+			return rt
+		}
+	},
+	watch: {
+		size: function (n, o) {
+			if (n != o && !this._empty(n)) {
+				this.cSize = n
+				if (!this._empty(this.val)) {
+					setTimeout(() => {
+						this._makeCode()
+					}, 100);
+				}
+			}
+		},
+		val: function (n, o) {
+			if (this.onval) {
+				if (n != o && !this._empty(n)) {
+					setTimeout(() => {
+						this._makeCode()
+					}, 0);
+				}
+			}
+		}
+	},
+	computed: {
+		cpSize() {
+			if(this.unit == "upx"){
+				return uni.upx2px(this.size)
+			}else{
+				return this.size
+			}
+		}
+	},
+	mounted: function () {
+		if (this.loadMake) {
+			if (!this._empty(this.val)) {
+				setTimeout(() => {
+					this._makeCode()
+				}, 0);
+			}
+		}
+	},
+}
+</script>
+<style>
+.tki-qrcode {
+  position: relative;
+}
+.tki-qrcode-canvas {
+  position: fixed;
+  top: -99999upx;
+  left: -99999upx;
+  z-index: -99999;
+}
+</style>

+ 122 - 0
components/uni-badge/uni-badge.vue

@@ -0,0 +1,122 @@
+<template>
+	<text v-if="text" :class="inverted ? 'uni-badge--' + type + ' uni-badge--' + size + ' uni-badge--' + type + '-inverted' : 'uni-badge--' + type + ' uni-badge--' + size"
+	 class="uni-badge" :style="width" @click="onClick()">{{ text }}</text>
+</template>
+
+<script>
+	export default {
+		name: 'UniBadge',
+		props: {
+			type: {
+				type: String,
+				default: 'default'
+			},
+			inverted: {
+				type: Boolean,
+				default: false
+			},
+			text: {
+				type: [String,Number],
+				default: ''
+			},
+			size: {
+				// small.normal
+				type: String,
+				default: 'normal'
+			}
+		},
+		data() {
+			return {
+				width: `display: inline-block;width: ${String(this.text).length * 15 + 25}rpx`
+			};
+		},
+		methods: {
+			onClick() {
+				this.$emit('click');
+			}
+		}
+	};
+</script>
+
+<style lang="scss" scoped>
+	$bage-size: 12px;
+	$bage-small: scale(0.8);
+	$bage-height: 40rpx;
+
+	.uni-badge {
+		/* #ifndef APP-PLUS */
+		display: flex;
+		/* #endif */
+		flex-direction: row;
+		height: $bage-height;
+		line-height: $bage-height;
+		color: $uni-text-color;
+		border-radius: 100px;
+		background-color: $uni-bg-color-hover;
+		background-color: transparent;
+		text-align: center;
+		font-family: 'Helvetica Neue', Helvetica, sans-serif;
+		font-size: $bage-size;
+		padding: 0;
+	}
+
+	.uni-badge--inverted {
+		padding: 0 5px 0 0;
+		color: $uni-bg-color-hover;
+	}
+
+	.uni-badge--default {
+		color: $uni-text-color;
+		background-color: $uni-bg-color-hover;
+	}
+
+	.uni-badge--default-inverted {
+		color: $uni-text-color-grey;
+		background-color: transparent;
+	}
+
+	.uni-badge--primary {
+		color: $uni-text-color-inverse;
+		background-color: $uni-color-primary;
+	}
+
+	.uni-badge--primary-inverted {
+		color: $uni-color-primary;
+		background-color: transparent;
+	}
+
+	.uni-badge--success {
+		color: $uni-text-color-inverse;
+		background-color: $uni-color-success;
+	}
+
+	.uni-badge--success-inverted {
+		color: $uni-color-success;
+		background-color: transparent;
+	}
+
+	.uni-badge--warning {
+		color: $uni-text-color-inverse;
+		background-color: $uni-color-warning;
+	}
+
+	.uni-badge--warning-inverted {
+		color: $uni-color-warning;
+		background-color: transparent;
+	}
+
+	.uni-badge--error {
+		color: $uni-text-color-inverse;
+		background-color: $uni-color-error;
+	}
+
+	.uni-badge--error-inverted {
+		color: $uni-color-error;
+		background-color: transparent;
+	}
+
+	.uni-badge--small {
+		transform: $bage-small;
+		transform-origin: center center;
+	}
+</style>

+ 188 - 0
components/uni-countdown/uni-countdown.vue

@@ -0,0 +1,188 @@
+<template>
+	<view class="uni-countdown">
+		<text v-if="showDay" :style="{ borderColor: borderColor, color: color, backgroundColor: backgroundColor }" class="uni-countdown__number">{{ d }}</text>
+		<text v-if="showDay" :style="{ color: splitorColor }" class="uni-countdown__splitor">天</text>
+		<text :style="{ borderColor: borderColor, color: color, backgroundColor: backgroundColor }" class="uni-countdown__number">{{ h }}</text>
+		<text :style="{ color: splitorColor }" class="uni-countdown__splitor">{{ showColon ? ':' : '时' }}</text>
+		<text :style="{ borderColor: borderColor, color: color, backgroundColor: backgroundColor }" class="uni-countdown__number">{{ i }}</text>
+		<text :style="{ color: splitorColor }" class="uni-countdown__splitor">{{ showColon ? ':' : '分' }}</text>
+		<text :style="{ borderColor: borderColor, color: color, backgroundColor: backgroundColor }" class="uni-countdown__number">{{ s }}</text>
+		<text v-if="!showColon" :style="{ color: splitorColor }" class="uni-countdown__splitor">秒</text>
+	</view>
+</template>
+<script>
+	export default {
+		name: 'UniCountdown',
+		props: {
+			showDay: {
+				type: Boolean,
+				default: true
+			},
+			showColon: {
+				type: Boolean,
+				default: true
+			},
+			backgroundColor: {
+				type: String,
+				default: '#FFFFFF'
+			},
+			borderColor: {
+				type: String,
+				default: '#000000'
+			},
+			color: {
+				type: String,
+				default: '#000000'
+			},
+			splitorColor: {
+				type: String,
+				default: '#000000'
+			},
+			day: {
+				type: Number,
+				default: 0
+			},
+			hour: {
+				type: Number,
+				default: 0
+			},
+			minute: {
+				type: Number,
+				default: 0
+			},
+			second: {
+				type: Number,
+				default: 0
+			}
+		},
+		data() {
+			return {
+				timer: null,
+				syncFlag: false,
+				d: '00',
+				h: '00',
+				i: '00',
+				s: '00',
+				leftTime: 0,
+				seconds: 0
+			}
+		},
+		watch: {
+			day(val) {
+				this.changeFlag()
+			},
+			hour(val) {
+				this.changeFlag()
+			},
+			minute(val) {
+				this.changeFlag()
+			},
+			second(val) {
+				this.changeFlag()
+			}
+		},
+		created: function(e) {
+			this.startData();
+		},
+		beforeDestroy() {
+			clearInterval(this.timer)
+		},
+		methods: {
+			toSeconds(day, hours, minutes, seconds) {
+				return day * 60 * 60 * 24 + hours * 60 * 60 + minutes * 60 + seconds
+			},
+			timeUp() {
+				clearInterval(this.timer)
+				this.$emit('timeup')
+			},
+			countDown() {
+				let seconds = this.seconds
+				let [day, hour, minute, second] = [0, 0, 0, 0]
+				if (seconds > 0) {
+					day = Math.floor(seconds / (60 * 60 * 24))
+					hour = Math.floor(seconds / (60 * 60)) - (day * 24)
+					minute = Math.floor(seconds / 60) - (day * 24 * 60) - (hour * 60)
+					second = Math.floor(seconds) - (day * 24 * 60 * 60) - (hour * 60 * 60) - (minute * 60)
+				} else {
+					this.timeUp()
+				}
+				if (day < 10) {
+					day = '0' + day
+				}
+				if (hour < 10) {
+					hour = '0' + hour
+				}
+				if (minute < 10) {
+					minute = '0' + minute
+				}
+				if (second < 10) {
+					second = '0' + second
+				}
+				this.d = day
+				this.h = hour
+				this.i = minute
+				this.s = second
+			},
+			startData() {
+				this.seconds = this.toSeconds(this.day, this.hour, this.minute, this.second)
+				if (this.seconds <= 0) {
+					return
+				}
+				this.countDown()
+				this.timer = setInterval(() => {
+					this.seconds--
+					if (this.seconds < 0) {
+						this.timeUp()
+						return
+					}
+					this.countDown()
+				}, 1000)
+			},
+			changeFlag() {
+				if (!this.syncFlag) {
+					this.seconds = this.toSeconds(this.day, this.hour, this.minute, this.second)
+					this.startData();
+					this.syncFlag = true;
+				}
+			}
+		}
+	}
+</script>
+<style lang="scss" scoped>
+	@import '~@/uni.scss';
+	$countdown-height: 48rpx;
+	$countdown-width: 52rpx;
+
+	.uni-countdown {
+		/* #ifndef APP-NVUE */
+		display: flex;
+		/* #endif */
+		flex-direction: row;
+		justify-content: flex-start;
+		padding: 2rpx 0;
+	}
+
+	.uni-countdown__splitor {
+		/* #ifndef APP-NVUE */
+		display: flex;
+		/* #endif */
+		justify-content: center;
+		line-height: $countdown-height;
+		padding: 5rpx;
+		font-size: $uni-font-size-sm;
+	}
+
+	.uni-countdown__number {
+		/* #ifndef APP-NVUE */
+		display: flex;
+		/* #endif */
+		justify-content: center;
+		align-items: center;
+		width: $countdown-width;
+		height: $countdown-height;
+		line-height: $countdown-height;
+		margin: 5rpx;
+		text-align: center;
+		font-size: $uni-font-size-sm;
+	}
+</style>

+ 96 - 0
components/uni-icons/icons.js

@@ -0,0 +1,96 @@
+export default {
+	'contact': '\ue100',
+	'person': '\ue101',
+	'personadd': '\ue102',
+	'contact-filled': '\ue130',
+	'person-filled': '\ue131',
+	'personadd-filled': '\ue132',
+	'phone': '\ue200',
+	'email': '\ue201',
+	'chatbubble': '\ue202',
+	'chatboxes': '\ue203',
+	'phone-filled': '\ue230',
+	'email-filled': '\ue231',
+	'chatbubble-filled': '\ue232',
+	'chatboxes-filled': '\ue233',
+	'weibo': '\ue260',
+	'weixin': '\ue261',
+	'pengyouquan': '\ue262',
+	'chat': '\ue263',
+	'qq': '\ue264',
+	'videocam': '\ue300',
+	'camera': '\ue301',
+	'mic': '\ue302',
+	'location': '\ue303',
+	'mic-filled': '\ue332',
+	'speech': '\ue332',
+	'location-filled': '\ue333',
+	'micoff': '\ue360',
+	'image': '\ue363',
+	'map': '\ue364',
+	'compose': '\ue400',
+	'trash': '\ue401',
+	'upload': '\ue402',
+	'download': '\ue403',
+	'close': '\ue404',
+	'redo': '\ue405',
+	'undo': '\ue406',
+	'refresh': '\ue407',
+	'star': '\ue408',
+	'plus': '\ue409',
+	'minus': '\ue410',
+	'circle': '\ue411',
+	'checkbox': '\ue411',
+	'close-filled': '\ue434',
+	'clear': '\ue434',
+	'refresh-filled': '\ue437',
+	'star-filled': '\ue438',
+	'plus-filled': '\ue439',
+	'minus-filled': '\ue440',
+	'circle-filled': '\ue441',
+	'checkbox-filled': '\ue442',
+	'closeempty': '\ue460',
+	'refreshempty': '\ue461',
+	'reload': '\ue462',
+	'starhalf': '\ue463',
+	'spinner': '\ue464',
+	'spinner-cycle': '\ue465',
+	'search': '\ue466',
+	'plusempty': '\ue468',
+	'forward': '\ue470',
+	'back': '\ue471',
+	'left-nav': '\ue471',
+	'checkmarkempty': '\ue472',
+	'home': '\ue500',
+	'navigate': '\ue501',
+	'gear': '\ue502',
+	'paperplane': '\ue503',
+	'info': '\ue504',
+	'help': '\ue505',
+	'locked': '\ue506',
+	'more': '\ue507',
+	'flag': '\ue508',
+	'home-filled': '\ue530',
+	'gear-filled': '\ue532',
+	'info-filled': '\ue534',
+	'help-filled': '\ue535',
+	'more-filled': '\ue537',
+	'settings': '\ue560',
+	'list': '\ue562',
+	'bars': '\ue563',
+	'loop': '\ue565',
+	'paperclip': '\ue567',
+	'eye': '\ue568',
+	'arrowup': '\ue580',
+	'arrowdown': '\ue581',
+	'arrowleft': '\ue582',
+	'arrowright': '\ue583',
+	'arrowthinup': '\ue584',
+	'arrowthindown': '\ue585',
+	'arrowthinleft': '\ue586',
+	'arrowthinright': '\ue587',
+	'pulldown': '\ue588',
+	'closefill': '\ue589',
+	'sound': '\ue590',
+	'scan': '\ue612'
+}

파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 10 - 0
components/uni-icons/uni-icons.vue


+ 230 - 0
components/uni-list-item/uni-list-item.vue

@@ -0,0 +1,230 @@
+<template>
+	<!-- #ifdef APP-NVUE -->
+	<cell>
+	<!-- #endif -->
+	<view :class="disabled ? 'uni-list-item--disabled' : ''" :hover-class="disabled || showSwitch ? '' : 'uni-list-item--hover'"
+	 class="uni-list-item" @click="onClick">
+		<view class="uni-list-item__container" :class="{'uni-list-item--first':isFirstChild}">
+			<view v-if="thumb" class="uni-list-item__icon">
+				<image :src="thumb" mode="aspectFit" class="uni-list-item__icon-img" />
+			</view>
+			<view v-else-if="showExtraIcon" class="uni-list-item__icon">
+				<uni-icons :color="extraIcon.color" :size="extraIcon.size" :type="extraIcon.type" class="uni-icon-wrapper" />
+			</view>
+			<view class="uni-list-item__content">
+				<slot></slot>
+				<text class="uni-list-item__content-title">{{ title }}</text>
+				<text v-if="note" class="uni-list-item__content-note">{{ note }}</text>
+			</view>
+			<view class="uni-list-item__slot">
+				<slot name="right" ></slot>
+			</view>
+			<view v-if="showBadge || showArrow || showSwitch" class="uni-list-item__extra">
+				<uni-badge v-if="showBadge" :type="badgeType" :text="badgeText" />
+				<switch class="itemSwitch" v-if="showSwitch" :color="switchColor" :disabled="disabled" :checked="switchChecked" @change="onSwitchChange" />
+				<uni-icons v-if="showArrow" :size="20" class="uni-icon-wrapper" color="#bbb" type="arrowright" />
+			</view>
+		</view>
+	</view>
+	<!-- #ifdef APP-NVUE -->
+	</cell>
+	<!-- #endif -->
+</template>
+
+<script>
+	import uniIcons from '../uni-icons/uni-icons.vue'
+	import uniBadge from '../uni-badge/uni-badge.vue'
+	export default {
+		name: 'UniListItem',
+		components: {
+			uniIcons,
+			uniBadge
+		},
+		props: {
+			title: {
+				type: String,
+				default: ''
+			}, // 列表标题
+			note: {
+				type: String,
+				default: ''
+			}, // 列表描述
+			disabled: {
+				// 是否禁用
+				type: [Boolean, String],
+				default: false
+			},
+			showArrow: {
+				// 是否显示箭头
+				type: [Boolean, String],
+				default: true
+			},
+			showBadge: {
+				// 是否显示数字角标
+				type: [Boolean, String],
+				default: false
+			},
+			showSwitch: {
+				// 是否显示Switch
+				type: [Boolean, String],
+				default: false
+			},
+			switchChecked: {
+				// Switch是否被选中
+				type: [Boolean, String],
+				default: false
+			},
+			switchColor:{
+				type:String,
+				default:''
+			},
+			badgeText: {
+				// badge内容
+				type: String,
+				default: ''
+			},
+			badgeType: {
+				// badge类型
+				type: String,
+				default: 'success'
+			},
+			thumb: {
+				// 缩略图
+				type: String,
+				default: ''
+			},
+			showExtraIcon: {
+				// 是否显示扩展图标
+				type: [Boolean, String],
+				default: false
+			},
+			extraIcon: {
+				type: Object,
+				default () {
+					return {
+						type: 'contact',
+						color: '#000000',
+						size: 20
+					}
+				}
+			}
+		},
+		inject: ['list'],
+		data() {
+			return {
+				isFirstChild: false
+			}
+		},
+		mounted() {
+			if (!this.list.firstChildAppend) {
+				this.list.firstChildAppend = true
+				this.isFirstChild = true
+			}
+		},
+		methods: {
+			onClick() {
+				this.$emit('click')
+			},
+			onSwitchChange(e) {
+				this.$emit('switchChange', e.detail)
+			}
+		}
+	}
+</script>
+
+<style lang="scss" scoped>
+	@import '~@/uni.scss';
+
+	$list-item-pd: $uni-spacing-col-lg $uni-spacing-row-lg;
+
+	.uni-list-item {
+		font-size: $uni-font-size-lg;
+		position: relative;
+		flex-direction: column;
+		justify-content: space-between;
+		padding-left: $uni-spacing-row-lg;
+	}
+
+	.uni-list-item--disabled {
+		opacity: 0.3;
+	}
+
+	.uni-list-item--hover {
+		background-color: $uni-bg-color-hover;
+	}
+
+	.uni-list-item__container {
+		/* #ifndef APP-NVUE */
+		display: flex;
+		/* #endif */
+		flex-direction: row;
+		padding: $list-item-pd;
+		padding-left: 0;
+		flex: 1;
+		position: relative;
+		justify-content: space-between;
+		align-items: center;
+		border-top-color: $uni-border-color;
+		border-top-style: solid;
+		border-top-width: 1px;
+	}
+
+	.uni-list-item--first {
+		border-top-width: 0px;
+	}
+
+	.uni-list-item__content {
+		/* #ifndef APP-NVUE */
+		display: flex;
+		/* #endif */
+		flex: 1;
+		overflow: hidden;
+		flex-direction: column;
+		color: #3b4144;
+
+	}
+
+	.uni-list-item__content-title {
+		font-size: $uni-font-size-base;
+		color: #3b4144;
+		overflow: hidden;
+	}
+
+	.uni-list-item__content-note {
+		margin-top: 6rpx;
+		color: $uni-text-color-grey;
+		font-size: $uni-font-size-sm;
+		overflow: hidden;
+	}
+
+	.uni-list-item__extra {
+		// width: 25%;
+		/* #ifndef APP-NVUE */
+		display: flex;
+		/* #endif */
+		flex-direction: row;
+		justify-content: flex-end;
+		align-items: center;
+	}
+
+	.uni-list-item__icon {
+		margin-right: 18rpx;
+		flex-direction: row;
+		justify-content: center;
+		align-items: center;
+		display: flex;
+	}
+
+	.uni-list-item__icon-img {
+		height: $uni-img-size-base;
+		width: $uni-img-size-base;
+	}
+	// 修改switch默认大小
+	.itemSwitch{
+		transform: translateX(16rpx) scale(.84);
+	}
+	.uni-list-item__slot{
+		color: #909399;
+		font-size: 28rpx;
+	}
+</style>

+ 68 - 0
components/uni-list/uni-list.vue

@@ -0,0 +1,68 @@
+<template>
+	<!-- #ifndef APP-NVUE -->
+	<view class="uni-list">
+		<slot />
+	</view>
+	<!-- #endif -->
+	<!-- #ifdef APP-NVUE -->
+	<list class="uni-list" :enableBackToTop="enableBackToTop" loadmoreoffset="15" :scroll-y="scrollY" @loadmore="loadMore">
+		<slot />
+	</list>
+	<!-- #endif -->
+</template>
+
+<script>
+	export default {
+		name: 'UniList',
+		'mp-weixin': {
+			options: {
+				multipleSlots: false
+			}
+		},
+		props: {
+			enableBackToTop: {
+				type: [Boolean, String],
+				default: false
+			},
+			scrollY: {
+				type: [Boolean, String],
+				default: false
+			}
+		},
+		provide() {
+			return {
+				list: this
+			}
+		},
+		created() {
+			this.firstChildAppend = false
+		},
+		methods: {
+			loadMore(e) {
+				this.$emit("scrolltolower");
+			}
+		}
+	}
+</script>
+<style lang="scss" scoped>
+	.uni-list {
+		/* #ifndef APP-NVUE */
+		display: flex;
+		/* #endif */
+		background-color: $uni-bg-color;
+		position: relative;
+		flex-direction: column;
+		// border-bottom-color: $uni-border-color;
+		// border-bottom-style: solid;
+		// border-bottom-width: 1px;
+	}
+	/* #ifndef APP-NVUE */
+	.uni-list:before {
+		height: 0;
+	}
+	.uni-list:after {
+		height: 0;
+	}
+	/* #endif */
+
+</style>

+ 65 - 0
components/uni-list/uni-refresh.vue

@@ -0,0 +1,65 @@
+<template>
+    <!-- #ifdef APP-NVUE -->
+    <refresh :display="display" @refresh="onrefresh" @pullingdown="onpullingdown">
+        <slot />
+    </refresh>
+    <!-- #endif -->
+    <!-- #ifndef APP-NVUE -->
+    <view ref="uni-refresh" class="uni-refresh" v-show="isShow">
+        <slot />
+    </view>
+    <!-- #endif -->
+</template>
+
+<script>
+    export default {
+        name: 'UniRefresh',
+        props: {
+            display: {
+                type: [String],
+                default: "hide"
+            }
+        },
+        data() {
+            return {
+                pulling: false
+            }
+        },
+        computed: {
+            isShow() {
+                if (this.display === "show" || this.pulling === true) {
+                    return true;
+                }
+                return false;
+            }
+        },
+        created() {},
+        methods: {
+            onchange(value) {
+                this.pulling = value;
+            },
+            onrefresh(e) {
+                this.$emit("refresh", e);
+            },
+            onpullingdown(e) {
+                // #ifdef APP-NVUE
+                this.$emit("pullingdown", e);
+                // #endif
+                // #ifndef APP-NVUE
+                var detail = {
+                    viewHeight: 90,
+                    pullingDistance: e.height
+                }
+                this.$emit("pullingdown", detail);
+                // #endif
+            }
+        }
+    }
+</script>
+
+<style>
+    .uni-refresh {
+        height: 0;
+        overflow: hidden;
+    }
+</style>

+ 87 - 0
components/uni-list/uni-refresh.wxs

@@ -0,0 +1,87 @@
+var pullDown = {
+    threshold: 95,
+    maxHeight: 200,
+    callRefresh: 'onrefresh',
+    callPullingDown: 'onpullingdown',
+    refreshSelector: '.uni-refresh'
+};
+
+function ready(newValue, oldValue, ownerInstance, instance) {
+    var state = instance.getState()
+    state.canPullDown = newValue;
+    console.log(newValue);
+}
+
+function touchStart(e, instance) {
+    var state = instance.getState();
+    state.refreshInstance = instance.selectComponent(pullDown.refreshSelector);
+    state.canPullDown = (state.refreshInstance != null && state.refreshInstance != undefined);
+    if (!state.canPullDown) {
+        return
+    }
+
+    console.log("touchStart");
+
+    state.height = 0;
+    state.touchStartY = e.touches[0].pageY || e.changedTouches[0].pageY;
+    state.refreshInstance.setStyle({
+        'height': 0
+    });
+    state.refreshInstance.callMethod("onchange", true);
+}
+
+function touchMove(e, ownerInstance) {
+    var instance = e.instance;
+    var state = instance.getState();
+    if (!state.canPullDown) {
+        return
+    }
+
+    var oldHeight = state.height;
+    var endY = e.touches[0].pageY || e.changedTouches[0].pageY;
+    var height = endY - state.touchStartY;
+    if (height > pullDown.maxHeight) {
+        return;
+    }
+
+    var refreshInstance = state.refreshInstance;
+    refreshInstance.setStyle({
+        'height': height + 'px'
+    });
+
+    height = height < pullDown.maxHeight ? height : pullDown.maxHeight;
+    state.height = height;
+    refreshInstance.callMethod(pullDown.callPullingDown, {
+        height: height
+    });
+}
+
+function touchEnd(e, ownerInstance) {
+    var state = e.instance.getState();
+    if (!state.canPullDown) {
+        return
+    }
+
+    state.refreshInstance.callMethod("onchange", false);
+
+    var refreshInstance = state.refreshInstance;
+    if (state.height > pullDown.threshold) {
+        refreshInstance.callMethod(pullDown.callRefresh);
+        return;
+    }
+
+    refreshInstance.setStyle({
+        'height': 0
+    });
+}
+
+function propObserver(newValue, oldValue, instance) {
+    pullDown = newValue;
+}
+
+module.exports = {
+    touchmove: touchMove,
+    touchstart: touchStart,
+    touchend: touchEnd,
+    propObserver: propObserver
+}

+ 194 - 0
components/uni-load-more/uni-load-more.vue

@@ -0,0 +1,194 @@
+<template>
+	<view class="uni-load-more">
+		<view class="uni-load-more__img" v-show="status === 'loading' && showIcon">
+			<view class="load1 load">
+				<view class="item" :style="{background:color}"></view>
+				<view class="item" :style="{background:color}"></view>
+				<view class="item" :style="{background:color}"></view>
+				<view class="item" :style="{background:color}"></view>
+			</view>
+			<view class="load2 load">
+				<view class="item" :style="{background:color}"></view>
+				<view class="item"  :style="{background:color}"></view>
+				<view class="item" :style="{background:color}"></view>
+				<view class="item" :style="{background:color}"></view>
+			</view>
+			<view class="load3 load">
+				<view class="item" :style="{background:color}"></view>
+				<view class="item" :style="{background:color}"></view>
+				<view class="item" :style="{background:color}"></view>
+				<view class="item" :style="{background:color}"></view>
+			</view>
+		</view>
+		<text class="uni-load-more__text" :style="{color:color}">{{status === 'more' ? contentText.contentdown : (status === 'loading' ? contentText.contentrefresh : contentText.contentnomore)}}</text>
+	</view>
+</template>
+
+<script>
+	export default {
+		name: "uni-load-more",
+		props: {
+			status: {
+				//上拉的状态:more-loading前;loading-loading中;noMore-没有更多了
+				type: String,
+				default: 'more'
+			},
+			showIcon: {
+				type: Boolean,
+				default: true
+			},
+			color: {
+				type: String,
+				default: "#777777"
+			},
+			contentText: {
+				type: Object,
+				default () {
+					return {
+						contentdown: "上拉显示更多",
+						contentrefresh: "正在加载...",
+						contentnomore: "没有更多数据了"
+					};
+				}
+			}
+		},
+		data() {
+			return {}
+		}
+	}
+</script>
+
+<style>
+	@charset "UTF-8";
+
+	.uni-load-more {
+		display: flex;
+		flex-direction: row;
+		height: 80upx;
+		align-items: center;
+		justify-content: center
+	}
+
+	.uni-load-more__text {
+		font-size: 28upx;
+		color: #999
+	}
+
+	.uni-load-more__img {
+		height: 24px;
+		width: 24px;
+		margin-right: 10px
+	}
+
+	.uni-load-more__img>.load {
+		position: absolute
+	}
+
+	.uni-load-more__img>.load .item {
+		width: 6px;
+		height: 2px;
+		border-top-left-radius: 1px;
+		border-bottom-left-radius: 1px;
+		background: #999;
+		position: absolute;
+		opacity: .2;
+		transform-origin: 50%;
+		animation: load 1.56s ease infinite
+	}
+
+	.uni-load-more__img>.load .item:nth-child(1) {
+		transform: rotate(90deg);
+		top: 2px;
+		left: 9px
+	}
+
+	.uni-load-more__img>.load .item:nth-child(2) {
+		transform: rotate(180deg);
+		top: 11px;
+		right: 0
+	}
+
+	.uni-load-more__img>.load .item:nth-child(3) {
+		transform: rotate(270deg);
+		bottom: 2px;
+		left: 9px
+	}
+
+	.uni-load-more__img>.load .item:nth-child(4) {
+		top: 11px;
+		left: 0
+	}
+
+	.load1,
+	.load2,
+	.load3 {
+		height: 24px;
+		width: 24px
+	}
+
+	.load2 {
+		transform: rotate(30deg)
+	}
+
+	.load3 {
+		transform: rotate(60deg)
+	}
+
+	.load1 .item:nth-child(1) {
+		animation-delay: 0s
+	}
+
+	.load2 .item:nth-child(1) {
+		animation-delay: .13s
+	}
+
+	.load3 .item:nth-child(1) {
+		animation-delay: .26s
+	}
+
+	.load1 .item:nth-child(2) {
+		animation-delay: .39s
+	}
+
+	.load2 .item:nth-child(2) {
+		animation-delay: .52s
+	}
+
+	.load3 .item:nth-child(2) {
+		animation-delay: .65s
+	}
+
+	.load1 .item:nth-child(3) {
+		animation-delay: .78s
+	}
+
+	.load2 .item:nth-child(3) {
+		animation-delay: .91s
+	}
+
+	.load3 .item:nth-child(3) {
+		animation-delay: 1.04s
+	}
+
+	.load1 .item:nth-child(4) {
+		animation-delay: 1.17s
+	}
+
+	.load2 .item:nth-child(4) {
+		animation-delay: 1.3s
+	}
+
+	.load3 .item:nth-child(4) {
+		animation-delay: 1.43s
+	}
+
+	@-webkit-keyframes load {
+		0% {
+			opacity: 1
+		}
+
+		100% {
+			opacity: .2
+		}
+	}
+</style>

+ 396 - 0
components/uni-notice-bar/uni-notice-bar.vue

@@ -0,0 +1,396 @@
+<template>
+	<view v-if="show" class="uni-noticebar" :style="{ backgroundColor: backgroundColor }" @click="onClick">
+		<!-- #ifdef MP-ALIPAY -->
+		<view v-if="showClose === true || showClose === 'true'" class="uni-noticebar-close" @click="close">
+			<uni-icons type="closefill" :color="color" size="12" />
+		</view>
+		<view v-if="showIcon === true || showIcon === 'true'" class="uni-noticebar-icon">
+			<uni-icons type="sound" :color="color" size="14" />
+		</view>
+		<!-- #endif -->
+		<!-- #ifndef MP-ALIPAY -->
+		<uni-icons v-if="showClose === true || showClose === 'true'" class="uni-noticebar-close" type="closefill" :color="color"
+		 size="12" @click="close" />
+		<uni-icons v-if="showIcon === true || showIcon === 'true'" class="uni-noticebar-icon" type="sound" :color="color"
+		 size="14" />
+		<!-- #endif -->
+		<view ref="textBox" class="uni-noticebar__content-wrapper" :class="{'uni-noticebar__content-wrapper--scrollable':scrollable, 'uni-noticebar__content-wrapper--single':!scrollable && (single || moreText)}">
+			<view :id="elIdBox" class="uni-noticebar__content" :class="{'uni-noticebar__content--scrollable':scrollable, 'uni-noticebar__content--single':!scrollable && (single || moreText)}">
+				<text :id="elId" ref="animationEle" class="uni-noticebar__content-text" :class="{'uni-noticebar__content-text--scrollable':scrollable,'uni-noticebar__content-text--single':!scrollable && (single || moreText)}"
+				 :style="{color:color, width:wrapWidth+'px', 'animationDuration': animationDuration, '-webkit-animationDuration': animationDuration ,animationPlayState: webviewHide?'paused':animationPlayState,'-webkit-animationPlayState':webviewHide?'paused':animationPlayState, animationDelay: animationDelay, '-webkit-animationDelay':animationDelay}">{{text}}</text>
+			</view>
+		</view>
+		<view v-if="showGetMore === true || showGetMore === 'true'" class="uni-noticebar__more" @click="clickMore">
+			<text v-if="moreText" :style="{ color: moreColor }" class="uni-noticebar__more-text">{{ moreText }}</text>
+			<uni-icons type="arrowright" :color="moreColor" size="14" />
+		</view>
+	</view>
+</template>
+
+<script>
+	import uniIcons from '../uni-icons/uni-icons.vue'
+	// #ifdef APP-NVUE
+	const dom = weex.requireModule('dom');
+	const animation = weex.requireModule('animation');
+	// #endif
+
+	/**
+	 * NoticeBar 自定义导航栏
+	 * @description 通告栏组件
+	 * @tutorial https://ext.dcloud.net.cn/plugin?id=30
+	 * @property {Number} speed 文字滚动的速度,默认100px/秒
+	 * @property {String} text 显示文字
+	 * @property {String} backgroundColor 背景颜色
+	 * @property {String} color 文字颜色
+	 * @property {String} moreColor 查看更多文字的颜色
+	 * @property {String} moreText 设置“查看更多”的文本
+	 * @property {Boolean} single = [true|false] 是否单行
+	 * @property {Boolean} scrollable = [true|false] 是否滚动,为true时,NoticeBar为单行
+	 * @property {Boolean} showIcon = [true|false] 是否显示左侧喇叭图标
+	 * @property {Boolean} showClose = [true|false] 是否显示左侧关闭按钮
+	 * @property {Boolean} showGetMore = [true|false] 是否显示右侧查看更多图标,为true时,NoticeBar为单行
+	 * @event {Function} click 点击 NoticeBar 触发事件
+	 * @event {Function} close 关闭 NoticeBar 触发事件
+	 * @event {Function} getmore 点击”查看更多“时触发事件
+	 */
+
+	export default {
+		name: 'UniNoticeBar',
+		components: {
+			uniIcons
+		},
+		props: {
+			text: {
+				type: String,
+				default: ''
+			},
+			moreText: {
+				type: String,
+				default: ''
+			},
+			backgroundColor: {
+				type: String,
+				default: '#fffbe8'
+			},
+			speed: {
+				// 默认1s滚动100px
+				type: Number,
+				default: 100
+			},
+			color: {
+				type: String,
+				default: '#de8c17'
+			},
+			moreColor: {
+				type: String,
+				default: '#999999'
+			},
+			single: {
+				// 是否单行
+				type: [Boolean, String],
+				default: false
+			},
+			scrollable: {
+				// 是否滚动,添加后控制单行效果取消
+				type: [Boolean, String],
+				default: false
+			},
+			showIcon: {
+				// 是否显示左侧icon
+				type: [Boolean, String],
+				default: false
+			},
+			showGetMore: {
+				// 是否显示右侧查看更多
+				type: [Boolean, String],
+				default: false
+			},
+			showClose: {
+				// 是否显示左侧关闭按钮
+				type: [Boolean, String],
+				default: false
+			}
+		},
+		data() {
+			const elId = `Uni_${Math.ceil(Math.random() * 10e5).toString(36)}`
+			const elIdBox = `Uni_${Math.ceil(Math.random() * 10e5).toString(36)}`
+			return {
+				textWidth: 0,
+				boxWidth: 0,
+				wrapWidth: '',
+				webviewHide: false,
+				// #ifdef APP-NVUE
+				stopAnimation: false,
+				// #endif
+				elId: elId,
+				elIdBox: elIdBox,
+				show: true,
+				animationDuration: 'none',
+				animationPlayState: 'paused',
+				animationDelay: '0s'
+			}
+		},
+		mounted() {
+			// #ifdef APP-PLUS
+			var pages = getCurrentPages();
+			var page = pages[pages.length - 1];
+			var currentWebview = page.$getAppWebview();
+			currentWebview.addEventListener('hide',()=>{
+				this.webviewHide = true
+			})
+			currentWebview.addEventListener('show',()=>{
+				this.webviewHide = false
+			})
+			// #endif
+			this.$nextTick(() => {
+				this.initSize()
+			})
+		},
+		// #ifdef APP-NVUE
+		beforeDestroy() {
+			this.stopAnimation = true
+		},
+		// #endif
+		methods: {
+			initSize() {
+				if (this.scrollable) {
+					// #ifndef APP-NVUE
+					let query = [],
+						boxWidth = 0,
+						textWidth = 0;
+					let textQuery = new Promise((resolve, reject) => {
+						uni.createSelectorQuery()
+							// #ifndef MP-ALIPAY
+							.in(this)
+							// #endif
+							.select(`#${this.elId}`)
+							.boundingClientRect()
+							.exec(ret => {
+								this.textWidth = ret[0].width
+								resolve()
+							})
+					})
+					let boxQuery = new Promise((resolve, reject) => {
+						uni.createSelectorQuery()
+							// #ifndef MP-ALIPAY
+							.in(this)
+							// #endif
+							.select(`#${this.elIdBox}`)
+							.boundingClientRect()
+							.exec(ret => {
+								this.boxWidth = ret[0].width
+								resolve()
+							})
+					})
+					query.push(textQuery)
+					query.push(boxQuery)
+					Promise.all(query).then(() => {
+						this.animationDuration = `${this.textWidth / this.speed}s`
+						this.animationDelay = `-${this.boxWidth / this.speed}s`
+						setTimeout(() => {
+							this.animationPlayState = 'running'
+						}, 1000)
+					})
+					// #endif
+					// #ifdef APP-NVUE
+					dom.getComponentRect(this.$refs['animationEle'], (res) => {
+						let winWidth = uni.getSystemInfoSync().windowWidth
+						this.textWidth = res.size.width
+						animation.transition(this.$refs['animationEle'], {
+							styles: {
+								transform: `translateX(-${winWidth}px)`
+							},
+							duration: 0,
+							timingFunction: 'linear',
+							delay: 0
+						}, () => {
+							if (!this.stopAnimation) {
+								animation.transition(this.$refs['animationEle'], {
+									styles: {
+										transform: `translateX(-${this.textWidth}px)`
+									},
+									timingFunction: 'linear',
+									duration: (this.textWidth - winWidth) / this.speed * 1000,
+									delay: 1000
+								}, () => {
+									if (!this.stopAnimation) {
+										this.loopAnimation()
+									}
+								});
+							}
+						});
+					})
+					// #endif
+				}
+				// #ifdef APP-NVUE
+				if (!this.scrollable && (this.single || this.moreText)) {
+					dom.getComponentRect(this.$refs['textBox'], (res) => {
+						this.wrapWidth = res.size.width
+					})
+				}
+				// #endif
+			},
+			loopAnimation() {
+				// #ifdef APP-NVUE
+				animation.transition(this.$refs['animationEle'], {
+					styles: {
+						transform: `translateX(0px)`
+					},
+					duration: 0
+				}, () => {
+					if (!this.stopAnimation) {
+						animation.transition(this.$refs['animationEle'], {
+							styles: {
+								transform: `translateX(-${this.textWidth}px)`
+							},
+							duration: this.textWidth / this.speed * 1000,
+							timingFunction: 'linear',
+							delay: 0
+						}, () => {
+							if (!this.stopAnimation) {
+								this.loopAnimation()
+							}
+						});
+					}
+				});
+				// #endif
+			},
+			clickMore() {
+				this.$emit('getmore')
+			},
+			close() {
+				this.show = false;
+				this.$emit('close')
+			},
+			onClick() {
+				this.$emit('click')
+			}
+		}
+	}
+</script>
+
+<style lang="scss" scoped>
+	@import '@/uni.scss';
+
+	.uni-noticebar {
+		/* #ifndef APP-NVUE */
+		display: flex;
+		width: 100%;
+		box-sizing: border-box;
+		/* #endif */
+		flex-direction: row;
+		align-items: center;
+		padding: 6px 12px;
+		margin-bottom: 10px;
+	}
+
+	.uni-noticebar-close {
+		margin-right: 5px;
+	}
+
+	.uni-noticebar-icon {
+		margin-right: 5px;
+	}
+
+	.uni-noticebar__content-wrapper {
+		flex: 1;
+		flex-direction: column;
+		overflow: hidden;
+	}
+
+	.uni-noticebar__content-wrapper--single {
+		/* #ifndef APP-NVUE */
+		line-height: 18px;
+		/* #endif */
+	}
+
+	.uni-noticebar__content-wrapper--single,
+	.uni-noticebar__content-wrapper--scrollable {
+		flex-direction: row;
+	}
+
+	/* #ifndef APP-NVUE */
+	.uni-noticebar__content-wrapper--scrollable {
+		position: relative;
+		height: 18px;
+	}
+	/* #endif */
+
+	.uni-noticebar__content--scrollable {
+		/* #ifdef APP-NVUE */
+		flex: 0;
+		/* #endif */
+		/* #ifndef APP-NVUE */
+		flex: 1;
+		display: block;
+		overflow: hidden;
+		/* #endif */
+	}
+
+	.uni-noticebar__content--single {
+		/* #ifndef APP-NVUE */
+		display: flex;
+		flex: none;
+		width: 100%;
+		justify-content: center;
+		/* #endif */
+	}
+
+	.uni-noticebar__content-text {
+		font-size: 14px;
+		line-height: 18px;
+		/* #ifndef APP-NVUE */
+		word-break: break-all;
+		/* #endif */
+	}
+
+	.uni-noticebar__content-text--single {
+		/* #ifdef APP-NVUE */
+		lines: 1;
+		/* #endif */
+		/* #ifndef APP-NVUE */
+		display: block;
+		width: 100%;
+		white-space: nowrap;
+		/* #endif */
+		overflow: hidden;
+		text-overflow: ellipsis;
+	}
+
+	.uni-noticebar__content-text--scrollable {
+		/* #ifdef APP-NVUE */
+		lines: 1;
+		padding-left: 750rpx;
+		/* #endif */
+		/* #ifndef APP-NVUE */
+		position: absolute;
+		display: block;
+		height: 18px;
+		line-height: 18px;
+		white-space: nowrap;
+		padding-left: 100%;
+		animation: notice 10s 0s linear infinite both;
+		animation-play-state: paused;
+		/* #endif */
+	}
+
+	.uni-noticebar__more {
+		/* #ifndef APP-NVUE */
+		display: inline-flex;
+		/* #endif */
+		flex-direction: row;
+		flex-wrap: nowrap;
+		align-items: center;
+		padding-left: 5px;
+	}
+
+	.uni-noticebar__more-text {
+		font-size: 14px;
+	}
+
+	@keyframes notice {
+		100% {
+			transform: translate3d(-100%, 0, 0);
+		}
+	}
+</style>

+ 196 - 0
components/uni-number-box.vue

@@ -0,0 +1,196 @@
+<template>
+	<view class="uni-numbox">
+		<view class="uni-numbox-minus" 
+			@click="_calcValue('subtract')"
+		>
+			<text class="iconfont iconmove" :class="minDisabled?'uni-numbox-disabled': ''" ></text>
+		</view>
+		<input 
+			class="uni-numbox-value" 
+			type="number"  
+			:disabled="disabled"
+			:value="inputValue" 
+			@blur="_onBlur"
+		>
+		<view 
+			class="uni-numbox-plus" 
+			@click="_calcValue('add')"
+		>
+			<text class="iconfont iconadd" :class="maxDisabled?'uni-numbox-disabled': ''" ></text>
+		</view>
+	</view>
+</template>
+<script>
+	export default {
+		name: 'uni-number-box',
+		props: {
+			isMax: {
+				type: Boolean,
+				default: false
+			},
+			isMin: {
+				type: Boolean,
+				default: false
+			},
+			index: {
+				type: Number,
+				default: 0
+			},
+			value: {
+				type: Number,
+				default: 0
+			},
+			min: {
+				type: Number,
+				default: 1
+			},
+			max: {
+				type: Number,
+				default: Infinity
+			},
+			step: {
+				type: Number,
+				default: 1
+			},
+			disabled: {
+				type: Boolean,
+				default: false
+			}
+		},
+		data() {
+			return {
+				inputValue: this.value,
+				minDisabled: false,
+				maxDisabled: false
+			}
+		},
+		created(){
+			this.maxDisabled = this.isMax;
+			this.minDisabled = this.isMin;
+		},
+		computed: {
+
+		},
+		watch: {
+			inputValue(number) {
+				const data = {
+					number: number,
+					index: this.index
+				}
+				this.$emit('eventChange', data);
+			}
+		},
+		methods: {
+			_calcValue(type) {
+				const scale = this._getDecimalScale();
+				let value = this.inputValue * scale;
+				let newValue = 0;
+				let step = this.step * scale;
+				
+				if(type === 'subtract'){
+					newValue = value - step;
+					if (newValue <= this.min){
+						this.minDisabled = true;
+					}
+					if(newValue < this.min){
+						newValue = this.min
+					}
+					if(newValue < this.max && this.maxDisabled === true){
+						this.maxDisabled = false;
+					}
+				}else if(type === 'add'){
+					newValue = value + step;
+					if (newValue >= this.max){
+						this.maxDisabled = true;
+					}
+					if(newValue > this.max){
+						newValue = this.max
+					}
+					if(newValue > this.min && this.minDisabled === true){
+						this.minDisabled = false;
+					}
+				}
+				if(newValue === value){
+					return;
+				}
+				this.inputValue = newValue / scale;
+			},
+			_getDecimalScale() {
+				let scale = 1;
+				// 浮点型
+				if (~~this.step !== this.step) {
+					scale = Math.pow(10, (this.step + '').split('.')[1].length);
+				}
+				return scale;
+			},
+			_onBlur(event) {
+				let value = event.detail.value;
+				if (!value) {
+					this.inputValue = 0;
+					return
+				}
+				value = +value;
+				if (value > this.max) {
+					value = this.max;
+				} else if (value < this.min) {
+					value = this.min
+				}
+
+				this.inputValue = value
+			}
+		}
+	}
+</script>
+<style>
+	.uni-numbox {
+		/* position:absolute; */
+		/* left: 30rpx; */
+		/* bottom: 0; */
+		display: flex;
+		justify-content: flex-start;
+		align-items: center;
+	}
+
+	.uni-numbox-minus,
+	.uni-numbox-plus {
+		margin: 0;
+		background-color: #f5f5f5;
+		width: 70rpx;
+		height: 100%;
+		line-height: 70rpx;
+		text-align: center;
+		position: relative;
+	}
+	.uni-numbox-minus .yticon,
+	.uni-numbox-plus .yticon{
+		font-size: 36rpx;
+		color: #555;
+	}
+
+	.uni-numbox-minus {
+		border-right: none;
+		border-top-left-radius: 6rpx;
+		border-bottom-left-radius: 6rpx;
+	}
+
+	.uni-numbox-plus {
+		border-left: none;
+		border-top-right-radius: 6rpx;
+		border-bottom-right-radius: 6rpx;
+	}
+
+	.uni-numbox-value {
+		position: relative;
+		width: 91rpx;
+		height: 51rpx;
+		text-align: center;
+		color: #FFFFFF;
+		font-size: 33rpx;
+		background-color: #5771DF;
+		margin: 0rpx 10rpx;
+	}
+
+	.uni-numbox-disabled.iconfont {
+		color: #d6d6d6;
+	}
+</style>

+ 263 - 0
components/uni-popup/uni-popup.vue

@@ -0,0 +1,263 @@
+<template>
+	<view v-if="showPopup" class="uni-popup" @touchmove.stop.prevent="clear">
+		<uni-transition :mode-class="['fade']" :styles="maskClass" :duration="duration" :show="showTrans" @click="onTap" />
+		<uni-transition :mode-class="ani" :styles="transClass" :duration="duration" :show="showTrans" @click="onTap">
+			<view class="uni-popup__wrapper-box" @click.stop="clear">
+				<slot />
+			</view>
+		</uni-transition>
+	</view>
+</template>
+
+<script>
+	import uniTransition from '../uni-transition/uni-transition.vue'
+
+	/**
+	 * PopUp 弹出层
+	 * @description 弹出层组件,为了解决遮罩弹层的问题
+	 * @tutorial https://ext.dcloud.net.cn/plugin?id=329
+	 * @property {String} type = [top|center|bottom] 弹出方式
+	 * 	@value top 顶部弹出
+	 * 	@value center 中间弹出
+	 * 	@value bottom 底部弹出
+	 * @property {Boolean} animation = [ture|false] 是否开启动画
+	 * @property {Boolean} maskClick = [ture|false] 蒙版点击是否关闭弹窗
+	 * @event {Function} change 打开关闭弹窗触发,e={show: false}
+	 */
+
+	export default {
+		name: 'UniPopup',
+		components: {
+			uniTransition
+		},
+		props: {
+			// 开启动画
+			animation: {
+				type: Boolean,
+				default: true
+			},
+			// 弹出层类型,可选值,top: 顶部弹出层;bottom:底部弹出层;center:全屏弹出层
+			type: {
+				type: String,
+				default: 'center'
+			},
+			// maskClick
+			maskClick: {
+				type: Boolean,
+				default: true
+			}
+		},
+		data() {
+			return {
+				duration: 300,
+				ani: [],
+				showPopup: false,
+				showTrans: false,
+				maskClass: {
+					'position': 'fixed',
+					'bottom': 0,
+					'top': 0,
+					'left': 0,
+					'right': 0,
+					'backgroundColor': 'rgba(0, 0, 0, 0.4)'
+				},
+				transClass: {
+					'position': 'fixed',
+					'left': 0,
+					'right': 0,
+				}
+			}
+		},
+		watch: {
+			type: {
+				handler: function(newVal) {
+					switch (this.type) {
+						case 'top':
+							this.ani = ['slide-top']
+							this.transClass = {
+								'position': 'fixed',
+								'left': 0,
+								'right': 0,
+							}
+							break
+						case 'bottom':
+							this.ani = ['slide-bottom']
+							this.transClass = {
+								'position': 'fixed',
+								'left': 0,
+								'right': 0,
+								'bottom': 0
+							}
+							break
+						case 'center':
+							this.ani = ['zoom-out', 'fade']
+							this.transClass = {
+								'position': 'fixed',
+								/* #ifndef APP-NVUE */
+								'display': 'flex',
+								'flexDirection': 'column',
+								/* #endif */
+								'bottom': 0,
+								'left': 0,
+								'right': 0,
+								'top': 0,
+								'justifyContent': 'center',
+								'alignItems': 'center'
+							}
+
+							break
+					}
+				},
+				immediate: true
+			}
+		},
+		created() {
+			if (this.animation) {
+				this.duration = 300
+			} else {
+				this.duration = 0
+			}
+		},
+		methods: {
+			clear(e) {
+				// TODO nvue 取消冒泡
+				e.stopPropagation()
+			},
+			open() {
+				this.showPopup = true
+				this.$nextTick(() => {
+					clearTimeout(this.timer)
+					this.timer = setTimeout(() => {
+						this.showTrans = true
+					}, 50);
+				})
+				this.$emit('change', {
+					show: true
+				})
+			},
+			close(type) {
+				this.showTrans = false
+				this.$nextTick(() => {
+					clearTimeout(this.timer)
+					this.timer = setTimeout(() => {
+						this.$emit('change', {
+							show: false
+						})
+						this.showPopup = false
+					}, 300)
+				})
+			},
+			onTap() {
+				if (!this.maskClick) return
+				this.close()
+			}
+		}
+	}
+</script>
+<style lang="scss" scoped>
+	.uni-popup {
+		position: fixed;
+		/* #ifdef H5 */
+		top: var(--window-top);
+		/* #endif */
+		/* #ifndef H5 */
+		top: 0;
+		/* #endif */
+		bottom: 0;
+		left: 0;
+		right: 0;
+		/* #ifndef APP-NVUE */
+		z-index: 999;
+		/* #endif */
+	}
+
+	.uni-popup__mask {
+		position: absolute;
+		top: 0;
+		bottom: 0;
+		left: 0;
+		right: 0;
+		background-color: $uni-bg-color-mask;
+		opacity: 0;
+	}
+
+	.mask-ani {
+		transition-property: opacity;
+		transition-duration: 0.2s;
+	}
+
+	.uni-top-mask {
+		opacity: 1;
+	}
+
+	.uni-bottom-mask {
+		opacity: 1;
+	}
+
+	.uni-center-mask {
+		opacity: 1;
+	}
+
+	.uni-popup__wrapper {
+		/* #ifndef APP-NVUE */
+		display: block;
+		/* #endif */
+		position: absolute;
+	}
+
+	.top {
+		top: 0;
+		left: 0;
+		right: 0;
+		transform: translateY(-500px);
+	}
+
+	.bottom {
+		bottom: 0;
+		left: 0;
+		right: 0;
+		transform: translateY(500px);
+	}
+
+	.center {
+		/* #ifndef APP-NVUE */
+		display: flex;
+		flex-direction: column;
+		/* #endif */
+		bottom: 0;
+		left: 0;
+		right: 0;
+		top: 0;
+		justify-content: center;
+		align-items: center;
+		transform: scale(1.2);
+		opacity: 0;
+	}
+
+	.uni-popup__wrapper-box {
+		/* #ifndef APP-NVUE */
+		display: block;
+		/* #endif */
+		position: relative;
+	}
+
+	.content-ani {
+		// transition: transform 0.3s;
+		transition-property: transform, opacity;
+		transition-duration: 0.2s;
+	}
+
+
+	.uni-top-content {
+		transform: translateY(0);
+	}
+
+	.uni-bottom-content {
+		transform: translateY(0);
+	}
+
+	.uni-center-content {
+		transform: scale(1);
+		opacity: 1;
+	}
+</style>

+ 279 - 0
components/uni-transition/uni-transition.vue

@@ -0,0 +1,279 @@
+<template>
+	<view v-if="isShow" ref="ani" class="uni-transition" :class="[ani.in]" :style="'transform:' +transform+';'+stylesObject"
+	 @click="change">
+		 <slot></slot>
+	</view>
+</template>
+
+<script>
+	// #ifdef APP-NVUE
+	const animation = uni.requireNativePlugin('animation');
+	// #endif
+	/**
+	 * Transition 过渡动画
+	 * @description 简单过渡动画组件
+	 * @tutorial https://ext.dcloud.net.cn/plugin?id=985
+	 * @property {Boolean} show = [false|true] 控制组件显示或隐藏
+     * @property {Array} modeClass = [fade|slide-top|slide-right|slide-bottom|slide-left|zoom-in|zoom-out] 过渡动画类型
+     *  @value fade 渐隐渐出过渡
+     *  @value slide-top 由上至下过渡
+     *  @value slide-right 由右至左过渡
+     *  @value slide-bottom 由下至上过渡
+     *  @value slide-left 由左至右过渡
+     *  @value zoom-in 由小到大过渡
+     *  @value zoom-out 由大到小过渡
+	 * @property {Number} duration 过渡动画持续时间
+	 * @property {Object} styles 组件样式,同 css 样式,注意带’-‘连接符的属性需要使用小驼峰写法如:`backgroundColor:red`
+	 */
+	export default {
+		name: 'uniTransition',
+		props: {
+			show: {
+				type: Boolean,
+				default: false
+			},
+			modeClass: {
+				type: Array,
+				default () {
+					return []
+				}
+			},
+			duration: {
+				type: Number,
+				default: 300
+			},
+			styles: {
+				type: Object,
+				default () {
+					return {}
+				}
+			}
+		},
+		data() {
+			return {
+				isShow: false,
+				transform: '',
+				ani: { in: '',
+					active: ''
+				}
+			};
+		},
+		watch: {
+			show: {
+				handler(newVal) {
+					if (newVal) {
+						this.open()
+					} else {
+						this.close()
+					}
+				},
+				immediate: true
+			}
+		},
+		computed: {
+			stylesObject() {
+				let styles = {
+					...this.styles,
+					'transition-duration': this.duration / 1000 + 's'
+				}
+				let transfrom = ''
+				for (let i in styles) {
+					let line = this.toLine(i)
+					transfrom += line + ':' + styles[i] + ';'
+				}
+				return transfrom
+			}
+		},
+		created() {
+			// this.timer = null
+			// this.nextTick = (time = 50) => new Promise(resolve => {
+			// 	clearTimeout(this.timer)
+			// 	this.timer = setTimeout(resolve, time)
+			// 	return this.timer
+			// });
+		},
+		methods: {
+			change() {
+				this.$emit('click', {
+					detail: this.isShow
+				})
+			},
+			open() {
+				clearTimeout(this.timer)
+				this.isShow = true
+				this.transform = ''
+				this.ani.in = ''
+				for (let i in this.getTranfrom(false)) {
+					if (i === 'opacity') {
+						this.ani.in = 'fade-in'
+					} else {
+						this.transform += `${this.getTranfrom(false)[i]} `
+					}
+				}
+				this.$nextTick(() => {
+					setTimeout(() => {
+						this._animation(true)
+					}, 50)
+				})
+
+			},
+			close(type) {
+				clearTimeout(this.timer)
+				this._animation(false)
+			},
+			_animation(type) {
+				let styles = this.getTranfrom(type)
+				// #ifdef APP-NVUE
+				if(!this.$refs['ani']) return
+				animation.transition(this.$refs['ani'].ref, {
+					styles,
+					duration: this.duration, //ms
+					timingFunction: 'ease',
+					needLayout: false,
+					delay: 0 //ms
+				}, () => {
+					if (!type) {
+						this.isShow = false
+					}
+					this.$emit('change', {
+						detail: this.isShow
+					})
+				})
+				// #endif
+				// #ifndef APP-NVUE
+				this.transform = ''
+				for (let i in styles) {
+					if (i === 'opacity') {
+						this.ani.in = `fade-${type?'out':'in'}`
+					} else {
+						this.transform += `${styles[i]} `
+					}
+				}
+				this.timer = setTimeout(() => {
+					if (!type) {
+						this.isShow = false
+					}
+					this.$emit('change', {
+						detail: this.isShow
+					})
+
+				}, this.duration)
+				// #endif
+
+			},
+			getTranfrom(type) {
+				let styles = {
+					transform: ''
+				}
+				this.modeClass.forEach((mode) => {
+					switch (mode) {
+						case 'fade':
+							styles.opacity = type ? 1 : 0
+							break;
+						case 'slide-top':
+							styles.transform += `translateY(${type?'0':'-100%'}) `
+							break;
+						case 'slide-right':
+							styles.transform += `translateX(${type?'0':'100%'}) `
+							break;
+						case 'slide-bottom':
+							styles.transform += `translateY(${type?'0':'100%'}) `
+							break;
+						case 'slide-left':
+							styles.transform += `translateX(${type?'0':'-100%'}) `
+							break;
+						case 'zoom-in':
+							styles.transform += `scale(${type?1:0.8}) `
+							break;
+						case 'zoom-out':
+							styles.transform += `scale(${type?1:1.2}) `
+							break;
+					}
+				})
+				return styles
+			},
+			_modeClassArr(type) {
+				let mode = this.modeClass
+				if (typeof(mode) !== "string") {
+					let modestr = ''
+					mode.forEach((item) => {
+						modestr += (item + '-' + type + ',')
+					})
+					return modestr.substr(0, modestr.length - 1)
+				} else {
+					return mode + '-' + type
+				}
+			},
+			// getEl(el) {
+			// 	console.log(el || el.ref || null);
+			// 	return el || el.ref || null
+			// },
+			toLine(name) {
+				return name.replace(/([A-Z])/g, "-$1").toLowerCase();
+			}
+		}
+	}
+</script>
+
+<style>
+	.uni-transition {
+		transition-timing-function: ease;
+		transition-duration: 0.3s;
+		transition-property: transform, opacity;
+	}
+
+	.fade-in {
+		opacity: 0;
+	}
+
+	.fade-active {
+		opacity: 1;
+	}
+
+	.slide-top-in {
+		/* transition-property: transform, opacity; */
+		transform: translateY(-100%);
+	}
+
+	.slide-top-active {
+		transform: translateY(0);
+		/* opacity: 1; */
+	}
+
+	.slide-right-in {
+		transform: translateX(100%);
+	}
+
+	.slide-right-active {
+		transform: translateX(0);
+	}
+
+	.slide-bottom-in {
+		transform: translateY(100%);
+	}
+
+	.slide-bottom-active {
+		transform: translateY(0);
+	}
+
+	.slide-left-in {
+		transform: translateX(-100%);
+	}
+
+	.slide-left-active {
+		transform: translateX(0);
+		opacity: 1;
+	}
+
+	.zoom-in-in {
+		transform: scale(0.8);
+	}
+
+	.zoom-out-active {
+		transform: scale(1);
+	}
+
+	.zoom-out-in {
+		transform: scale(1.2);
+	}
+</style>

+ 226 - 0
components/upload-images.vue

@@ -0,0 +1,226 @@
+<template>
+	<view class="upload-content">
+		<block v-for="(item, index) in imageList" :key="index">
+			<view class="upload-item">
+				<image class="upload-img" :src="item.filePath" mode="aspectFill" @click="previewImage(index)"></image>
+				<image class="upload-del-btn" 
+					@click="delImage(index)" 
+					src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACYAAAAmCAYAAACoPemuAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyJpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMy1jMDExIDY2LjE0NTY2MSwgMjAxMi8wMi8wNi0xNDo1NjoyNyAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNiAoV2luZG93cykiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6RjNBODgzQjUwNDM5MTFFOUJDMjlGN0UwRTJGMjVCNjQiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6RjNBODgzQjYwNDM5MTFFOUJDMjlGN0UwRTJGMjVCNjQiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDpGM0E4ODNCMzA0MzkxMUU5QkMyOUY3RTBFMkYyNUI2NCIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDpGM0E4ODNCNDA0MzkxMUU5QkMyOUY3RTBFMkYyNUI2NCIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PuYQTIAAAAHNSURBVHjazJgxasMwFIbjnsD4BDmCLxDQDZrNQ5bcILlBvXvpDRLIWmiHFkyH2t0LyVbwEkPpbE/eYlUCGYQax096UuIffkIgij7ryU/vyZuYy2e+Z56K70R8lsJcOfPn5AriMCvmZ2YKdMW8EQ/hRA9iEorwXlpZtObMRySQ6kysvrFWloHUEIcmUBuHUDLccmxQskErt7wyVLdy00tQ4Q2g5De2V9kNwWjffiNDA33f/42i6E13Qj5uNptlwJD+SyODuaqqqi/KVBTFOxSKA7VtW/NxSZI8AcbE2nuraZpvKgSBk6G4drsdBOwogz1CwAghH/JEl+BUKJ1VltPHHjoIAoeE4l53YFqb+RKcBSgqyqXhtxEKZwkKB3YOThYCqjPuCDoHZwGK3mGLtdPp5LmqTI1Dqe4p26EkNqA4iE6eg2z+iQ0okyQMATvYgLIIt9Y6knTyFBIudHqIq3BpmkL60VJ9O0sXZY8MBwSLtdNGEAQ/i8XiVXcz83EcEPDbuq/fzMdYWt+6GTmMsX2rh9q3TtsxNrzXhKt1rwg6rR1Dhdjqo7QMlWOvoWTF4imxQMRF7eaL8L5ohmwrLgDB8pCQc8DlcG7y538CDABJNGPqfaJgfgAAAABJRU5ErkJggg==" 
+					mode="scaleToFill">
+				</image>
+				<view class="upload-progress" v-if="item.progress < 100">{{item.progress}}%</view>
+			</view>
+		</block>
+		<view class="upload-add-btn" v-if="rduLength > 0" @click="chooseImage"></view>
+	</view>
+</template>
+
+<script>
+export default {
+	data() {
+		return {
+			imageList: []
+		};
+	},
+	props: {
+		url: {
+			type: String,
+			value: '' //上传接口地址
+		},
+		count: {
+			type: Number,
+			value: 4 //单次可选择的图片数量
+		},
+		length: {
+			type: Number,
+			value: 50 //可上传总数量
+		}
+	},
+	computed: {
+		rduLength(){
+			return this.length - this.imageList.length;
+		}
+	},
+	methods: {
+		//选择图片
+		chooseImage: function(){
+			uni.chooseImage({
+				count: this.rduLength < this.count ? this.rduLength : this.count, //最多可以选择的图片张数,默认9
+				sizeType: ['original', 'compressed'], //original 原图,compressed 压缩图,默认二者都有
+				sourceType: ['album'], //album 从相册选图,camera 使用相机,默认二者都有
+				success: (res)=> {
+					const images = res.tempFilePaths;
+					this.uploadFiles(images);
+				}
+			});
+		},
+		//上传图片
+		async uploadFiles(images){
+			this.imageList.push({
+				filePath: images[0],
+				progress: 0
+			});
+			uni.showLoading({
+				title: '请稍后..',
+				mask: true,
+			})
+			try{
+				const uploadUrl = await this.uploadImage(images[0]);
+			}catch(err){
+				console.log(err);
+				return;
+			}
+			
+			if(uploadUrl !== false){
+				images.splice(0, 1);
+				this.imageList[this.imageList.length - 1].src = uploadUrl;
+
+				//判断是否需要继续上传
+				if(images.length > 0 && this.rduLength > 0){
+					this.uploadFiles(images);
+				}else{
+					uni.hideLoading();
+				}
+			}else{
+				//上传失败处理
+				this.imageList.pop();
+				uni.hideLoading();
+				uni.showToast({
+					title: '上传中出现问题,已终止上传',
+					icon: 'none',
+					mask: true,
+					duration: 2000
+				});
+			}
+		},
+		uploadImage: function(file){
+			return new Promise((resolve, reject)=> {
+				//发送给后端的附加参数
+				const formData = {
+					thumb_mode: 1,  
+				};
+				this.uploadTask = uni.uploadFile({
+					url: this.url, 
+					filePath: file,
+					name: 'file',
+					formData: formData,
+					success(uploadFileResult){
+						const uploadFileRes = JSON.parse(uploadFileResult.data) || {};
+						if(uploadFileRes.status === 1 && uploadFileRes.data){
+							resolve(uploadFileRes.data);
+						}else{
+							reject('接口返回错误');
+						}
+					}, 
+					fail(){
+						reject('网络链接错误');
+					}
+				});
+				//上传进度
+				this.uploadTask.onProgressUpdate((progressRes)=> {
+					this.imageList[this.imageList.length - 1].progress = progressRes.progress;
+				});
+			});
+		},
+		//删除图片
+		delImage: function(index){
+			uni.showModal({
+				content: '确定要放弃这张图片么?',
+				success: (confirmRes)=> {
+					if (confirmRes.confirm) {
+						this.imageList.splice(index, 1);
+					} 
+				}
+			});
+		},
+		//预览图片
+		previewImage: function(index){
+			const urls = [];
+			this.imageList.forEach((item)=> {
+				urls.push(item.filePath);
+			})
+			uni.previewImage({
+				current: urls[index],
+				urls: urls,
+				indicator: "number"
+			})
+		}
+	}
+}
+</script>
+
+<style lang="scss">
+	.upload-content{
+		padding:24upx 0 0 28upx;
+		background-color: #fff;
+		overflow:hidden;
+	}
+	.upload-item{
+		position: relative;
+		float:left;
+		width:150upx;
+		height:150upx;
+		margin-right:30upx;
+		margin-bottom:30upx;
+		&:nth-child(4n){
+			margin-right:0;
+		}
+		.upload-img{
+			width:100%;
+			height:100%;
+			border-radius:8upx;
+		}
+		.upload-del-btn{
+			position: absolute;
+			right:-16upx;
+			top:-14upx;
+			width:36upx;
+			height:36upx;
+			border: 4upx solid #fff;
+			border-radius: 100px;
+		}
+		.upload-progress{
+			position: absolute;
+			left:0;
+			top:0;
+			display:flex;
+			align-items:center;
+			justify-content: center;
+			width:100%;
+			height:100%;
+			background-color: rgba(0,0,0,.4);
+			color:#fff;
+			font-size:24upx;
+			border-radius:8upx;
+		}
+	}
+	.upload-add-btn {
+		position: relative;
+		float:left;
+		width: 150upx;
+		height: 150upx;
+		z-index: 99;
+		border-radius:8upx;
+		background:#f9f9f9;
+		&:before,
+		&:after {
+			content: " ";
+			position: absolute;
+			top: 50%;
+			left: 50%;
+			-webkit-transform: translate(-50%, -50%);
+			transform: translate(-50%, -50%);
+			width: 4upx;
+			height: 60upx;
+			background-color: #d6d6d6;
+		}
+		&:after {
+			width: 60upx;
+			height: 4upx;
+		}
+		&:active {
+			background-color: #f7f7f7;
+		}
+	}
+
+</style>

+ 34 - 0
interceptor.js

@@ -0,0 +1,34 @@
+// 应用打开后拦截
+const loadRouter = function() {
+	// 获取上个页面
+	let pages = getCurrentPages();
+	let prePage = pages[pages.length - 2];
+	// #ifdef H5
+	let page =  prePage;
+	// #endif
+	// #ifdef APP-PLUS
+	let page = prePage.$vm;
+	// #endif
+	interceptor(page,prePage)
+}
+// 路由拦截
+/**
+ * @param {Object} now 当前页面
+ * @param {Object} before 上一个页面
+ */
+const interceptor = function(now,before) {
+	// 获取用户信息判断是否登录过
+	let userInfo = uni.getStorageSync('userInfo') || '';
+	// 判断是否需要拦截
+	let state = uni.getStorageSync('loginInterceptor');
+	// 判断是否需要拦截
+	if (state) {
+		// 拦截条件
+		if (!userInfo.id) {
+			uni.navigateTo({
+				url: '/pages/public/login'
+			})
+		}
+	}
+}
+export default loadRouter

+ 33 - 0
js_sdk/xb-copy/uni-copy.js

@@ -0,0 +1,33 @@
+export default function uniCopy(content) {
+	/**
+	 * 小程序端 和 app端的复制逻辑
+	 */
+	//#ifndef H5
+	uni.setClipboardData({
+		data: content,
+		success: function() {
+			console.log('success');
+			return true
+		}
+	});
+	//#endif
+	
+	/**
+	 * H5端的复制逻辑
+	 */
+	// #ifdef H5
+	if (!document.queryCommandSupported('copy')) { //为了兼容有些浏览器 queryCommandSupported 的判断
+		// 不支持
+		return false
+	}
+	let textarea = document.createElement("textarea")
+	textarea.value = content
+	textarea.readOnly = "readOnly"
+	document.body.appendChild(textarea)
+	textarea.select() // 选择对象
+	textarea.setSelectionRange(0, content.length) //核心
+	let result = document.execCommand("copy") // 执行浏览器复制命令
+	textarea.remove()
+	return result
+	// #endif
+}

+ 44 - 0
main.js

@@ -0,0 +1,44 @@
+import Vue from 'vue'
+import store from './store'
+import App from './App'
+/**
+ *  所有测试用数据均存放于根目录json.js
+ *  
+ *  css部分使用了App.vue下的全局样式和iconfont图标,有需要图标库的可以留言。
+ *  示例使用了uni.scss下的变量, 除变量外已尽量移除特有语法,可直接替换为其他预处理器使用
+ */
+const msg = (title, duration=1500, mask=false, icon='none')=>{
+	//统一提示方便全局修改
+	if(Boolean(title) === false){
+		return;
+	}
+	uni.showToast({
+		title,
+		duration,
+		mask,
+		icon
+	});
+}
+
+const prePage = ()=>{
+	// 获取当前页面
+	let pages = getCurrentPages();
+	let prePage = pages[pages.length - 2];
+	// #ifdef H5
+	return prePage;
+	// #endif
+	return prePage.$vm;
+}
+
+
+Vue.config.productionTip = false
+Vue.prototype.$fire = new Vue();
+Vue.prototype.$store = store;
+Vue.prototype.$api = {msg, prePage};
+
+App.mpType = 'app'
+
+const app = new Vue({
+    ...App
+})
+app.$mount()

+ 118 - 0
manifest.json

@@ -0,0 +1,118 @@
+{
+    "name" : "鲲鹏云矿",
+    "appid" : "__UNI__36C0ACD",
+    "description" : "",
+    "versionName" : "1.0.1",
+    "versionCode" : 101,
+    "transformPx" : false,
+    "app-plus" : {
+        /* 5+App特有相关 */
+        "usingComponents" : true,
+        "splashscreen" : {
+            "alwaysShowBeforeRender" : true,
+            "waiting" : true,
+            "autoclose" : true,
+            "delay" : 0
+        },
+        "modules" : {},
+        /* 模块配置 */
+        "distribute" : {
+            /* 应用发布信息 */
+            "android" : {
+                /* android打包配置 */
+                "permissions" : [
+                    "<uses-feature android:name=\"android.hardware.camera\"/>",
+                    "<uses-feature android:name=\"android.hardware.camera.autofocus\"/>",
+                    "<uses-permission android:name=\"android.permission.CALL_PHONE\"/>",
+                    "<uses-permission android:name=\"android.permission.CAMERA\"/>",
+                    "<uses-permission android:name=\"android.permission.CHANGE_NETWORK_STATE\"/>",
+                    "<uses-permission android:name=\"android.permission.FLASHLIGHT\"/>",
+                    "<uses-permission android:name=\"android.permission.GET_ACCOUNTS\"/>",
+                    "<uses-permission android:name=\"android.permission.MODIFY_AUDIO_SETTINGS\"/>",
+                    "<uses-permission android:name=\"android.permission.READ_CONTACTS\"/>",
+                    "<uses-permission android:name=\"android.permission.RECORD_AUDIO\"/>",
+                    "<uses-permission android:name=\"android.permission.VIBRATE\"/>",
+                    "<uses-permission android:name=\"android.permission.WAKE_LOCK\"/>",
+                    "<uses-permission android:name=\"android.permission.WRITE_CONTACTS\"/>"
+                ],
+                "abiFilters" : [ "armeabi-v7a", "arm64-v8a", "x86" ]
+            },
+            "ios" : {},
+            /* ios打包配置 */
+            "sdkConfigs" : {
+                "maps" : {},
+                "ad" : {}
+            },
+            "icons" : {
+                "android" : {
+                    "hdpi" : "unpackage/res/icons/72x72.png",
+                    "xhdpi" : "unpackage/res/icons/96x96.png",
+                    "xxhdpi" : "unpackage/res/icons/144x144.png",
+                    "xxxhdpi" : "unpackage/res/icons/192x192.png"
+                },
+                "ios" : {
+                    "appstore" : "unpackage/res/icons/1024x1024.png",
+                    "ipad" : {
+                        "app" : "unpackage/res/icons/76x76.png",
+                        "app@2x" : "unpackage/res/icons/152x152.png",
+                        "notification" : "unpackage/res/icons/20x20.png",
+                        "notification@2x" : "unpackage/res/icons/40x40.png",
+                        "proapp@2x" : "unpackage/res/icons/167x167.png",
+                        "settings" : "unpackage/res/icons/29x29.png",
+                        "settings@2x" : "unpackage/res/icons/58x58.png",
+                        "spotlight" : "unpackage/res/icons/40x40.png",
+                        "spotlight@2x" : "unpackage/res/icons/80x80.png"
+                    },
+                    "iphone" : {
+                        "app@2x" : "unpackage/res/icons/120x120.png",
+                        "app@3x" : "unpackage/res/icons/180x180.png",
+                        "notification@2x" : "unpackage/res/icons/40x40.png",
+                        "notification@3x" : "unpackage/res/icons/60x60.png",
+                        "settings@2x" : "unpackage/res/icons/58x58.png",
+                        "settings@3x" : "unpackage/res/icons/87x87.png",
+                        "spotlight@2x" : "unpackage/res/icons/80x80.png",
+                        "spotlight@3x" : "unpackage/res/icons/120x120.png"
+                    }
+                }
+            },
+            "splashscreen" : {
+                "androidStyle" : "default",
+                "android" : {
+                    "hdpi" : "H:/item/zhiya/启动图/qd480x762.png",
+                    "xhdpi" : "H:/item/zhiya/启动图/qd720x1242.png",
+                    "xxhdpi" : "H:/item/zhiya/启动图/qd1080x1882.png"
+                },
+                "iosStyle" : "default",
+                "ios" : {
+                    "iphone" : {
+                        "portrait-896h@3x" : "H:/item/zhiya/启动图/qd1242x2688.png",
+                        "portrait-896h@2x" : "H:/item/zhiya/启动图/qd828x1792.png"
+                    }
+                }
+            }
+        },
+        "nativePlugins" : {}
+    },
+    /* SDK配置 */
+    "quickapp" : {},
+    /* 快应用特有相关 */
+    "mp-weixin" : {
+        /* 小程序特有相关 */
+        "usingComponents" : true,
+        "appid" : "",
+        "setting" : {
+            "urlCheck" : true
+        }
+    },
+    "h5" : {
+        "title" : "鲲鹏云矿",
+        "domain" : "",
+        "router" : {
+            "base" : "/index/",
+            "mode" : "hash"
+        },
+        "devServer" : {
+            "port" : ""
+        }
+    }
+}

+ 30 - 0
node_modules/jweixin-module/README.md

@@ -0,0 +1,30 @@
+# jweixin-module
+
+微信JS-SDK
+
+## 安装
+
+### NPM
+
+```shell
+npm install jweixin-module --save
+```
+
+### UMD
+
+```http
+https://unpkg.com/jweixin-module/out/index.js
+```
+
+## 使用
+
+```js
+var wx = require('jweixin-module')
+wx.ready(function(){
+    // TODO
+});
+```
+
+## 完整API
+
+>[微信JS-SDK说明文档](https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421141115)

파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 0 - 0
node_modules/jweixin-module/out/index.js


+ 60 - 0
node_modules/jweixin-module/package.json

@@ -0,0 +1,60 @@
+{
+  "_from": "jweixin-module",
+  "_id": "jweixin-module@1.4.1",
+  "_inBundle": false,
+  "_integrity": "sha512-2R2oa1lYhAsclfjKSf3DP4ZiP1dcrQUbM7aklbeJA+UAg/LS7MqoA6UbTy1cs4sbB34z62K4bKW0Z9iazD8ejg==",
+  "_location": "/jweixin-module",
+  "_phantomChildren": {},
+  "_requested": {
+    "type": "tag",
+    "registry": true,
+    "raw": "jweixin-module",
+    "name": "jweixin-module",
+    "escapedName": "jweixin-module",
+    "rawSpec": "",
+    "saveSpec": null,
+    "fetchSpec": "latest"
+  },
+  "_requiredBy": [
+    "#USER",
+    "/"
+  ],
+  "_resolved": "https://registry.npmjs.org/jweixin-module/-/jweixin-module-1.4.1.tgz",
+  "_shasum": "1fc8fa42622243f6c35651d272cd587debf56cd1",
+  "_spec": "jweixin-module",
+  "_where": "D:\\工作\\项目\\appBase",
+  "author": {
+    "name": "Shengqiang Guo"
+  },
+  "bugs": {
+    "url": "https://github.com/zhetengbiji/jweixin-module/issues"
+  },
+  "bundleDependencies": false,
+  "deprecated": false,
+  "description": "微信JS-SDK",
+  "devDependencies": {
+    "textfile": "^1.2.0",
+    "uglify-js": "^3.4.9"
+  },
+  "homepage": "https://github.com/zhetengbiji/jweixin-module#readme",
+  "keywords": [
+    "wxjssdk",
+    "weixin",
+    "jweixin",
+    "wechat",
+    "jssdk",
+    "wx"
+  ],
+  "license": "ISC",
+  "main": "out/index.js",
+  "name": "jweixin-module",
+  "repository": {
+    "type": "git",
+    "url": "git+https://github.com/zhetengbiji/jweixin-module.git"
+  },
+  "scripts": {
+    "build": "node build",
+    "prepublish": "npm run build"
+  },
+  "version": "1.4.1"
+}

+ 11 - 0
package-lock.json

@@ -0,0 +1,11 @@
+{
+  "requires": true,
+  "lockfileVersion": 1,
+  "dependencies": {
+    "jweixin-module": {
+      "version": "1.4.1",
+      "resolved": "https://registry.npmjs.org/jweixin-module/-/jweixin-module-1.4.1.tgz",
+      "integrity": "sha512-2R2oa1lYhAsclfjKSf3DP4ZiP1dcrQUbM7aklbeJA+UAg/LS7MqoA6UbTy1cs4sbB34z62K4bKW0Z9iazD8ejg=="
+    }
+  }
+}

+ 13 - 0
package.json

@@ -0,0 +1,13 @@
+{
+    "id": "lb-picker",
+    "name": "lb-picker选择器",
+    "version": "v1.2.0",
+    "description": "支持app、nvue、h5、各小程序,支持单选、理论任意级数多级联动、非联动及日期选择。",
+    "keywords": [
+        "picker",
+        "多级联动",
+        "省市区",
+        "城市选择",
+        "date日期选择"
+    ]
+}

+ 275 - 0
pages.json

@@ -0,0 +1,275 @@
+{
+	"pages": [
+		{
+			"path": "pages/public/login",
+			"style": {
+				"navigationBarTitleText": "登录",
+				"app-plus": {
+					"titleNView": {
+						"type": "transparent"
+					}
+				}
+			}
+		},
+		{
+			"path": "pages/public/register",
+			"style": {
+				"navigationBarTitleText": ""
+			}
+		}, 
+		{
+			"path": "pages/public/forget",
+			"style": {
+				"navigationBarTitleText": "修改密码"
+			}
+		},
+		{
+			"path": "pages/index/index",
+			"style": {
+				"navigationBarTextStyle":"black",
+				"navigationBarTitleText": "",
+				"enablePullDownRefresh": true,
+				"onReachBottomDistance":50,
+				"app-plus": {
+					"titleNView":false
+				}
+			}
+		},
+		{
+			"path": "pages/index/information",
+			"style": {
+				"navigationBarTitleText": "资讯"
+			}
+		},
+		{
+			"path": "pages/index/informationDetails",
+			"style": {
+				"navigationBarTitleText": "资讯详情"
+			}
+		},
+		{
+			"path": "pages/index/introduce",
+			"style": {
+				"navigationBarTitleText": "平台介绍"
+			}
+		},
+		{
+			"path": "pages/index/notice",
+			"style": {
+				"navigationBarTitleText": "通知公告"
+			}
+		},
+		{
+			"path": "pages/index/share",
+			"style": {
+				"navigationBarTitleText": "分享好友"
+			}
+		},
+		{
+			"path": "pages/calculation/index",
+			"style": {
+				"navigationBarTitleText": "算力",
+				"enablePullDownRefresh": true
+				
+			}
+		},
+		{
+			"path": "pages/index/pingtai",
+			"style": {
+				"navigationBarTitleText": "平台介绍",
+				"enablePullDownRefresh": true
+				
+			}
+		},
+		{
+			"path": "pages/calculation/myCalculation",
+			"style": {
+				"navigationBarTitleText": "我的算力"
+			}
+		},
+		{
+			"path": "pages/finance/allMiner",
+			"style": {
+				"navigationBarTitleText": "总矿工列表"
+			}
+		},
+		{
+			"path": "pages/calculation/details",
+			"style": {
+				"navigationBarTitleText": "云算力详情",
+				"navigationBarBackgroundColor":"#5771DF",
+				"navigationBarTextStyle": "white"
+			}
+		},
+		{
+			"path": "pages/calculation/buyCalculation",
+			"style": {
+				"navigationBarTitleText": "服务器租赁"
+			}
+		},
+		{
+			"path": "pages/calculation/computer",
+			"style": {
+				"navigationBarTitleText": "收益计算器"
+			}
+		},
+		{
+			"path": "pages/product/index",
+			"style": {
+				"navigationBarTitleText": "商城"
+			}
+		},
+		{
+			"path": "pages/finance/index",
+			"style": {
+				"navigationBarTitleText": "资产",
+				"enablePullDownRefresh": true
+			}
+		},
+		{
+			"path": "pages/finance/xieyi",
+			"style": {
+				"navigationBarTitleText": "租赁协议"
+			}
+		},
+		{
+			"path": "pages/finance/computat",
+			"style": {
+				"navigationBarTitleText": "我的算力"
+			}
+		},
+		{
+			"path": "pages/finance/recharge",
+			"style": {
+				"navigationBarTitleText": "充币"
+			}
+		},
+		{
+			"path": "pages/finance/details",
+			"style": {
+				"navigationBarTitleText": "资金流水"
+			}
+		},
+		{
+			"path": "pages/finance/transfer",
+			"style": {
+				"navigationBarTitleText": "转账",
+				"navigationBarBackgroundColor":"#5771DF",
+				"navigationBarTextStyle": "white"
+			}
+		},
+		{
+			"path": "pages/finance/withdraw",
+			"style": {
+				"navigationBarTitleText": "提币"
+			}
+		},
+		{
+			"path": "pages/user/user",
+			"style": {
+				"navigationBarTitleText": "个人中心",
+				"enablePullDownRefresh": true,
+				"app-plus": {
+					"titleNView": {
+						"type": "transparent"
+					}
+				}
+			}
+		},
+		{
+			"path": "pages/user/loginPass",
+			"style": {
+				"navigationBarTitleText": "登录密码"
+			}
+		},
+		{
+			"path": "pages/user/payment",
+			"style": {
+				"navigationBarTitleText": "支付密码"
+			}
+		},
+		{
+			"path": "pages/user/myTeam",
+			"style": {
+				"navigationBarTitleText": "我的分享",
+				"navigationBarBackgroundColor":"#5771DF",
+				"navigationBarTextStyle": "white"
+			}
+		},
+		{
+			"path": "pages/user/meaasge",
+			"style": {
+				"navigationBarTitleText": "消息中心"
+			}
+		},
+		{
+			"path": "pages/set/set",
+			"style": {
+				"navigationBarTitleText": "设置"
+			}
+		},
+		{
+			"path": "pages/public/wxLogin",
+			"style": {
+				"navigationBarTitleText": "微信登录",
+				"app-plus": {
+					"titleNView": {
+						"type": "transparent"
+					}
+				}
+			}
+		},
+		{
+			"path": "pages/redirect/redirect",
+			"style": {
+				"navigationBarTitleText": "微信登录跳转页面",
+				"app-plus": {
+					"titleNView": false
+				}
+			}
+		}
+	],
+	"globalStyle": {
+		"navigationBarTextStyle": "black",
+		"navigationBarTitleText": "uni-app",
+		"navigationBarBackgroundColor": "#FFFFFF",
+		"backgroundColor": "#f8f8f8"
+	},
+	"tabBar": {
+		"color": "#C2C6D5",
+		"selectedColor": "#5771DF",
+		"borderStyle": "black",
+		"backgroundColor": "#ffffff",
+		"list": [{
+				"pagePath": "pages/index/index",
+				"iconPath": "static/tabBar/tab-home.png",
+				"selectedIconPath": "static/tabBar/tab-home-current.png",
+				"text": "首页"
+			},
+			// {
+			// 	"pagePath": "pages/product/index",
+			// 	"iconPath": "static/tabBar/tab-product.png",
+			// 	"selectedIconPath": "static/tabBar/tab-product-current.png",
+			// 	"text": "产品"
+			// },
+			{
+				"pagePath": "pages/calculation/index",
+				"iconPath": "static/tabBar/tab-calculation.png",
+				"selectedIconPath": "static/tabBar/tab-calculation-current.png",
+				"text": "算力"
+			},
+			{
+				"pagePath": "pages/finance/index",
+				"iconPath": "static/tabBar/tab-finance.png",
+				"selectedIconPath": "static/tabBar/tab-finance-current.png",
+				"text": "资产"
+			},
+			{
+				"pagePath": "pages/user/user",
+				"iconPath": "static/tabBar/tab-my.png",
+				"selectedIconPath": "static/tabBar/tab-my-current.png",
+				"text": "我的"
+			}
+		]
+	}
+}

+ 391 - 0
pages/calculation/buyCalculation.vue

@@ -0,0 +1,391 @@
+<template>
+	<view class="container">
+		<image class="logo-img" src="../../static/img/img01.png"></image>
+		<view class="list-box">
+			<scroll-view scroll-x class="list-title">
+				<view
+					class="title"
+					v-for="(ls, index) in moneyTypeList"
+					:key="index"
+					:class="{ blue: tabCurrent == ls.code, grey: ls.has_mining == 0 }"
+					@click="tabClick(ls.code, ls.has_mining)"
+				>
+					{{ ls.name }}
+				</view>
+			</scroll-view>
+			<view class="flex_item list-name">
+				<view class="name" :class="{ black: tabType == 1 }" @click="tabTypeClick(1)">算力包</view>
+				<view class="name" :class="{ black: tabType == 2 }" @click="tabTypeClick(2)">独享矿机</view>
+				<!-- <view class='name' :class="{'black':tabType==3}" @click="tabTypeClick(3)">联合挖矿</view> -->
+				<!-- <view class='name' :class="{'black':tabCurrent==4}">分类名称</view> -->
+			</view>
+			<view class="list-cell" v-if="list.length > 0" v-for="(ls, index) in list" :key="index">
+				<view class="flex">
+					<view>
+						<view class="cell-title flex">
+							<image :src="ls.logo"></image>
+							<view class="title">{{ ls.name }}</view>
+						</view>
+						<view class="cell-tip">{{ ls.first_step_time + ls.second_step_time + ls.third_step_time }}天矿机</view>
+					</view>
+					<image v-if="ls.stock == 0" class="all-list" src="../../static/img/img51.png"></image>
+				</view>
+				<view class="flex cell-tpl">
+					<view class="tpl">
+						<view class="">单价</view>
+						<view class="">{{ ls._cost_money }}/T</view>
+					</view>
+					<view class="tpl">
+						<view class="">有效算力</view>
+						<view class="">{{ ls.step }}T</view>
+					</view>
+					<view class="tpl">
+						<view class="">合约周期</view>
+						<view class="">{{ ls.first_step_time + ls.second_step_time + ls.third_step_time }}天</view>
+					</view>
+				</view>
+				<view class="cell-info flex">
+					<!-- <view class="tip">剩余数量:{{ls.stock}}/{{ls.all_stock}}T</view> -->
+					<view class="tip">剩余数量:{{ ls | dataStock }}</view>
+					<view class="zhiya-btn" v-if="ls.stock > 0" @click="ToBuy(ls)">{{ ls.type == 3 ? '立即质押' : '立即购买' }}</view>
+					<view class="zhiya-btn grey" v-if="ls.stock == 0">已售罄</view>
+				</view>
+				<view class="list-tip" v-if="ls.detail"><rich-text :nodes="ls.detail"></rich-text></view>
+			</view>
+			<view class="empty-box" v-show="list.length === 0"><empty></empty></view>
+		</view>
+		<uni-popup ref="popup" type="center">
+			<view class="popup">
+				<view class="cancel flex" @click="close">
+					<view></view>
+					<view class="tip">x</view>
+				</view>
+				<view class="list-box">
+					<view class="popup-text">购买数量:</view>
+					<view class="password"><input type="number" v-model="num" /></view>
+					<view class="popup-text">支付密码:</view>
+					<view class="password"><input type="password" v-model="password" /></view>
+					<view class="confirm-btn" @click="pay"><text>确认购买</text></view>
+				</view>
+			</view>
+		</uni-popup>
+	</view>
+</template>
+<script>
+import { mining, buyMining } from '@/api/calculation.js';
+import { moneyType } from '@/api/index.js';
+import empty from '@/components/empty';
+export default {
+	components: {
+		empty
+	},
+	filters: {
+		dataStock: function(ls) {
+			let type = 'T';
+			// if (+ls.stock >= 1024) {
+			// 	// type = 'P';
+			// 	return `${ls.stock/1024 }/${ls.all_stock/1024 }${type}`;
+			// } else {
+			// 	return `${ls.stock}/${ls.all_stock}${type}`;
+			// }
+			return `${+ls.stock}${type}/${+ls.all_stock}${type}`;
+		}
+	},
+	data() {
+		return {
+			tabCurrent: 'XCH',
+			tabType: 1,
+			moneyTypeList: [
+				{
+					code: 'XCH',
+					name: 'XCH',
+					has_mining: 1
+				},
+				{
+					code: 'USDT',
+					name: 'USDT',
+					has_mining: 0
+				},
+				{
+					code: 'BTC',
+					name: 'BTC',
+					has_mining: 0
+				},
+				{
+					code: 'ETH',
+					name: 'ETH',
+					has_mining: 0
+				},
+				{
+					code: 'FIL',
+					name: 'FIL',
+					has_mining: 0
+				}
+			],
+			list: [],
+			buyId: '',
+			password: '',
+			num: ''
+		};
+	},
+	onLoad(option) {
+		this.moneyType();
+		this.loadData();
+	},
+	onShow() {},
+	//下拉刷新
+	onPullDownRefresh() {
+		this.moneyType();
+	},
+	methods: {
+		// 所有币种
+		async moneyType() {
+			let obj = this;
+			console.log(obj.moneyTypeList);
+			moneyType({}).then(({ data }) => {
+				obj.moneyTypeList = data;
+				// if(obj.moneyTypeList.length > 0){
+				// 	obj.tabCurrent = obj.moneyTypeList[0].code
+				// }
+			});
+		},
+		// 请求载入数据
+		async loadData() {
+			let obj = this;
+			uni.showLoading({
+				title: '加载中...'
+			});
+			mining({
+				page: 1,
+				limit: 1000,
+				type: obj.tabType,
+				get_money_type: obj.tabCurrent
+			}).then(({ data }) => {
+				console.log(data,"1111");
+				obj.list = data.data.map(e => {
+					e.step = +e.step;
+					e._cost_money = +(e._cost_money.replace(e.cost_money_type,''))+e.cost_money_type;
+					return e;
+				});
+				uni.hideLoading();
+			});
+		},
+		ToBuy(ls) {
+			// let obj = this;
+			// obj.buyId = id;
+			// this.$refs.popup.open();
+			uni.navigateTo({
+				url: '/pages/calculation/details?id=' + ls.id + '&type=' + ls.type
+			});
+		},
+		pay() {
+			let obj = this;
+			buyMining(
+				{
+					num: obj.num,
+					trade_psw: obj.password
+				},
+				obj.buyId
+			)
+				.then(({ data }) => {
+					obj.$api.msg('购买成功!');
+					obj.loadData();
+					obj.password = '';
+					obj.num = '';
+					obj.$refs.popup.close();
+				})
+				.catch(e => {
+					obj.loadData();
+					obj.password = '';
+					obj.num = '';
+					obj.$refs.popup.close();
+				});
+		},
+		close() {
+			this.$refs.popup.close();
+		},
+		tabClick(index, has_mining) {
+			if (has_mining == 0) {
+				this.$api.msg('敬请期待!');
+			} else {
+				this.tabCurrent = index;
+				this.loadData();
+			}
+		},
+		tabTypeClick(index) {
+			this.tabType = index;
+			this.loadData();
+		}
+	}
+};
+</script>
+
+<style lang="scss">
+page {
+	min-height: 100%;
+	background-color: #ffffff;
+	.container {
+		width: 100%;
+	}
+}
+.logo-img {
+	margin: 40rpx 6%;
+	width: 88%;
+	height: 209rpx;
+}
+.list-box {
+	.list-title {
+		overflow: hidden;
+		white-space: nowrap;
+		.title {
+			display: inline-block;
+			background-color: #bac1ef;
+			font-size: 30rpx;
+			font-weight: bold;
+			color: #ffffff;
+			width: 24.49%;
+			margin-right: 5rpx;
+			text-align: center;
+			line-height: 60rpx;
+		}
+		.blue {
+			background-color: #5771df;
+		}
+		.grey {
+			background-color: #dbdbdb !important;
+		}
+	}
+	.list-name {
+		padding: 24rpx 50rpx;
+		.name {
+			font-size: 28rpx;
+			margin-right: 20%;
+			font-weight: 500;
+			color: #666666;
+		}
+		.black {
+			color: #333333;
+			border-bottom: 2rpx solid #5771df;
+			padding-bottom: 10rpx;
+			font-size: 30rpx;
+		}
+	}
+}
+.more {
+	color: #606266;
+	font-size: 24rpx;
+	font-weight: normal;
+	border-bottom: 1rpx solid #606266;
+}
+.all-list {
+	width: 180rpx;
+	height: 180rpx;
+}
+.list-cell {
+	padding: 40rpx 40rpx;
+	.cell-title {
+		padding: 29rpx 38rpx;
+		font-size: 30rpx;
+		font-weight: bold;
+		color: #333333;
+		image {
+			width: 40rpx;
+			height: 40rpx;
+			margin-right: 15rpx;
+		}
+	}
+	.cell-tip {
+		padding: 0rpx 38rpx;
+		font-size: 24rpx;
+		font-weight: bold;
+		color: #0ec1a1;
+	}
+	.cell-tpl {
+		padding: 50rpx 31rpx;
+		font-size: 24rpx;
+		font-weight: bold;
+		color: #333333;
+		line-height: 40rpx;
+	}
+	.cell-info {
+		.tip {
+			font-size: 30rpx;
+			font-weight: bold;
+			color: #5771df;
+			line-height: 55px;
+		}
+		.zhiya-btn {
+			background-color: #5771df;
+			width: 150rpx;
+			text-align: center;
+			line-height: 60rpx;
+			font-size: 24rpx;
+			border-radius: 50rpx;
+			color: #ffffff;
+		}
+		.grey {
+			background-color: #999999;
+		}
+	}
+	.list-tip {
+		background-color: #bac1ef !important;
+		word-wrap: break-word;
+		font-size: 24rpx;
+		font-weight: 500;
+		color: #333333;
+		padding: 36rpx 32rpx;
+		margin-top: 15rpx;
+		border-bottom-left-radius: 15rpx;
+		border-bottom-right-radius: 15rpx;
+	}
+}
+.empty-box {
+	width: 100%;
+	height: 500rpx;
+}
+//弹窗
+.popup {
+	background-color: #ffffff;
+	border-radius: 25rpx;
+	font-size: 30rpx;
+	.cancel {
+		text-align: center;
+		width: 100%;
+		line-height: 60rpx;
+		.tip {
+			background-color: #5771df;
+			color: #ffffff;
+			width: 70rpx;
+			height: 70rpx;
+			border-top-right-radius: 25rpx;
+		}
+	}
+	.list-box {
+		padding: 0rpx 80rpx;
+		.password {
+			padding: 50rpx 0rpx;
+			width: 100%;
+			input {
+				width: 70%;
+				height: 80rpx;
+				border: 2rpx solid #999999;
+				padding-left: 25rpx;
+				box-shadow: 0px 3px 5px 0px rgba(0, 0, 0, 0.27);
+				border-radius: 11rpx;
+			}
+		}
+		.confirm-btn {
+			padding-bottom: 120rpx;
+			padding-top: 30rpx;
+			text {
+				background-color: #5771df;
+				color: #ffffff;
+				width: 70%;
+				text-align: center;
+				padding: 25rpx 90rpx;
+				border-radius: 15rpx;
+			}
+		}
+	}
+}
+</style>

+ 150 - 0
pages/calculation/computer.vue

@@ -0,0 +1,150 @@
+<template>
+	<view class="container">
+		<view class="list-cell">
+			<view class="list-name">有效算力</view>
+			<view class="list-tpl flex">
+				<view class="tip"><input type="number" v-model="num" placeholder="请输入有效算力"></view>
+				<view class="tpl">T</view>
+			</view>
+		</view>
+		<view class="list-cell">
+			<view class="list-name">XCH价格</view>
+			<view class="list-tpl flex">
+				<view class="tip">{{list.fli_usdt}}</view>
+				<view class="tpl">USDT</view>
+			</view>
+		</view><view class="list-cell">
+			<view class="list-name">算力单价</view>
+			<view class="list-tpl flex">
+				<view class="tip">{{list.machine_price}}</view>
+				<view class="tpl">{{list.machine_price_type}}</view>
+			</view>
+		</view><view class="list-cell">
+			<view class="list-name">算力收益</view>
+			<view class="list-tpl flex">
+				<view class="tip">{{list.machine_get}}</view>
+				<view class="tpl">XCH/T</view>
+			</view>
+		</view><view class="list-cell">
+			<view class="list-name">合约周期</view>
+			<view class="list-tpl flex">
+				<view class="tip">{{list.time}}</view>
+				<view class="tpl">天</view>
+			</view>
+		</view>
+		<view class="submit-box">
+			<view class="submit" @click="jisuan">计算收益</view>
+		</view>
+		<view class="tips">计算结果仅供参考,具体以实际交易为准。</view>
+		<view class="jisuan-box" v-show="infoShow == true">
+			<view class="flex jisuan">
+				<view>投入资金</view>
+				<view>{{moeny}}</view>
+			</view>
+			<view class="flex jisuan">
+				<view>有效算力</view>
+				<view>{{suanli}}</view>
+			</view>
+			<view class="flex jisuan">
+				<view>回本期</view>
+				<view>{{huiben}}</view>
+			</view>
+			<view class="flex jisuan">
+				<view>算力年华收益率</view>
+				<view>{{year}}</view>
+			</view>
+			<view class="flex jisuan">
+				<view>每月产币</view>
+				<view>{{month}}</view>
+			</view>
+		</view>
+	</view>
+</template>
+<script>
+import { calculator } from '@/api/calculation.js';
+export default {
+	data() {
+		return {
+			list:'',
+			num:'',
+			moeny:'',
+			suanli:'',
+			huiben:'',
+			year:'',
+			month:'',
+			infoShow:false
+		};
+	},
+	onLoad(option){
+		this.loadData();
+	},
+	onShow() {
+		
+	},
+	methods: {
+		async loadData(){
+			let obj = this;
+			calculator({}).then(({ data }) => {
+				obj.list = data;
+			});
+		},
+		jisuan(){
+			if(this.num < 0 || this.num ==''){
+				this.$api.msg('请输入大于或等于1的有效算力!');
+				return;
+			}
+			this.moeny = (this.list.machine_price)*(this.num);
+			this.suanli = this.num;
+			this.huiben = (this.list.get_back)*(this.num);
+			this.year = (this.list.year_get)*(this.num);
+			this.month = (this.list.month_back)*(this.num);
+			this.infoShow = true;
+		},
+	}
+};
+</script>
+
+<style lang="scss">
+page {
+	min-height: 100%;
+	background-color: #ffffff;
+	.container {
+		width: 100%;
+		padding: 20rpx 50rpx;
+		
+	}
+}
+.list-cell{
+	font-size: 28rpx;
+	font-weight: bold;
+	color: #333333;
+	padding: 0rpx 32rpx;
+	padding-top: 50rpx;
+	.list-tpl{
+		padding-top: 50rpx;
+	}
+}
+.submit-box{
+		padding: 54rpx 50rpx;
+		.submit{
+			background-color: #5771DF;
+			color: #FFFFFF;
+			font-size: 30rpx;
+			padding: 26rpx 0rpx;
+			border-radius: 50rpx;
+			text-align: center;
+		}
+	}
+	.tips{
+		color: #FB3A2F;
+		font-size: 24rpx;
+		font-weight: 500;
+	}
+	.jisuan-box{
+		margin: 80rpx 0rpx;
+		.jisuan{
+			padding-bottom: 50rpx;
+			font-size: 26rpx;
+		}
+	}
+</style>

+ 260 - 0
pages/calculation/details.vue

@@ -0,0 +1,260 @@
+<template>
+	<view class="container">
+		<view class="list-box"></view>
+		<view class="list">
+			<view class="list-title">{{ list.name }}</view>
+			<view class="flex list-item">
+				<view class="item-name">价格</view>
+				<view class="item-tpl">{{ list.cost_money * 1 }}{{ list._cost_money_type }}</view>
+			</view>
+			<view class="flex list-item" v-if="list.stand_money > 0">
+				<view class="item-name">质押FIL数量(用户自行支付)</view>
+				<view class="item-tpl">{{ list.stand_money * 1 }}</view>
+			</view>
+			<view class="flex list-item">
+				<view class="item-name">托管运维费</view>
+				<view class="item-tpl">{{ list.service_ratio }}%</view>
+			</view>
+			<view class="flex list-item">
+				<view class="item-name">上架期</view>
+				<view class="item-tpl">{{ list.stand_time }}天</view>
+			</view>
+			<!-- <view class="flex list-item">
+				<view class="item-name">封装期</view>
+				<view class="item-tpl">{{list.first_step_time}}</view>
+			</view> -->
+			<view class="flex list-item">
+				<view class="item-name">合约期</view>
+				<view class="item-tpl">{{ list.first_step_time + list.second_step_time + list.third_step_time }}天</view>
+			</view>
+			<!-- <view class="tpl" v-if="list.stand_money > 0">需完成应质押的FIL后,才能开始进入50天封装期</view> -->
+			<view class="num-box flex">
+				<view class="num-title">购买数量(1T)</view>
+				<uni-number-box class="step" :value="num" :disabled="false" @eventChange="numberChange"></uni-number-box>
+			</view>
+			<view class="flex money-box">
+				<view class="money-name">金额</view>
+				<view class="money-num">{{ money * 1 }}{{ list._cost_money_type }}</view>
+			</view>
+			<view class="flex money-box">
+				<view class="money-name">交易密码</view>
+				<view class="money-num"><input class="input-box" type="password" v-model="password" placeholder="请输入交易密码" /></view>
+			</view>
+			<view class="pay-box">支付方式:{{ list._cost_money_type }}</view>
+			<!-- <view class="list-title">IPFS独享算力包-1T</view> -->
+			<view class="tips">说明:</view>
+			<view class="explain"><rich-text :nodes="list.detail"></rich-text></view>
+			<view class="check_box flex_item">
+				<view><radio style="transform: scale(0.75)" @click="Getcheckbox" color="#6786FB" :checked="checked" /></view>
+				<view class="">
+					请阅读并同意
+					<text @click="ToIndex">《矿机租赁协议》</text>
+				</view>
+			</view>
+			<view class="submit-box">
+				<view class="submit" @click="pay()">{{ type == 3 ? '立即质押' : '立即购买' }}</view>
+			</view>
+		</view>
+	</view>
+</template>
+<script>
+import { miningDateils, buyMining } from '@/api/calculation.js';
+import uniNumberBox from '@/components/uni-number-box.vue';
+export default {
+	components: {
+		uniNumberBox
+	},
+	data() {
+		return {
+			id: '',
+			type: '',
+			num: 1,
+			password: '',
+			money: '',
+			price: '',
+			list: {
+				
+			},
+			checked: false
+		};
+	},
+	onLoad(option) {
+		this.id = option.id;
+		this.type = option.type;
+		this.loadData();
+	},
+	watch: {
+		num(newVal, oldVal) {
+			this.money = this.num * this.price;
+		}
+	},
+	onShow() {},
+	methods: {
+		async loadData() {
+			let obj = this;
+			miningDateils({}, obj.id).then(({ data }) => {
+				obj.list = data;
+				obj.money = obj.list.cost_money;
+				obj.price = obj.list.cost_money;
+			});
+		},
+		//阅读并同意
+		Getcheckbox() {
+			let obj = this;
+			obj.checked = !obj.checked;
+		},
+		ToIndex() {
+			uni.navigateTo({
+				url: '/pages/finance/xieyi'
+			});
+		},
+		pay() {
+			let obj = this;
+			if (obj.password == '') {
+				obj.$api.msg('请输入交易密码!');
+				return;
+			}
+			if (obj.checked == false) {
+				obj.$api.msg('请阅读并同意协议!');
+				return;
+			}
+			buyMining(
+				{
+					num: obj.num,
+					trade_psw: obj.password
+				},
+				obj.id
+			)
+				.then(data => {
+					obj.$api.msg(data.msg);
+					obj.password = '';
+					obj.num = 1;
+				})
+				.catch(e => {
+					obj.password = '';
+					obj.num = 1;
+					if (e.msg == '交易密码错误') {
+						return;
+					}
+					console.log(e);
+					var reg = new RegExp('购买矿机所需的');
+					if (e.msg.match(reg) == -1) {
+					} else {
+						setTimeout(function() {
+							uni.navigateTo({
+								url: '/pages/finance/recharge'
+							});
+						}, 1000);
+					}
+				});
+		},
+		numberChange(data) {
+			let obj = this;
+			obj.num = data.number;
+		}
+	}
+};
+</script>
+
+<style lang="scss" scoped>
+page {
+	min-height: 100%;
+	background-color: #ffffff;
+	.container {
+		width: 100%;
+	}
+}
+.list-box {
+	background-color: #5771df;
+	width: 100%;
+	height: 200rpx;
+}
+.list {
+	margin: 0rpx 31rpx;
+	padding: 45rpx 35rpx;
+	background-color: #ffffff;
+	border-radius: 15rpx;
+	position: relative;
+	top: -100rpx;
+	.list-title {
+		font-size: 34rpx;
+		font-weight: 500;
+		color: #333333;
+		padding-bottom: 35rpx;
+	}
+	.list-item {
+		font-size: 24rpx;
+		font-weight: 500;
+		color: #666666;
+		padding-bottom: 35rpx;
+		.item-tpl {
+			font-size: 24rpx;
+			font-weight: bold;
+			color: #333333;
+		}
+		.tpls {
+			color: #faba38;
+		}
+	}
+	.tpl {
+		font-size: 26rpx;
+		font-weight: 500;
+		color: #faba38;
+		padding-bottom: 98rpx;
+	}
+	.num-box {
+		font-size: 30rpx;
+		font-weight: 500;
+		color: #333333;
+		padding-bottom: 83rpx;
+	}
+	.money-box {
+		font-size: 32rpx;
+		font-weight: 500;
+		color: #333333;
+		padding-bottom: 102rpx;
+		.money-num {
+			font-weight: bold;
+			.input-box {
+				text-align: right;
+			}
+		}
+	}
+	.pay-box {
+		font-size: 24rpx;
+		font-weight: 500;
+		color: #333333;
+		padding-bottom: 60rpx;
+	}
+	.tips {
+		font-size: 26rpx;
+		font-weight: 500;
+		color: #5771df;
+		padding-bottom: 25rpx;
+	}
+	.explain {
+		word-wrap: break-word;
+		font-size: 26rpx;
+		font-weight: 500;
+		color: #666666;
+		line-height: 38rpx;
+	}
+}
+.submit-box {
+	.submit {
+		background-color: #5771df;
+		color: #ffffff;
+		text-align: center;
+		padding: 25rpx 0rpx;
+		border-radius: 50rpx;
+	}
+}
+.check_box {
+	padding: 25rpx 25rpx;
+	font-size: 28rpx;
+	padding-bottom: 60rpx;
+	text {
+		color: #6786fb;
+	}
+}
+</style>

+ 260 - 0
pages/calculation/index.vue

@@ -0,0 +1,260 @@
+<template>
+	<view class="container">
+		<view class="list-box">
+			<view class="list flex">
+				<view class="list-tpls">
+					<view class="tpls-num">{{list.all}}T</view>
+					<view class="tpls-name">总算力</view>
+				</view>
+				<view class="level-box">
+					<image src="../../static/img/img28.png"></image>
+					<view class="level">V{{level}}</view>
+				</view>
+			</view>
+			<view class="list-item flex">
+				<view class="item-tpl">
+					<view class="tpl name">已P好</view>
+					<view class="tpl num">{{list.doing}}T</view>
+				</view>
+				<view class="item-tpl">
+					<view class="tpl name">P盘中</view>
+					<view class="tpl num">{{list.stand}}T</view>
+				</view>
+			</view>
+			<view class="list-item">
+				<view class="item-tpl tols">
+					<view class="tpl name">累计挖币</view>
+					<view class="tpl num">{{list.all_mining}}XCH</view>
+				</view>
+				<!-- <view class="item-tpl">
+					<view class="tpl name">当前锁仓</view>
+					<view class="tpl num">{{list.all_lock}}FIL</view>
+				</view> -->
+			</view>
+			<view class="submit-box flex">
+				<view class="submit" @click="navTo('/pages/calculation/myCalculation')">我的算力</view>
+				<view class="submit" @click="navTo('/pages/calculation/buyCalculation')">购买算力</view>
+			</view>
+		</view>
+		<image @click="navTo('/pages/calculation/computer')"  class="logo-img" src="../../static/img/img34.png"></image>
+		<!-- <view class="item-box">
+			<view class="item-tile flex_item">
+				<image src="../../static/img/img02.png"></image>
+				<view class="title">f0111469/存储0.0TB</view>
+			</view>
+			<view class="item-list flex">
+				<view class="tpl-box">
+					<view class="flex tpl">
+						<view class="name">今日挖币</view>
+						<image src="../../static/img/img03.png"></image>
+					</view>
+					<view class="list-tip">0.0FIL</view>
+				</view>
+				<view class="tpl-box">
+					<view class="flex tpl">
+						<view class="name">挖矿到期</view>
+						<image src="../../static/img/img03.png"></image>
+					</view>
+					<view class="list-tip">0.0FIL</view>
+				</view>
+				<view class="tpl-box">
+					<view class="flex tpl">
+						<view class="name">销售奖励</view>
+						<image src="../../static/img/img03.png"></image>
+					</view>
+					<view class="list-tip">0.0FIL</view>
+				</view>
+			</view>
+			<view class="item-list flex">
+				<view class="tpl-box">
+					<view class="flex tpl">
+						<view class="name">挖币奖励</view>
+						<image src="../../static/img/img03.png"></image>
+					</view>
+					<view class="list-tip">0.0FIL</view>
+				</view>
+				<view class="tpl-box">
+					<view class="flex tpl">
+						<view class="name">已释放FIL</view>
+						<image src="../../static/img/img03.png"></image>
+					</view>
+					<view class="list-tip">0.0FIL</view>
+				</view>
+				<view class="tpl-box">
+					<view class="flex tpl">
+						<view class="name">锁仓FIL</view>
+						<image src="../../static/img/img03.png"></image>
+					</view>
+					<view class="list-tip">0.0FIL</view>
+				</view>
+			</view>
+		</view> -->
+	</view>
+</template>
+<script>
+import { mining,miningIndex } from '@/api/calculation.js';
+export default {
+	data() {
+		return {
+			list:'',
+			level:'',
+		};
+	},
+	onLoad(option){
+		let userInfo = uni.getStorageSync('userInfo') || '';
+		this.level = userInfo.level;
+		this.loadData();
+	},
+	onShow() {
+		
+	},
+	//下拉刷新
+	onPullDownRefresh() {
+		this.loadData();
+		setTimeout(function () {
+			uni.stopPullDownRefresh();
+		}, 1000);
+	},
+	methods: {
+		// 请求载入数据
+		async loadData() {
+			let obj = this;
+			miningIndex({}).then(({ data }) => {
+				obj.list = data;
+			});
+		},
+		/**
+		 * 统一跳转接口,拦截未登录路由
+		 * navigator标签现在默认没有转场动画,所以用view
+		 */
+		navTo(url) {
+			uni.navigateTo({
+				url
+			});
+		},
+	}
+};
+</script>
+
+<style lang="scss">
+page {
+	min-height: 100%;
+	background-color: #ffffff;
+	.container {
+		width: 100%;
+		padding: 20rpx 40rpx;
+		
+	}
+}
+.list-box{
+	padding:30rpx 25rpx;
+	background-image: url(../../static/img/img42.png);
+	background-size: 100% 100%;
+	.list{
+		padding:30rpx 0rpx;
+		margin-bottom: 40rpx !important;
+		.list-tpls{
+			.tpls-num{
+				font-weight: bold;
+				color: #333333;
+				font-size: 40rpx;
+				padding-bottom: 30rpx;
+			}
+		}
+		.level-box{
+			position: relative;
+			image{
+				width: 128rpx;
+				height:45rpx;
+			}
+			.level{
+				position: absolute;
+				top: 12rpx;
+				left: 62rpx;
+				font-size: 24rpx;
+				color: #826740;
+				font-weight: bold;
+			}
+		}
+	}
+	.list-item{
+		// padding: 90rpx 118rpx 0 118rpx;
+		margin-bottom: 15rpx;
+		.item-tpl{
+			text-align: center;
+			background-color: #FFFFFF;
+			padding: 41rpx 0;
+			width: 48%;
+			.name{
+				color: #666666;
+				font-size: 24rpx;
+			}
+			.num{
+				font-size: 32rpx;
+				color: #333333;
+				font-weight: bold;
+				padding-top: 10rpx;
+			}
+		}
+	}
+	.tols{
+		width: 100% !important;
+		
+	}
+	.submit-box{
+		margin-top: 50rpx;
+		.submit{
+			background-color: #5771DF;
+			color: #FFFFFF;
+			font-size: 30rpx;
+			padding: 25rpx 0;
+			width: 40%;
+			text-align: center;
+			border-radius: 50rpx;
+		}
+	}
+}
+.logo-img{
+	width: 100%;
+	height: 208rpx;
+	margin: 40rpx 0rpx;
+}
+.item-box{
+	padding: 15rpx 25rpx;
+	.item-tile{
+		padding-bottom: 80rpx;
+		.title{
+			padding-left: 15rpx;
+			font-weight: bold;
+			color: #333333;
+			font-size: 30rpx;
+		}
+		image{
+			width: 44rpx;
+			height: 44rpx;
+		}
+	}
+	.item-list{
+		padding-bottom: 67rpx;
+		.tpl-box{
+			.tpl{
+				.name{
+					color: #666666;
+					font-size: 24rpx;
+					padding-right: 10rpx;
+					padding-bottom: 15rpx;
+				}
+				image{
+					width: 25rpx;
+					height: 25rpx;
+				}
+			}
+			.list-tip{
+				font-size: 28rpx;
+				font-weight: bold;
+				color: #333333;
+			}
+		}
+	}
+}
+</style>

+ 148 - 0
pages/calculation/myCalculation.vue

@@ -0,0 +1,148 @@
+<template>
+	<view class="container">
+		<view class="list-cell" v-if="list.length > 0" v-for="(ls,index) in list" :key='index'>
+			<view class="cell-title flex">
+				<view class="cellTpl flex_item">
+					<image :src="ls.machine.logo"></image>
+					<view class="title">{{ls.machine.name}}</view>
+				</view>
+				<view class="status">{{ls.status == 0 ? '准备中' : ls.status ==  1 ? '挖矿中' : '已到期'}}</view>
+			</view>
+			<view class="cell-tip">{{ls.machine.first_step_time + ls.machine.second_step_time + ls.machine.third_step_time}}天矿机</view>
+			<view class="flex cell-tpl">
+				<view class="tpl">
+					<view class="">单价</view>
+					<view class="">{{ls.machine.cost_money}}</view>
+				</view>
+				<view class="tpl">
+					<view class="">有效算力</view>
+					<view class="">{{ls.num * 1}}T</view>
+				</view>
+				<view class="tpl">
+					<view class="">合约周期</view>
+					<view class="">{{ls.machine.first_step_time + ls.machine.second_step_time + ls.machine.third_step_time}}天</view>
+				</view>
+			</view>
+			<view class="cell-info flex">
+				<view class="tip">到期时间:{{ls.mining_end_time}}</view>
+			</view>
+			<!-- <view class="cell-info flex">
+				<view class="tip">正式挖矿时间:{{ls.mining_start_time}}</view>
+			</view> -->
+			<view class="list-tip">
+				<rich-text :nodes="ls.machine.detail"></rich-text>
+			</view>
+		</view>
+		<view class="empty-box" v-show="list.length === 0"><empty></empty></view>
+	</view>
+</template>
+<script>
+import { mymining } from '@/api/calculation.js';
+import empty from '@/components/empty';
+export default {
+	components: {
+		empty
+	},
+	data() {
+		return {
+			list:'',
+		};
+	},
+	onLoad(option){
+		this.loadData();
+	},
+	onShow() {
+		
+	},
+	//下拉刷新
+	onPullDownRefresh() {
+		this.loadData();
+	},
+	methods: {
+		async loadData() {
+			let obj = this;
+			mymining({
+				page:1,
+				limit:1000,
+			}).then(({ data }) => {
+				console.log(data);
+			    obj.list = data.data;
+			});
+		},
+	}
+};
+</script>
+
+<style lang="scss">
+page {
+	min-height: 100%;
+	background-color: #ffffff;
+	.container {
+		width: 100%;
+		
+	}
+}
+.list-cell{
+		padding: 40rpx 40rpx;
+		.cell-title{
+			padding: 29rpx 38rpx;
+			font-size: 30rpx;
+			font-weight: bold;
+			color: #333333;
+			.cellTpl{
+				image{
+					width: 40rpx;
+					height: 40rpx;
+					margin-right: 15rpx;
+				}
+			}
+			.status{
+				color: #E51C23;
+			}
+		}
+		.cell-tip{
+			padding: 0rpx 38rpx;
+			font-size: 24rpx;
+			font-weight: bold;
+			color: #0EC1A1;
+		}
+		.cell-tpl{
+			padding: 40rpx 31rpx;
+			font-size: 24rpx;
+			font-weight: bold;
+			color: #333333;
+			line-height: 40rpx;
+		}
+		.cell-info{
+			margin-bottom: 25rpx;
+			.tip{
+				font-size: 30rpx;
+				font-weight: bold;
+				color: #5771DF;
+			}
+			.zhiya-btn{
+				background-color: #5771DF;
+				padding: 12rpx 22rpx;
+				font-size: 24rpx;
+				border-radius: 50rpx;
+				color: #FFFFFF;
+			}
+		}
+		.list-tip{
+			word-wrap:break-word;
+			background-color: #BAC1EF !important;
+			font-size: 24rpx;
+			font-weight: 500;
+			color: #333333;
+			padding: 36rpx 32rpx;
+			margin-top: 15rpx;
+			border-bottom-left-radius:15rpx ;
+			border-bottom-right-radius:15rpx ;
+		}
+	}
+	.empty-box{
+		margin-top: 100rpx;
+		width: 100%;
+		height: 500rpx;
+	}
+</style>

+ 168 - 0
pages/finance/allMiner.vue

@@ -0,0 +1,168 @@
+<template>
+	<view class="container">
+		<view class="info-box">
+			<view class="list-cell" v-if="list.length > 0">
+				<view class="cell-name flex">
+					<view class="title">成员信息</view>
+					<view class="title-box flex">
+						<view class="title">等待算力</view>
+						<view class="title">算力</view>
+						<view class="title">等级</view>
+					</view>
+				</view>
+				<view class="cell-box flex" v-for="(ls,index) in list" :key='index'>
+					<view class="cell-tit flex_item">
+						<image :src="ls.avatar"></image>
+						<view class="tit-box">
+							<view class="tit-tpl clamp">{{ls.nickname}}</view>
+							<view class="tit-tip">{{ls.phone}}</view>
+						</view>
+					</view>
+					<view class="flex num-box">
+						<view class="num clamp">{{ls.wait_mining}}T</view>
+						<view class="num clamp">{{ls.mining}}T</view>
+						<view class="level">V{{ls.level}}</view>
+					</view>
+				</view>
+			</view>
+			<view class="empty-box" v-show="list.length === 0"><empty></empty></view>
+		</view>
+	</view>
+</template>
+
+<script>
+import { miner } from '@/api/finance.js';
+import empty from '@/components/empty';
+export default {
+	components: {
+		empty
+	},
+	data() {
+		return {
+			loadingType: 'more',
+			data:'',
+			list:'',
+		};
+	},
+	onLoad(option){
+		this.loadData("add");
+	},
+	onShow() {
+	},
+	methods: {
+		// 请求载入数据
+		async loadData(type = "add",loading) {
+			let obj = this;
+			if (type === 'add'){
+				if (obj.loadingType === 'nomore'){
+					return;
+				}
+				obj.loadingType = 'loading';
+			}else {
+				obj.loadingType = 'more';
+			}
+			
+			miner({
+				page: 1,
+				limit: 20,
+				
+			}).then(({ data }) => {
+				console.log(data);
+				obj.data = data;
+				obj.list = data.list;
+				if(obj.limit == data.list.length){
+					obj.page++
+					obj.loadingType="more"
+				}else{
+					obj.loadingType="nomore"
+				}
+				
+			});
+		},
+	}
+}
+</script>
+
+<style lang="scss">
+	page {
+		min-height: 100%;
+		background-color: #ffffff;
+		.container {
+			width: 100%;
+		}
+	}
+	.info-box{
+		
+		.info-name{
+			padding: 40rpx 0rpx;
+			.info-cell{
+				width: 33.33%;
+				text-align: center;
+				.cell{
+					font-size: 38rpx;
+					font-weight: bold;
+					color: #333333;
+				}
+				.cell-title{
+					font-size: 26rpx;
+					font-weight: 500;
+					color: #999999;
+					padding-top: 20rpx;
+				}
+			}
+		}
+		.list-cell{
+			padding: 10rpx 25rpx;
+			.cell-name{
+				padding:50rpx 50rpx;
+				.title-box{
+					width: 60%;
+				}
+			}
+			.cell-box{
+				margin-bottom: 94rpx;
+				.cell-tit{
+					width: 40%;
+					image{
+						width: 80rpx;
+						height: 80rpx;
+						border-radius: 100%;
+					}
+					.tit-box{
+						padding-left: 15rpx;
+						width: 70%;
+						.tit-tpl{
+							font-size: 30rpx;
+							font-weight: 500;
+							color: #333333;
+						}
+						.tit-tip{
+							font-size: 24rpx;
+							font-weight: 500;
+							color: #999999;
+							padding-top: 20rpx;
+						}
+					}
+				}
+				.num-box{
+					width: 60%;
+					.num{
+						width: 33.33%;
+						text-align: center;
+					}
+					.level{
+						background-color: #FED82F;
+						border-radius: 25rpx;
+						padding: 8rpx 50rpx;
+						font-size: 26rpx;
+					}
+				}
+			}
+		}
+	}
+	.empty-box{
+		margin-top: 60rpx;
+		width: 100%;
+		height: 500rpx;
+	}
+</style>

+ 132 - 0
pages/finance/computat.vue

@@ -0,0 +1,132 @@
+<template>
+	<view class="container">
+		<view class="swiper-box">
+			<scroll-view scroll-y class="cate-list" @scrolltolower="loadData">
+				<view v-for="(item, index) in orderList" class="content-box">
+					<view class="list-box">
+						<view class="list-item">订单号:{{item.order_id}}</view>
+						<view class="list-item">产品名称:{{item.body}}</view>
+						<view class="list-item">购买数量:{{item.num}}</view>
+						<view class="list-item">状态:{{item.status}}</view>
+						<view class="list-item grey">购买时间:{{item.add_time}}</view>
+						<view class="list-item grey">到期倒计时:{{item.end_time}}</view>
+					</view>
+				</view>
+				<uni-load-more :status="loadingType"></uni-load-more>
+			</scroll-view>
+		</view>
+	</view>
+</template>
+<script>
+	import { order } from '@/api/quotation.js';
+	import { getTime } from '@/utils/rocessor.js';
+export default {
+	data() {
+		return {
+			loadingType:'',
+			loading:'',
+			page:1,
+			limit:3,
+			orderList:[],
+			
+		};
+	},
+	onShow: function() {
+		this.loadData();
+	},
+	methods: {
+		// 请求载入数据
+		async loadData(type) {
+			//这里是将订单挂载到tab列表下
+			let obj = this;
+			if (type != 'refresh') {
+				//没有更多数据直接跳出方法
+				if (obj.loadingType === 'nomore') {
+					return;
+				} else {
+					// 设置当前为数据载入中
+					obj.loadingType = 'loading';
+				}
+			} else {
+				//当重新加载数据时更新状态为可继续添加数据
+				obj.loadingType = 'more';
+			}
+			order({
+				page: obj.page,
+				limit: obj.limit
+			})
+				.then(({ data }) => {
+					if (type === 'refresh') {
+						obj.orderList = [];
+					}
+					let arr = data.list.map(e => {
+						let now = new Date();
+						//现在时间转换成时间戳
+						let nowTime = now.getTime();
+						let data = e.end_time;
+						data = data.replace(/-/g, '/');
+						let time = new Date(data);
+						let end_time = time.getTime();
+						if(nowTime > end_time){
+							e.status = '过期了'
+						}else{
+							e.status = '正常'
+						}
+						return e;
+					});
+					obj.orderList = obj.orderList.concat(arr);
+					//判断是否还有下一页,有是more  没有是nomore
+					if (obj.limit == arr.length) {
+						obj.page++;
+						obj.loadingType = 'more';
+					} else {
+						obj.loadingType = 'nomore';
+					}
+					// 判断是否为刷新数据
+					if (type == 'refresh') {
+						// 判断是否为点击搜索按钮跳转加载
+						if (obj.loading == 1) {
+							uni.hideLoading();
+						} else {
+							uni.stopPullDownRefresh();
+						}
+					}
+				})
+				.catch(e => {
+					obj.loadingType = 'nomore';
+					uni.stopPullDownRefresh();
+					uni.hideLoading();
+				});
+		},
+	}
+};
+</script>
+
+<style lang="scss">
+page {
+	min-height: 100%;
+	background-color: #F7F7F7;
+	.container {
+		width: 100%;
+		background-color: #FFFFFF;
+		font-size: 30rpx;
+	}
+}
+.swiper-box {
+	height: 90vh;
+	.cate-list {
+		height: 90vh;
+	}
+}
+.list-box{
+	padding: 25rpx 25rpx;
+	border-bottom: 2rpx solid #EAEAEA;
+	.list-item{
+		padding-bottom: 25rpx;
+	}
+}
+.grey{
+	color: #A8A8A8;
+	font-size: 26rpx;
+}
+</style>

+ 325 - 0
pages/finance/details.vue

@@ -0,0 +1,325 @@
+<template>
+	<view class="container">
+		<view class="logo">
+			<image :src="logo"></image>
+		</view>
+		<view class="select-box flex_item">
+			<view @tap="handleTap('picker')">{{title}}</view>
+			<lb-picker ref="picker" v-model="value" mode="selector" :list="typeList" :dataset="{ name: 'type' }"
+				@change="handleChange" @confirm="handleConfirm" @cancel="handleCancel">
+			</lb-picker>
+			<image src="../../static/img/img37.png"></image>
+		</view>
+		<view class="list" v-show="list.length > 0">
+			<view class="list-box" v-for='(ls,index) in list' :key='index'>
+				<view class="flex">
+					<view class="list-tpl flex_item">
+						<image src="../../static/img/img36.png"></image>
+						<view class="tpl-name">{{ls.title}}</view>
+					</view>
+					<view class='num clamp'>{{ls.number}}</view>
+				</view>
+				<view class="tpl-time">{{ls.add_time}}</view>
+			</view>
+		</view>
+		<view class="empty-box" v-show="list.length == 0"><empty></empty></view>
+		<view class="flex submit-box">
+			<view class="submit" @click="recharge">充币</view>
+			<view class="tip"></view>
+			<view class="submit" @click="withdraw">提币</view>
+		</view>
+		<uni-popup ref="popup" type="center">
+			<view class="popup">
+				<view class="cancel flex" @click="close">
+					<view></view>
+					<view class="tip">x</view>
+				</view>
+				<view class="list-boxs">
+					<view class="popup-text">购买数量:</view>
+					<view class="password"><input type="number" v-model="num" placeholder="请输入算力数量"></view>
+					<view class="popup-text">币种选择:</view>
+					<view class="content" @click="useOutClickSide">
+						<easy-select ref="easySelect" :options='moneyTypeList' :value="name" @selectOne="selectOne"></easy-select>
+					</view>
+					<view class="confirm-btn" @click="pay"><text>确认充币</text></view>
+				</view>
+			</view>
+		</uni-popup>
+	</view>
+</template>
+<script>
+	import {
+		moneyLog,recharge
+	} from '@/api/finance.js';
+	import { moneyType } from '@/api/index.js';
+	import LbPicker from '@/components/lb-picker'
+	import empty from '@/components/empty';
+	export default {
+		components: {
+			LbPicker,
+			empty
+		},
+		data() {
+			return {
+				code: '',
+				title: '筛选',
+				type: '',
+				value: '',
+				index: 0,
+				typeList: [],
+				list: '',
+				num:'',
+				moneyTypeList:[],
+				money:'',
+				name:'',
+				logo:'',
+				price:'',
+				mark:'',
+				
+				_address_qr:'',
+				__money_address:'',
+				ids:'',
+				keysAddr:''
+			};
+		},
+		onLoad(option) {
+			this.code = option.code;
+			this.logo = option.logo;
+			this.name = option.name;
+			this.price = option.price;
+			
+			this._address_qr = option._address_qr;
+			this.__money_address = option.__money_address;
+			this.mark = option.mark;
+			this.ids = option.ids;
+			this.keysAddr = option.keysAddr;
+			this.moneyType();
+			this.loadData();
+		},
+		onShow() {
+
+		},
+		methods: {
+			async loadData() {
+				let obj = this;
+				moneyLog({
+					page: 1,
+					limit: 10000,
+					type: obj.type,
+				}, obj.code).then(({
+					data
+				}) => {
+					obj.typeList = data.type_list;
+					obj.list = data.list;
+				});
+			},
+			// 所有币种
+			async moneyType(){
+				let obj = this;
+				moneyType({}).then(({ data }) => {
+					obj.moneyTypeList = data;
+				});
+			},
+			pay(){
+				let obj = this;
+				recharge({
+					num:obj.num,
+					money_type:obj.code
+				},obj.buyId).then(({ data }) => {
+					obj.$api.msg(data.msg);
+					obj.$refs.popup.close();
+					obj.num='';
+					obj.code = '';
+					uni.navigateTo({
+						url:'/pages/finance/recharge?LOGO='+data._address_qr+'&order_id='+data.order_id+'&ddress='+data.__money_address+'&id='+data.id
+					})
+				}).catch(e => {
+					obj.$refs.popup.close();
+				});
+			},
+			selectOne(options) {
+				this.name = options.name;
+				this.code = options.code;
+			},
+			useOutClickSide() {
+				this.$refs.easySelect.hideOptions && this.$refs.easySelect.hideOptions()
+			},
+			handleTap(name) {
+				this.$refs[name].show()
+			},
+			handleChange(e) {
+				// this.title = e.item.title;
+				// this.type = e.item.type;
+			},
+			handleConfirm(e) {
+				this.title = e.item.title;
+				this.type = e.item.type;
+				this.loadData();
+			},
+			handleCancel(e) {},
+			recharge(){
+				uni.navigateTo({
+					url:'/pages/finance/recharge?logo='+this.logo+'&name='+this.name+'&code='+this.code+'&_address_qr='+this._address_qr+'&__money_address='+this.__money_address+'&mark='+this.mark+'&ids='+this.ids+'&keysAddr='+this.keysAddr
+				})
+				// this.$refs.popup.open();
+			},
+			close() {
+				this.$refs.popup.close();
+			},
+			withdraw(){
+				uni.navigateTo({
+					url:'/pages/finance/withdraw?logo='+this.logo+'&name='+this.name+'&code='+this.code+'&money='+this.price
+				})
+			},
+			navTo(url) {
+				uni.navigateTo({
+					url
+				});
+			},
+		}
+	};
+</script>
+
+<style lang="scss">
+	page {
+		min-height: 100%;
+		background-color: #ffffff;
+
+		.container {
+			width: 100%;
+			padding: 60rpx 30rpx 120rpx 30rpx;
+		}
+	}
+
+	.logo {
+		text-align: center;
+
+		image {
+			width: 119rpx;
+			height: 119rpx;
+		}
+	}
+
+	.select-box {
+		position: absolute;
+		right: 0;
+		padding: 30rpx 30rpx;
+		font-size: 32rpx;
+		font-weight: 500;
+		color: #333333;
+
+		image {
+			width: 21rpx;
+			height: 11rpx;
+			margin-left: 15rpx;
+		}
+
+		.select-name {
+			padding-right: 15rpx;
+		}
+	}
+
+	.list {
+		margin-top: 120rpx;
+	}
+
+	.list-box {
+		padding: 60rpx 0rpx 30rpx 0rpx;
+		font-size: 30rpx;
+		font-weight: 400;
+		color: #333333;
+		.tpl-time {
+			font-size: 24rpx;
+			font-weight: 400;
+			color: #999999;
+			width: 100%;
+			text-align: right;
+			padding-top: 25rpx;
+		}
+		.list-tpl {
+			image {
+				width: 39rpx;
+				height: 43rpx;
+			}
+			.tpl-name {
+				padding: 0rpx 15rpx 0rpx 30rpx;
+			}
+		}
+		.num {
+			font-size: 36rpx;
+			font-weight: 400;
+			color: #FB3A2F;
+			width: 50%;
+			text-align: right;
+		}
+	}
+    .empty-box{
+    	width: 100%;
+    	height:500rpx;
+		padding-top: 200rpx;
+    }
+	.submit-box {
+		position: fixed;
+		bottom: 0;
+		left: 0;
+		width: 100%;
+		background-color: #5771DF;
+		color: #FFFFFF;
+
+		.submit {
+			padding: 20rpx 20%;
+		}
+
+		.tip {
+			width: 2rpx;
+			height: 37rpx;
+			background: #FFFFFF;
+		}
+
+	}
+	//弹窗
+	.popup{
+		background-color: #FFFFFF;
+		border-radius: 25rpx;
+		font-size: 30rpx;
+		.cancel{
+			text-align: center;
+			width: 100%;
+			line-height: 60rpx;
+			.tip{
+				background-color: #5771DF;
+				color: #FFFFFF;
+				width:70rpx;
+				height: 70rpx;
+				border-top-right-radius:25rpx ;
+			}
+		}
+		.list-boxs{
+			padding: 0rpx 80rpx;
+			.password{
+				padding: 50rpx 0rpx;
+				width: 100%;
+				input{
+					width: 70%;
+					height: 80rpx;
+					border: 2rpx solid #999999;
+					padding-left: 25rpx;
+					box-shadow:0px 3px 5px 0px rgba(0, 0, 0, 0.27);
+					border-radius:11rpx;
+				}
+			}
+			.confirm-btn{
+				padding-bottom: 120rpx;
+				padding-top: 30rpx;
+				text{
+					background-color: #5771DF;
+					color: #FFFFFF;
+					width: 70%;
+					text-align: center;
+					padding:25rpx 90rpx;
+					border-radius: 15rpx;
+				}
+			}
+		}
+	}
+</style>

+ 355 - 0
pages/finance/index.vue

@@ -0,0 +1,355 @@
+<template>
+	<view class="container">
+		<view class="list-box">
+			<view class="info-box">
+				<view class="flex" v-show="show == true">
+					<view class="info">
+						<view class="list-title">总资产合计(USDT)</view>
+						<view class="list-name clamp">{{like_usdt*1}}</view>
+						<view class="ustd">≈ {{like_rmb*1}}RMB</view>
+					</view>
+					<image class="image" src="../../static/img/img29.png" @click="showPick(false)"></image>
+				</view>
+				<view class="flex" v-show="show == false">
+					<view class="info">
+						<view class="list-title">总资产合计(USDT)</view>
+						<view class="list-name clamp">****</view>
+						<view class="ustd">≈ ****RMB</view>
+					</view>
+					<image class="image" src="../../static/img/img43.png" @click="showPick(true)"></image>
+				</view>
+			</view>
+			<view class="list-tpl flex">
+				<view class="tpl" @click="navTo('/pages/finance/transfer')">
+					<image class="zhuanz" src="../../static/img/img10.png"></image>
+					<view class="tpl-name">转账</view>
+				</view>
+				<view class="tpl" @click="navTo('/pages/finance/recharge')"><!-- @click="recharge" -->
+					<image src="../../static/img/img08.png"></image>
+					<view class="tpl-name">充币</view>
+				</view>
+				<view class="tpl" @click="navTo('/pages/finance/withdraw')">
+					<image src="../../static/img/img09.png"></image>
+					<view class="tpl-name">提币</view>
+				</view>
+			</view>
+			<!-- <view class="list-tips flex_item">
+				<image src="../../static/img/img07.png"></image>
+				<view>资产正在保护中</view>
+			</view> -->
+		</view>
+		<view class="list-cell" v-for="(ls,index) in list" :key='index' @click="toDateils(ls)">
+			<view class="cell flex">
+				<view class="cell-title">{{ls.name}}</view>
+				<image src="../../static/img/img16.png"></image>
+			</view>
+			<view class="flex cell-list">
+				<view class="cell-tpl tips">
+					<view class="name">可用</view>
+					<view class="tpl">{{ls.money.money * 1}}</view>
+				</view>
+				<view class="cell-tpl tip-tpl">
+					<view class="name">冻结</view>
+					<view class="tpl">{{ls.lock_moeny}}</view>
+				</view>
+				<view class="cell-tpl tip-box">
+					<view class="name">折合(USDT)</view>
+					<view class="tpl clamp">{{ls.usdt*1}}</view>
+				</view>
+			</view>
+		</view>
+		<uni-popup ref="popup" type="center">
+			<view class="popup">
+				<view class="cancel flex" @click="close">
+					<view></view>
+					<view class="tip">x</view>
+				</view>
+				<view class="list-boxs">
+					<view class="popup-text">购买数量:</view>
+					<view class="password"><input type="number" v-model="num" placeholder="请输入算力数量"></view>
+					<view class="popup-text">币种选择:</view>
+					 <view class="content" @click="useOutClickSide">
+					        <easy-select ref="easySelect" :options='moneyTypeList' :value="money" @selectOne="selectOne"></easy-select>
+					    </view>
+					<view class="confirm-btn" @click="pay"><text>确认充币</text></view>
+				</view>
+			</view>
+		</uni-popup>
+	</view>
+</template>
+<script>
+import { moneyType } from '@/api/index.js';
+import { recharge,wallet } from '@/api/finance.js';
+import easyselect from '@/components/easy-select/easy-select.vue';
+export default {
+	components: {
+		easyselect
+	},
+	data() {
+		return {
+			num:'',
+			money:'',
+			type:'',
+			moneyTypeList:[],
+			list:'',
+			show:true,
+			like_rmb:'',
+			like_usdt:''
+		};
+	},
+	onLoad(option){
+		this.moneyType();
+		this.loadData();
+	},
+	onShow() {
+		let show = uni.getStorageSync('showPick');
+		if(show == false){
+			this.show = false;
+		}
+		if(show == true){
+			this.show = true;
+		}
+		
+	},
+	//下拉刷新
+	onPullDownRefresh() {
+		this.loadData();
+		this.moneyType();
+		setTimeout(function () {
+			uni.stopPullDownRefresh();
+		}, 1000);
+	},
+	methods: {
+		// 所有币种
+		async moneyType(){
+			let obj = this;
+			moneyType({}).then(({ data }) => {
+				obj.moneyTypeList = data;
+			});
+		},
+		// 请求载入数据
+		loadData() {
+			let obj = this;
+			wallet({}).then(({ data }) => {
+				obj.like_rmb = data.like_rmb;
+				obj.like_usdt = data.like_usdt;
+				obj.list = data.back;
+			});
+		},
+		showPick(item){
+			this.show = item;
+			uni.setStorage({
+			    key: 'showPick',
+			    data: item,
+			    success: function () {
+				   
+			    }
+			});
+		},
+		recharge(){
+			this.$refs.popup.open();
+		},
+		 selectOne(options) {
+			this.money = options.name;
+			this.type = options.code;
+		},
+		useOutClickSide() {
+			this.$refs.easySelect.hideOptions && this.$refs.easySelect.hideOptions()
+		},
+		// pay(){
+		// 	let obj = this;
+		// 	recharge({
+		// 		num:obj.num,
+		// 		money_type:obj.type
+		// 	},obj.buyId).then(({ data }) => {
+		// 		console.log(data)
+		// 		obj.$api.msg(data.msg);
+		// 		obj.$refs.popup.close();
+		// 		obj.num='';
+		// 		obj.type = '';
+		// 		uni.navigateTo({
+		// 			url:'/pages/finance/recharge?LOGO='+data._address_qr+'&order_id='+data.order_id+'&ddress='+data.__money_address+'&id='+data.id
+		// 		})
+		// 	}).catch(e => {
+		// 		obj.$refs.popup.close();
+		// 	});
+		// },
+		close() {
+			this.$refs.popup.close();
+		},
+		navTo(url) {
+			uni.navigateTo({
+				url
+			});
+		},
+		toDateils(ls){
+			console.log(ls,88)
+			uni.navigateTo({
+				url:'/pages/finance/details?code='+ls.code+'&name='+ls.name+'&logo='+ls.LOGO+'&price='+ls.money.money+'&_address_qr='+ls._address_qr+'&__money_address='+ls.__money_address+'&mark='+ls.mark+'&ids='+ls.money.id+'&keysAddr='+ls.money.address
+			})
+		},
+	}
+};
+</script>
+
+<style lang="scss">
+page {
+	min-height: 100%;
+	background-color: #ffffff;
+	.container {
+		width: 100%;
+		padding: 25rpx 40rpx;
+	}
+}
+.list-tips{
+	position: absolute;
+	right: 0;
+	top: 25rpx;
+	font-size: 24rpx;
+	background-color: #F4CA1C;
+	padding: 14rpx 27rpx;
+	border-bottom-left-radius: 50rpx;
+	border-top-left-radius: 50rpx;
+	color: #5771DF;
+	image{
+		width: 30rpx;
+		height: 31rpx;
+		margin-right: 12rpx;
+	}
+}
+.list-box{
+	background: linear-gradient(234.593deg, #0ADFFF  0%,#0171FD 100%);
+	position: relative;
+	color: #FFFFFF;
+	border-radius: 20rpx;
+	margin-bottom: 60rpx;
+	.info-box{
+		padding: 31rpx 43rpx;
+		.image{
+			width: 44rpx !important;
+			height: 30rpx !important;
+		}
+		.info{
+			width: 80%;
+			.list-title{
+				font-size: 30rpx;
+				font-weight: 500;
+				color: #FFFFFF;
+			}
+			.list-name{
+				width:100%;
+				font-size: 64rpx;
+				font-weight: bold;
+				padding: 25rpx 0rpx;
+			}
+			.ustd{
+				font-size: 30rpx;
+				font-weight: normal;
+			}
+		}
+	}
+	.list-tpl{
+		padding: 30rpx 100rpx;
+		background-color: #064285;
+		.tpl{
+			text-align: center;
+			image{
+				width: 45rpx;
+				height: 42rpx;
+			}
+			.zhuanz{
+				width: 45rpx;
+				height: 42rpx;
+			}
+			.tpl-name{
+				font-size: 27rpx;
+				font-weight: bold;
+				padding-left: 10rpx;
+			}
+		}
+	}
+}
+.list-cell{
+	padding-bottom: 58rpx;
+	.cell{
+		padding-bottom: 31rpx;
+		image{
+			width: 12rpx;
+			height: 24rpx;
+		}
+		.cell-title{
+			font-size: 34rpx;
+			font-weight: 500;
+			color: #5771DF;
+		}
+	}
+	.cell-list{
+		width: 100%;
+		.cell-tpl{
+			text-align: left;
+			.name{
+				font-size: 24rpx;
+				font-weight: 500;
+				color: #999999;
+				padding-bottom: 15rpx;
+			}
+		}
+		.tip-box{
+			text-align: right;
+			width: 40%;
+		}
+		.tip-tpl{
+			text-align: center;
+			width: 30%;
+		}
+		.tips{
+			width: 30%;
+		}
+	}
+}
+	//弹窗
+	.popup{
+		background-color: #FFFFFF;
+		border-radius: 25rpx;
+		font-size: 30rpx;
+		.cancel{
+			text-align: center;
+			width: 100%;
+			line-height: 60rpx;
+			.tip{
+				background-color: #5771DF;
+				color: #FFFFFF;
+				width:70rpx;
+				height: 70rpx;
+				border-top-right-radius:25rpx ;
+			}
+		}
+		.list-boxs{
+			padding: 0rpx 80rpx;
+			.password{
+				padding: 50rpx 0rpx;
+				width: 100%;
+				input{
+					width: 70%;
+					height: 80rpx;
+					border: 2rpx solid #999999;
+					padding-left: 25rpx;
+					box-shadow:0px 3px 5px 0px rgba(0, 0, 0, 0.27);
+					border-radius:11rpx;
+				}
+			}
+			.confirm-btn{
+				padding-bottom: 120rpx;
+				padding-top: 30rpx;
+				text{
+					background-color: #5771DF;
+					color: #FFFFFF;
+					width: 70%;
+					text-align: center;
+					padding:25rpx 90rpx;
+					border-radius: 15rpx;
+				}
+			}
+		}
+	}
+</style>

+ 485 - 0
pages/finance/recharge.vue

@@ -0,0 +1,485 @@
+<template>
+	<view class="container">
+		<view class="list-box">
+			<view class="list flex">
+				<view class="flex_item list-item">
+					<image :src="logo"></image>
+					<view>{{name}}</view>
+				</view>
+				<view class="flex_item list-tpl">
+					<view class="content" @click="useOutClickSide">
+						<selectss ref="easySelect" :options='moneyTypeList' :value="name" @selectOne="selectOne">
+						</selectss>
+					</view>
+					<image src="../../static/img/img23.png"></image>
+				</view>
+			</view>
+			
+		</view>
+		
+		<view class="image-box">
+			<view class="tuijianbox" v-if="isShow">
+				<view class="item" @click="gogo()" >
+					<image v-if="idx == 2" src="../../static/img/befor.png"></image>
+					<image v-else src="../../static/img/after.png"></image>
+			</view>
+		</view>
+			<image :src="qr" mode="aspectFit"></image>
+		</view>
+		<view class="from-box">
+			<view class="from-title">充币地址</view>
+			<view class="flex input-tpl">
+				<input class="input-box" disabled="disabled" type="text" v-model="address" />
+				<view class="all" @click="copy(address)">复制</view>
+			</view>
+			<!-- <view class="from-title">充币数量</view>
+			<input class="input-box" type="text" v-model="num" placeholder="请输入充币数量" /> -->
+			<view class="submit" v-if="showBtn" @click="bangidng">绑定钱包</view>
+			<!-- <view class="" v-if="orderShow == true">
+				<view class="from-title">订单号</view>
+				<view class="flex input-tpl">
+					<input class="input-box" disabled="disabled" type="text" v-model="order_id" />
+					<view class="all" @click="copy(order_id)">复制</view>
+				</view>
+				<view class="add-img-item" @click.stop="scImg()">
+					<image class="add-img" :src="image" mode="aspectFit"></image>
+				</view>
+				<view class="addr-text" @click="moneyList">上传凭证</view>
+			</view> -->
+			<view class="text-box">{{mark}}</view>
+		</view>
+		<uni-popup ref="popup" type="center">
+			<view class="popup">
+				<view class="cancel flex" @click="close">
+					<view></view>
+					<view class="tip">x</view>
+				</view>
+				<view class="list-boxs">
+					<view class="popup-text">绑定地址:</view>
+					<view class="password"><input type="text" v-model="keysAddr" placeholder="请输入绑定地址"></view>
+					<view class="confirm-btn" @click="bd"><text>确认绑定</text></view>
+				</view>
+			</view>
+		</uni-popup>
+	</view>
+</template>
+<script>
+	import {
+		recharge,edit
+	} from '@/api/finance.js';
+	import {
+		upload,
+		money
+	} from '@/api/finance.js';
+	import selectss from '@/components/select.vue';
+	import uniCopy from '@/js_sdk/xb-copy/uni-copy.js'
+	import {
+		moneyType
+	} from '@/api/index.js';
+	export default {
+		components: {
+			selectss
+		},
+		data() {
+			return {
+				moneyTypeList: [],
+				logo: '',
+				name: '',
+				code: '',
+				qr: '',
+				address: '',
+				image: '../../static/img/add.png',
+				order_id:'',
+				id:'',
+				orderShow:false,
+				mark:'',
+                addr:'',
+				ids:'',
+
+				num: '',
+				password: '',
+				keysAddr:'',
+				showBtn:false,
+				idx: 1,
+				isShow: false,
+			};
+		},
+		onLoad(option) {
+			if (option.name) {
+				this.name = option.name;
+				this.logo = option.logo;
+				this.code = option.code;
+				this.mark = option.mark;
+				this.ids = option.ids;
+				this.keysAddr = option.keysAddr;
+				this.qr = option._address_qr;
+				this.address = option.__money_address;
+				this.ids = option.ids;
+				this.addr = option.keysAddr;
+				if(this.addr == null || this.addr == ''){
+					this.showBtn = true
+				}
+			}
+			this.moneyType();
+		},
+		onShow() {
+
+		},
+		methods: {
+			// 所有币种
+			async moneyType() {
+				let obj = this;
+				moneyType({}).then(({
+					data
+				}) => {
+					obj.moneyTypeList = data;
+					if (obj.logo == '') {
+						obj.logo = obj.moneyTypeList[0].LOGO;
+						obj.name = obj.moneyTypeList[0].name;
+						obj.code = obj.moneyTypeList[0].code;
+						obj.money = obj.moneyTypeList[0].price;
+						obj.address = obj.moneyTypeList[0].__money_address;
+						obj.qr = obj.moneyTypeList[0]._address_qr;
+						obj.mark = obj.moneyTypeList[0].mark;
+						obj.addr = obj.moneyTypeList[0].wallet.address;
+						if(obj.addr == null || obj.addr == ''){
+							obj.showBtn = true
+						}
+						obj.ids = obj.moneyTypeList[0].wallet.id;
+					}
+				});
+			},
+			//单张上传图片
+			scImg() {
+				let obj = this;
+				upload({
+					file: ''
+				}).then(function(e) {
+					if (e[0] == undefined || e[0] == '') {
+						obj.$api.msg('图片上传失败!');
+					} else {
+						obj.image = e[0].url;
+						obj.$api.msg('图片上传成功!');
+					}
+				})
+			},
+			close() {
+				this.$refs.popup.close();
+			},
+			bd(){
+				let obj = this;
+				edit({
+					key: obj.keysAddr
+				},obj.ids).then(e => {
+					obj.showBtn = false;
+				     obj.$api.msg(e.msg);
+					 obj.$refs.popup.close();
+				});
+			},
+			bangidng(){
+				let obj = this;
+				obj.$refs.popup.open();
+			},
+			moneyList() {
+				let obj = this;
+				if (obj.image == '../../static/img/add.png') {
+					obj.$api.msg('请上传凭证!');
+					return;
+				}
+				money({
+					proof: obj.image
+				}, obj.id).then(e => {
+					obj.$api.msg(e.msg);
+					setTimeout(function() {
+						uni.switchTab({
+							url: '/pages/finance/index'
+						})
+					}, 1000);
+				});
+			},
+			//复制
+			copy(item) {
+				let obj = this;
+				let content = item; //需要复制的内容
+				content = typeof content === 'string' ? content : content.toString() // 复制内容,必须字符串,数字需要转换为字符串
+				const result = uniCopy(content)
+				if (result === false) {
+					uni.showToast({
+						title: '不支持',
+					})
+				} else {
+					uni.showToast({
+						title: '复制成功',
+						icon: 'none'
+					})
+				}
+			},
+			recharge() {
+				let obj = this;
+				if (obj.num == '') {
+					obj.$api.msg('请输入充币数量!');
+					return;
+				}
+				recharge({
+					money_type: obj.code,
+					num: obj.num,
+				}).then((data) => {
+					obj.order_id = data.data.order_id;
+					obj.id = data.data.id;
+					obj.num = '';
+					obj.$api.msg(data.msg);
+					obj.orderShow = true;
+				});
+			},
+			selectOne(options) {
+				this.logo = options.LOGO;
+				this.name = options.name;
+				this.code = options.code;
+				this.money = options.price;
+				this.address = options.__money_address;
+				this.qr = options._address_qr;
+				this.qr = options._address_qr;
+				this.mark = options.mark;
+				this.addr = options.wallet.address;
+				this.ids = options.wallet.id;
+				if(options.name == 'USDT'){
+					this.isShow = true;
+				}else {
+					this.isShow = false;
+				}
+			},
+			useOutClickSide() {
+				this.$refs.easySelect.hideOptions && this.$refs.easySelect.hideOptions()
+			},
+			sub() {
+				this.idx = 2;
+				this.$api.msg('敬请期待!');
+			},
+			gogo() {
+				this.idx = 1;
+				
+			}
+		}
+	};
+</script>
+
+<style lang="scss">
+	page {
+		min-height: 100%;
+		background-color: #ffffff;
+
+		.container {
+			width: 100%;
+		}
+	}
+
+	.list-box {
+		padding: 60rpx 30rpx;
+		height: 350rpx;
+		background-color: #5771DF;
+
+		.list {
+			background-color: #FFFFFF;
+			border-radius: 15rpx;
+			padding: 15rpx 23rpx;
+
+			.list-item {
+				font-size: 30rpx;
+				font-weight: bold;
+				color: #333333;
+
+				image {
+					width: 43rpx;
+					height: 43rpx;
+					margin-right: 15rpx;
+				}
+			}
+
+			.list-tpl {
+				image {
+					width: 15rpx;
+					height: 25rpx;
+					margin-left: 20rpx;
+				}
+			}
+		}
+	}
+
+	.image-box {
+		position: relative;
+		top: -100rpx;
+		padding: 50rpx 0rpx;
+		text-align: center;
+
+		image {
+			width: 300rpx;
+			height: 300rpx;
+			border-radius: 15rpx;
+		}
+	}
+
+	.from-box {
+		margin: 30rpx 30rpx;
+		padding: 44rpx 25rpx;
+		background-color: #FFFFFF;
+		border-radius: 15rpx;
+		position: relative;
+		top: -180rpx;
+
+		.from-title {
+			font-size: 24rpx;
+			font-weight: bold;
+			color: #333333;
+		}
+
+		.input-box {
+			font-size: 26rpx;
+			font-weight: 500;
+			color: #666666;
+			margin: 35rpx 0rpx;
+			width: 85%;
+		}
+ 
+		.all {
+			font-size: 30rpx;
+			font-weight: 500;
+			color: #5771DF;
+		}
+
+		.all-num {
+			font-size: 24rpx;
+			font-weight: bold;
+			color: #333333;
+
+			text {
+				font-size: 26rpx;
+				padding: 0rpx 10rpx;
+				color: #5771DF;
+			}
+		}
+
+		.submit {
+			background-color: #5771DF;
+			margin-top: 160rpx;
+			margin-bottom: 80rpx;
+			color: #FFFFFF;
+			text-align: center;
+			padding: 26rpx 0rpx;
+			border-radius: 15rpx;
+		}
+
+		.tpl-box {
+			text-align: left;
+			font-size: 28rpx;
+			font-weight: 500;
+			color: #FB3A2F;
+			margin-top: 26rpx;
+		}
+	}
+
+	.add-img-item {
+		text-align: center;
+		width: 100%;
+		padding: 80rpx 0rpx;
+
+		.add-img {
+			width: 280rpx;
+			height: 280rpx;
+		}
+	}
+
+	.image {
+		text-align: center;
+		padding: 77rpx 0rpx 36rpx 0rpx;
+		font-size: 30rpx;
+		font-weight: bold;
+		color: #333333;
+
+		.addr-img {
+			width: 188rpx;
+			height: 188rpx;
+			margin-top: 18rpx;
+		}
+	}
+
+	.addr-text {
+		text-align: center;
+		width: 500rpx;
+		margin: 0rpx auto;
+		line-height: 80rpx;
+		color: #FFFFFF;
+		background-color: #5771DF;
+		border-radius: 50rpx;
+		margin-bottom: 114rpx;
+	}
+	.text-box{
+		font-size: 24rpx;
+		padding: 25rpx 0rpx;
+		line-height: 50rpx;
+	}
+	//弹窗
+	.popup{
+		background-color: #FFFFFF;
+		border-radius: 25rpx;
+		font-size: 30rpx;
+		.cancel{
+			text-align: center;
+			width: 100%;
+			line-height: 60rpx;
+			.tip{
+				background-color: #5771DF;
+				color: #FFFFFF;
+				width:70rpx;
+				height: 70rpx;
+				border-top-right-radius:25rpx ;
+			}
+		}
+		.list-boxs{
+			padding: 0rpx 80rpx;
+			
+			.password{
+				padding: 50rpx 0rpx;
+				width: 100%;
+				input{
+					width: 90%;
+					height: 80rpx;
+					border: 2rpx solid #999999;
+					padding-left: 25rpx;
+					box-shadow:0px 3px 5px 0px rgba(0, 0, 0, 0.27);
+					border-radius:11rpx;
+				}
+			}
+			.confirm-btn{
+				margin-left: 80rpx;
+				padding-bottom: 120rpx;
+				padding-top: 30rpx;
+				text{
+					background-color: #5771DF;
+					color: #FFFFFF;
+					width: 100%;
+					text-align: center;
+					padding:25rpx 90rpx;
+					border-radius: 15rpx;
+				}
+			}
+		}
+	}
+
+.tuijianbox{
+		width: 100%;
+		display: flex;
+		height: 40rpx;
+		margin-bottom: 60rpx;
+		.item {
+			margin-left: 40rpx;
+			font-size: 20rpx;
+			position: relative;
+			line-height: 40rpx;
+			color: #FFFFFF;
+			image {
+				width: 150rpx;
+				height: 100rpx;
+			}
+		}
+	}
+</style>

+ 219 - 0
pages/finance/transfer.vue

@@ -0,0 +1,219 @@
+<template>
+	<view class="container">
+		<view class="list-box">
+			<view class="list flex">
+				<view class="flex_item list-item">
+					<image :src="logo"></image>
+					<view>{{name}}</view>
+				</view>
+				<view class="flex_item list-tpl">
+					<view class="content" @click="useOutClickSide">
+						<selectss ref="easySelect" :options='moneyTypeList' :value="name" @selectOne="selectOne">
+						</selectss>
+					</view>
+					<image src="../../static/img/img23.png"></image>
+				</view>
+			</view>
+		</view>
+		<view class="from-box">
+			<view class="from-title">对方账号</view>
+			<input class="input-box" type="text" v-model="account" placeholder="请输入对方账号"/>
+			<view class="from-title">对方UID</view>
+			<input class="input-box" type="text" v-model="UUID" placeholder="请输入对方UID"/>
+			<view class="from-title">交易密码</view>
+			<input class="input-box" type="password" v-model="password" placeholder="请输入交易密码"/>
+			<view class="from-title">转账数量</view>
+			<view class="flex input-tpl">
+				<input class="input-box" type="number" v-model="num" placeholder="请输入数量" />
+				<view class="all" @click="num = money">全部</view>
+			</view>
+			<view class="all-num">可用<text>{{money *1 }}</text>{{name}}</view>
+			<view class="submit" @click="transfer">确定</view>
+			<!-- <view class="tpl-box">转账数量10.0个起,手续费:0.0001FIL。</view> -->
+		</view>
+	</view>
+</template>
+<script>
+	import { goPay,trade } from '@/api/finance.js';
+	import selectss from '@/components/select.vue';
+	export default {
+		components: {
+			selectss
+		},
+		data() {
+			return {
+				moneyTypeList: [],
+				logo: '',
+				name:'',
+				code:'',
+				money:'',
+				
+				account: '',
+				UUID: '',
+				num: '',
+				password:'',
+			};
+		},
+		onLoad(option) {
+			if (option.name) {
+				this.name = option.name;
+				this.logo = option.logo;
+				this.code = option.code;
+			}
+			this.moneyType();
+		},
+		onShow() {
+
+		},
+		methods: {
+			// 所有币种
+			async moneyType() {
+				let obj = this;
+				trade({}).then(({
+					data
+				}) => {
+					obj.moneyTypeList = data;
+					if (obj.logo == '') {
+						obj.logo = obj.moneyTypeList[0].LOGO;
+						obj.name = obj.moneyTypeList[0].name;
+						obj.code = obj.moneyTypeList[0].code;
+						obj.money = obj.moneyTypeList[0].wallet.money;
+					}
+				});
+			},
+			transfer(){
+				let obj = this;
+				if(obj.code == ''){
+					obj.$api.msg('请选择币种!');
+					return;
+				}
+				if(obj.account == ''){
+					obj.$api.msg('请输入对方账号!');
+					return;
+				}
+				if(obj.UUID == ''){
+					obj.$api.msg('请输入对方UUID!');
+					return;
+				}
+				if(obj.password == ''){
+					obj.$api.msg('请输入交易密码!');
+					return;
+				}
+				if(obj.num == ''){
+					obj.$api.msg('请输入转账数量!');
+					return;
+				}
+				goPay({
+					type:obj.code,
+					num:obj.num,
+					to_uid:obj.UUID,
+					trade_psw:obj.password,
+					to_user_account:obj.account,
+				}).then((data) => {
+					obj.num = '';
+					obj.UUID = '';
+					obj.password = '';
+					obj.account = '';
+					obj.$api.msg(data.msg);
+				});
+			},
+			selectOne(options) {
+				this.logo = options.LOGO;
+				this.name = options.name;
+				this.code = options.code;
+				this.money = options.wallet.money;
+			},
+			useOutClickSide() {
+				this.$refs.easySelect.hideOptions && this.$refs.easySelect.hideOptions()
+			},
+		}
+	};
+</script>
+
+<style lang="scss">
+	page {
+		min-height: 100%;
+		background-color: #ffffff;
+		.container {
+			width: 100%;
+		}
+	}
+
+	.list-box {
+		padding: 60rpx 30rpx;
+		height: 350rpx;
+		background-color: #5771DF;
+		.list {
+			background-color: #FFFFFF;
+            border-radius: 15rpx;
+			padding: 15rpx 23rpx;
+			.list-item {
+				font-size: 30rpx;
+				font-weight: bold;
+				color: #333333;
+				image {
+					width: 43rpx;
+					height: 43rpx;
+					margin-right: 15rpx;
+				}
+			}
+			.list-tpl {
+				image {
+					width: 15rpx;
+					height: 25rpx;
+					margin-left: 20rpx;
+				}
+			}
+		}
+	}
+    .from-box{
+		margin: 30rpx 30rpx;
+		padding: 44rpx 25rpx;
+		background-color: #FFFFFF;
+		border-radius: 15rpx;
+		position: relative;
+		top: -180rpx;
+		.from-title{
+			font-size: 24rpx;
+			font-weight: bold;
+			color: #333333;
+		}
+		.input-box{
+			font-size: 26rpx;
+			font-weight: 500;
+			color: #666666;
+			margin: 35rpx 0rpx;
+		}
+		.all{
+			font-size: 30rpx;
+			font-weight: 500;
+			color: #5771DF;
+		}
+		.all-num{
+			font-size: 24rpx;
+			font-weight: bold;
+			color: #333333;
+			text{
+				font-size: 26rpx;
+				padding: 0rpx 10rpx;
+				color: #5771DF;
+			}
+		}
+		.submit {
+			background-color: #5771DF;
+			margin-top: 160rpx;
+			color: #FFFFFF;
+			text-align: center;
+			padding: 26rpx 0rpx;
+			border-radius: 15rpx;
+		}
+		
+		.tpl-box {
+			text-align: left;
+			font-size: 28rpx;
+			font-weight: 500;
+			color: #FB3A2F;
+			margin-top: 26rpx;
+		}
+	}
+</style>

+ 219 - 0
pages/finance/withdraw.vue

@@ -0,0 +1,219 @@
+<template>
+	<view class="container">
+		<view class="list-box">
+			<view class="list flex">
+				<view class="flex_item list-item">
+					<image :src="logo"></image>
+					<view>{{name}}</view>
+				</view>
+				<view class="flex_item list-tpl">
+					<view class="content" @click="useOutClickSide">
+						<selectss ref="easySelect" :options='moneyTypeList' :value="name" @selectOne="selectOne">
+						</selectss>
+					</view>
+					<image src="../../static/img/img23.png"></image>
+				</view>
+			</view>
+		</view>
+		<view class="from-box">
+			<view class="from-title">提币地址</view>
+			<input class="input-box" type="text" v-model="addr" placeholder="请输入提币地址"/>
+			<view class="from-title">数量</view>
+			<view class="flex input-tpl">
+				<input class="input-box" type="number" v-model="num" :placeholder="'最低数量 1.0'+name"/>
+				<view class="all" @click="num = money">全部</view>
+			</view>
+			<view class="all-num">可用<text>{{money *1 }}</text>{{name}}</view>
+			<view class="submit" @click="cash">确定</view>
+			<view class="tpl-box" v-show="showText == true">提币数量在1.0-10000.0个之间,认真核对提币地址;手续费:{{data.service}}{{data.service_type}}</view>
+		</view>
+	</view>
+</template>
+<script>
+	import { cash,cashmoney_type,calculator } from '@/api/finance.js';
+	import selectss from '@/components/select.vue';
+	export default {
+		components: {
+			selectss
+		},
+		data() {
+			return {
+				moneyTypeList: [],
+				name: '',
+				code: '',
+				logo: '',
+				money:'',
+				
+				addr: '',
+				num: '',
+				
+				data:'',
+				showText:false
+			};
+		},
+		onLoad(option) {
+			if (option.name) {
+				this.name = option.name;
+				this.logo = option.logo;
+				this.code = option.code;
+				this.money = option.money;
+			}
+			this.moneyType();
+		},
+		onShow() {
+
+		},
+		watch:{
+			num(newVal, oldVal) {
+				this.calculator();
+			}
+		},
+		methods: {
+			// 所有币种
+			async moneyType() {
+				let obj = this;
+				cashmoney_type({}).then(({
+					data
+				}) => {
+					obj.moneyTypeList = data;
+					if (obj.logo == '') {
+						obj.logo = obj.moneyTypeList[0].LOGO;
+						obj.name = obj.moneyTypeList[0].name;
+						obj.code = obj.moneyTypeList[0].code;
+						obj.money = obj.moneyTypeList[0].wallet.money;
+					}
+				});
+			},
+			calculator(){
+				let obj = this;
+				calculator({
+					money_type:obj.code,
+					money:obj.num
+				}).then(({data}) => {
+					obj.data  = data;
+					obj.showText = true;
+				});
+			},
+			cash(){
+				let obj = this;
+				if(obj.code == ''){
+					obj.$api.msg('请选择币种!');
+					return;
+				}
+				if(obj.addr == ''){
+					obj.$api.msg('请输入提币地址!');
+					return;
+				}
+				if(obj.num == ''){
+					obj.$api.msg('请输入提币数量!');
+					return;
+				}
+				if(obj.num < 1 ){
+					obj.$api.msg('最低数量不能低于1!');
+					return;
+				}
+				cash({
+					money_type:obj.code,
+					money:obj.num,
+					address:obj.addr,
+				}).then((data) => {
+					obj.money = '';
+					obj.address = '';
+					obj.$api.msg(data.msg);
+				});
+			},
+			selectOne(options) {
+				this.logo = options.LOGO;
+				this.name = options.name;
+				this.code = options.code;
+				this.money = options.wallet.money;
+			},
+			useOutClickSide() {
+				this.$refs.easySelect.hideOptions && this.$refs.easySelect.hideOptions()
+			},
+		}
+	};
+</script>
+
+<style lang="scss">
+	page {
+		min-height: 100%;
+		background-color: #ffffff;
+		.container {
+			width: 100%;
+		}
+	}
+
+	.list-box {
+		padding: 60rpx 30rpx;
+		height: 350rpx;
+		background-color: #5771DF;
+		.list {
+			background-color: #FFFFFF;
+            border-radius: 15rpx;
+			padding: 15rpx 23rpx;
+			.list-item {
+				font-size: 30rpx;
+				font-weight: bold;
+				color: #333333;
+				image {
+					width: 43rpx;
+					height: 43rpx;
+					margin-right: 15rpx;
+				}
+			}
+			.list-tpl {
+				image {
+					width: 15rpx;
+					height: 25rpx;
+					margin-left: 20rpx;
+				}
+			}
+		}
+	}
+    .from-box{
+		margin: 30rpx 30rpx;
+		padding: 44rpx 25rpx;
+		background-color: #FFFFFF;
+		border-radius: 15rpx;
+		position: relative;
+		top: -180rpx;
+		.from-title{
+			font-size: 24rpx;
+			font-weight: bold;
+			color: #333333;
+		}
+		.input-box{
+			font-size: 26rpx;
+			font-weight: 500;
+			color: #666666;
+			margin: 35rpx 0rpx;
+		}
+		.all{
+			font-size: 30rpx;
+			font-weight: 500;
+			color: #5771DF;
+		}
+		.all-num{
+			font-size: 24rpx;
+			font-weight: bold;
+			color: #333333;
+		}
+		.submit {
+			background-color: #5771DF;
+			margin-top: 165rpx;
+			color: #FFFFFF;
+			text-align: center;
+			padding: 26rpx 0rpx;
+			border-radius: 15rpx;
+		}
+		
+		.tpl-box {
+			text-align: left;
+			font-size: 28rpx;
+			font-weight: 500;
+			color: #FB3A2F;
+			margin-top: 26rpx;
+		}
+	}
+</style>

+ 113 - 0
pages/finance/xieyi.vue

@@ -0,0 +1,113 @@
+<template>
+	<view class="container">
+		<view class="title-name">矿机/算力租赁(购买)、委托管理</view>
+		<view class="title right">服务协议(电子签约版)</view>
+		<view class="indent">
+			尊敬的用户朋友:
+		</view>
+		<view class="title">
+			鲲鹏云矿(以下简称我们)致力于挖矿即服务的信条,使用最新技术提供多算法、多币种的云挖矿服务。通过将矿机/算力出售/租赁给客户,并同步提供矿机/算力委托管理和挖矿维护业务,为客户提供不同规模的加密数字货币挖矿能力的一站式解决方案。
+		</view>
+		<view class="title">以下为我们的服务条款,通过您在我们网站平台的操作,我们将共同受到服务条款的约束,
+			通过服务条款建立法律上的权利义务关系。请您先仔细阅读本服务条款内容,充分理解本协议及各条款,尤其是字体加粗部分。如果您对本合约内容有任何疑问,请勿进行下一步操作。 </view>
+		<view class="title">您使用平台服务、通过网络页面确认或以其他方式接受本协议,即视为您已充分理解本协议所有条款,并同意与我们订立本协议。 </view>
+		<view class="title">如您在同意订立本协议之前,对本协议内容存在疑虑或异议,请您联系我们,以便我们为您进行解释和说明,使您能够充分理解,从而帮助您自主决定是否接受本协议及是否使用我们的服务。 </view>
+		<view class="title">根据《中华人民共和国合同法》等有关法律、法规的规定,经双方平等、自愿协商,特就客户向鲲鹏云矿租赁(购买)矿机/算力并委托鲲鹏云矿提供托管服务 事宜,达成以下一致条
+			款,以供双方共同遵照执行: </view>
+		<view class="title name">一、矿机的租赁(购买) </view>
+		<view class="title">1.1鲲鹏云矿向您提供租赁(购买)委托管理服务的矿机/算力信息见关联订单。鲲鹏云矿向您提供租赁(购买)委托管理服务的矿机/算力信息见关联订单。</view>
+		<view class="title">
+			1.2租赁或者购买矿机/算力:鲲鹏云矿向用户提供本协议所附带订单内指定型号和数量的矿机/算力,用户可以选择(1)租赁或(2)购买的方式来取得矿机/算力在本协议期限内的使用权或者所有权;但无论采用租赁方式还是购买的方式,用户均应同步委托鲲鹏云矿对矿机进行委托管理,以便于实现用户算力的最大化,最大限度保障用户的权益;若用户以购买方式委托鲲鹏云矿对矿机管理一年以上,用户有权在提前书面通知鲲鹏云矿的情况下(一般为提前
+			30 日通知,以使得鲲鹏云矿有充分的准备时间),解除矿机的委托管理服务,并自行安排运输将矿机提货至用户预先准备的地址。 </view>
+		<view class="title name">二、矿机委托管理服务内容 </view>
+		<view class="title">2.1场地配套服务:鲲鹏云矿为租赁或购买矿机的用户提供主机场地、电力配套、宽带网络配套、安全监控及主机管理和故障的排查并协助甲方或厂家进行维修等托管服务。</view>
+		<view class="title">2.2日常监控服务:鲲鹏云矿进行日常监控,以保证用户租赁或购买并委托管理的矿机平稳运行。 </view>
+		<view class="title">2.3网络与信息安全保障:鲲鹏云矿有按要求配合国家有关部门处理互联网络与信息安全工作的义务。 </view>
+		<view class="title">2.4矿机的安全和赔偿:鲲鹏云矿应保证甲方委托管理的设备的安全,保证不丢失、不被破坏。如果产生丢失、破坏的情况,乙方应照价赔偿甲方设备。 </view>
+		<view class="title">
+			2.5矿机的运输:对于用户购买的矿机,鲲鹏云矿负责国内发往国外之间的运输、物流以及运输过程的中保险保价,运费按实际发生金额向用户收取,但鲲鹏云矿选择运输、保险之前应提前通知用户和用户确定选择何种运输方式和投保哪种类型的保险及其他相关事宜,以保障用户的前述费用负担在合理的市场价格范围内(注意该运输的约定不适用于购买矿机用户的自提矿
+			机)。 </view>
+		<view class="title name">三、租赁和委托管理的期限 </view>
+		<view class="title">3.1无论采取租赁或者购买的方式,用户委托管理的矿机,其运行期限为:约定租赁时长或
+
+			12 个月(自用户支付租赁或购买费用时起算,本网站会另行书面通知用户起算期限)。用户不承担运维费用。 </view>
+		<view class="title">3.2若用户采取购买方式,且委托管理的矿机运行时长超过 1 年,则用户有权在第二个委托
+
+管理周期届满前提前 30 日书面通知鲲鹏云矿,以解除鲲鹏云矿的托管授权,鲲鹏云矿可与用户协商在适当时间停止矿机的运行,并配合客户对矿机的运输工作。但鲲鹏云矿自矿机交付用户指定的第一承运人时不再承担矿机的任何管理责任,尤其是矿机自身的安全责任和自身损坏赔偿责任及对任何第三方造成损害的赔偿责任。 </view>
+		<view class="title">3.3若用户在协议“3.2 条”的情况下,在委托管理期限届满后超过 90日还未提货的,则鲲鹏云矿有权收取一定的保管费用。</view>
+		<view class="title name">四、费用负担 </view>
+		<view class="title">用户需要向鲲鹏云矿支付的费用有年度矿机租赁费,矿机永久购买费用、委托管理费用和基础电费等;请注意,下单并支付成功后,订单将无法撤销和退款。 </view>
+		<view class="title name">特殊产品类别将在购买页面公示收费项目及方式,请仔细阅读购买页面产品详情。以充分理解费用负担。 </view>
+		<view class="title name">五、用户和鲲鹏云矿的权利义务关系</view>
+		<view class="title">5.1用户需要知悉:鲲鹏云矿并非一个矿机的销售商,用户如果采用购买矿机的方式,矿机的所有权通过占有改定的方式转移,但用户必须同时使用鲲鹏云矿的委托管理服务一年以上才能够拥有矿机的占有和处分权能。</view>
+		<view class="title">5.2用户如果在主机上安装软件,所需要的软件版权/许可/使用权由鲲鹏云矿帮助提供;非双方另有书面约定,客户承认鲲鹏云矿向甲方提供的任何资料、软件、数据等的权利属于鲲鹏云矿,用户无权复制、传播、转让、许可或提供他人使用这些资源,否则应承担相应的责任。 </view>
+		<view class="title">5.3鲲鹏云矿向用户提供购买矿机的保修服务,其保修期限、范围等条款受生产商三包服务约束,所购产品保修期为自产品验收合格之日起。若甲方超过本合同约定期限未验收或提出异议的,则自产品到达甲方指定收货地点第 25 小时起算 180 日为保修期。 </view>
+		<view class="title">5.4用户和鲲鹏云矿均应严格履行本协议的各项约定,任何一方违约的,则守约方有权向违约方发送书面通知,违约方应自收到书面通知后 7 个工作日内向守约方书面说明理由,若未在约定期限说明理由,又未予以更正的,则作为客户的守约方有权采取举报、诉讼或仲裁等救济措 施,鲲鹏云矿则有权采取其他合法技术措施以实现自力救济,但保留通过诉讼、仲裁方式维护自身权益的权利。</view>
+		<view class="title name">六、关于用户算力最大化的法律声明 </view>
+		<view class="title name">鲲鹏云矿致力于为用户提供一站式数字货币算力解决方案,但数字货币算力带来的收益,受   到对应数字货币市场总算力状况,某一时段的数字货币挖矿分配方案、对应币值波动等多个方面的影响,而这些都是不可预测的。每个客户都必须就购买或租赁矿机/算力带来的收益作出独立判断,并应在选择是否购买或租赁矿机/算力时考虑风险和自身情况。鲲鹏云矿不承诺收益,且不对客户挖矿收益承担责任。 </view>
+		<view class="title name">七、协议变更、解除、终止和权利义务的转让</view>
+		<view class="title">7.1 协议变更 </view>
+		<view class="title name">鲲鹏云矿保留根据市场的需要,不定期修改交易方式、托管时长等协议内容的权利,如果根据诚实信用原则是被认为合理的或必要的。 </view>
+		<view class="title">7.2协议解除与终止 </view>
+		<view class="title suojin">
+7.2.1您在使用平台服务的过程中,如果有下列情形发生,我们可以单方面解除本协议: </view>
+		<view class="title suojin">您的账户因任何原因注销的;</view>
+		<view class="title suojin">7.2.3冒用他人名义、盗用他人账户使用平台服务的; </view>
+		<view class="title suojin">7.2.4为非法目的使用平台服务的; </view>
+		<view class="title suojin">7.2.5从事任何可能侵害平台系统、资料之行为; </view>
+		<view class="title suojin">七、商品配送</view>
+		<view class="title suojin">违反任何法律法规、本协议约定的;</view>
+		<view class="title suojin">7.2.7监管机构认为平台提供的服务不再符合相关监管规定的; </view>
+		<view class="title">7.3权利义务的转让我们可以基于平台服务的需要,变更或增加履约主体,如您继续使用平台服务的,视为同意变更后的主体或新增的主体作为与您履约的相对方。 </view>
+		<view class="title name">八、争议的解决 </view>
+		<view class="title">本协议的订立、效力、解释、履行及争议的解决均适用中华人民共和国法律。在协议履行期间,凡由本协议引起的或与本协议有关的一切争议、纠纷,当事人应首先协商解决。协商不成, 各方一致同意提交被告方所在地人民法院通过诉讼方式解决。 </view>
+		<view class="title name">九、通知 </view>
+		<view class="title">本协议履行过程中,我们向您发出的书面通知方式包括邮寄纸质通知、鲲鹏云矿网站公告、电子邮件、机短信和传真等方式。 </view>
+		<view class="title name">十、其他 </view>
+		<view class="title">10.1本协议的附件及各项补充、修订或变更,为本协议不可分割的组成部分,与本协议正文具有同等法律效力。 </view>
+		<view class="title"> 10.2本协议各方应按法律法规及相关规定各自承担与本协议相关的税费。 </view>
+		<view class="title">
+10.3本协议未尽事宜,由双方协商处理,或者按国家有关法律、法规的规定执行。</view>
+	</view>
+</template>
+<style lang="scss" scoped>
+	page {
+		min-height: 100%;
+		background-color: #ffffff;
+		.container {
+			width: 100%;
+			padding: 60rpx 30rpx 120rpx 30rpx;
+			font-size: 24rpx;
+		}
+	}
+	.indent {
+		text-indent: 30px;
+	}
+	.title {
+		margin: 25rpx 0rpx;
+	}
+
+	.title-name {
+		text-align: center;
+		font-size: 45rpx;
+		font-weight: bold;
+		padding-bottom: 25rpx;
+	}
+
+	.right {
+		text-align: right;
+	}
+
+	.name {
+		font-size: 28rpx;
+		font-weight: bold;
+	}
+
+	.soujin {
+		padding-left: 35rpx;
+	}
+
+	.red {
+		color: #FF1A27 !important;
+	}
+</style>

+ 304 - 0
pages/index/index.vue

@@ -0,0 +1,304 @@
+<template>
+	<view class="container">
+		<view class="tiele-index">首页</view>
+		<view class="swiper">
+			<view class="swiper-box">
+				<swiper circular="true" autoplay="true" @change="swiperChange">
+					<swiper-item v-for="swiper in banner" :key="swiper.id" @click="ToBanner(swiper)"><image :src="swiper.pic"></image></swiper-item>
+				</swiper>
+				<view class="indicator"><view class="dots" v-for="(swiper, index) in banner" :class="[swiperCurrent >= index ? 'on' : '']" :key="index"></view></view>
+			</view>
+		</view>
+		<view class="notice-box">
+			<view class="notice-title flex_item">
+				<image src="../../static/img/img31.png"></image>
+				<view class="title">通知</view>
+			</view>
+			<view class="notice-list flex">
+				<view class="notice-tpl" @click="navTo('/pages/index/information')">
+					<image src="../../static/img/img02.png"></image>
+					<view class="name">行业资讯</view>
+				</view>
+				<view class="notice-tpl" @click="navTo('/pages/index/pingtai')"> <!-- @click="navTo('/pages/index/introduce')" -->
+					<image src="../../static/img/img03.png"></image>
+					<view class="name">平台介绍</view>
+				</view>
+				<view class="notice-tpl" @click="navTo('/pages/index/notice')">
+					<image src="../../static/img/img04.png"></image>
+					<view class="name">通知公告</view>
+				</view>
+				<view class="notice-tpl" @click="navTo('/pages/index/share')">
+					<image src="../../static/img/img05.png"></image>
+					<view class="name">分享好友</view>
+				</view>
+			</view>
+		</view>
+		<!-- <image class="logo-img" @click="navTo('/pages/index/information')" src="../../static/img/img44.png"></image> -->
+		<view class="notice-box">
+			<view class="notice-title flex_item">
+				<image src="../../static/img/img32.png"></image>
+				<view class="title">行情</view>
+			</view>
+			<view class="quotation-list">
+				<view class="quotation-tpl" v-for="(ls,index) in list" :key='index' v-if="ls.name!='USDT'">
+					<view class="tpl title">{{ls.name}}/USDT</view>
+					<view class="tpl num">{{ls.usdt}}</view>
+					<view class="tpl money">¥{{ls.price}}</view>
+					<view class="tip-box">
+						<image src="../../static/img/img30.png"></image>
+						<view class="tip" v-if="ls.up > 0">{{ls.up * 100}}%</view>
+						<view class="tip grenn" v-if="ls.up == 0 || ls.up < 0">{{ls.up * 100}}%</view>
+					</view>
+				</view>
+			</view>
+		</view>
+		<view class="list-box flex">
+			<image src="../../static/img/img45.png"></image>
+			<image src="../../static/img/img46.png"></image>
+		</view>
+	</view>
+</template>
+<script>
+import { interceptor } from '@/utils/loginUtils';
+import { loadIndexs,moneyType } from '@/api/index.js';
+import { mapState } from 'vuex';
+export default {
+	data() {
+		return {
+			swiperCurrent: 0,
+			banner: [],
+			list:''
+		};
+	},
+	computed: {
+		...mapState(['loginInterceptor','hasLogin']),
+	},
+	onLoad: function(option) {
+		if (option.spread) {
+			// 存储其他邀请人
+			uni.setStorageSync('spread', option.spread);
+		}
+	},
+	onShow: function() {
+		// 判断是否强制登录
+		if (this.loginInterceptor && !this.hasLogin) {
+			// 登录拦截
+			interceptor();
+		}else{
+			this.loadData();
+			this.moneyType();
+		}
+	},
+	//下拉刷新
+	onPullDownRefresh() {
+		this.loadData();
+		this.moneyType();
+		setTimeout(function () {
+			uni.stopPullDownRefresh();
+		}, 1000);
+	},
+	methods: {
+		// 请求载入数据
+		async loadData() {
+			let obj = this;
+			loadIndexs({}).then(({ data }) => {
+			   obj.banner = data.banner;
+			});
+		},
+		moneyType(){
+			let obj = this;
+			moneyType({index:1}).then(({ data }) => {
+			   obj.list = data;
+			});
+		},
+		/**
+		 * 统一跳转接口,拦截未登录路由
+		 * navigator标签现在默认没有转场动画,所以用view
+		 */
+		navTo(url) {
+			uni.navigateTo({
+				url
+			});
+		},
+		//轮播图
+		swiperChange(e) {
+			let index = e.detail.current;
+			this.swiperCurrent = index;
+		},
+	}
+};
+</script>
+
+<style lang="scss">
+page {
+	min-height: 100%;
+	background-color: #ffffff;
+	.container {
+		width: 100%;
+		padding: 25rpx 40rpx;
+	}
+}
+.tiele-index{
+	font-weight: 500;
+	font-size: 50rpx;
+	padding: 15% 0rpx 30rpx 0rpx;
+}
+.top-head {
+	position: fixed;
+	top: 0;
+	z-index: 99;
+	width: 100%;
+	background-color: #272f41;
+	padding: 15rpx 35rpx;
+	color: #edc959;
+	image {
+		width: 80rpx;
+		height: 80rpx;
+	}
+	.top-name {
+		padding-left: 15rpx;
+	}
+}
+//轮播图
+.swiper {
+	width: 100%;
+	display: flex;
+	justify-content: center;
+	border-radius: 15rpx;
+	.swiper-box {
+		width: 100%;
+		height: 335rpx;
+		overflow: hidden;
+		// box-shadow: 0upx 8upx 25upx rgba(0, 0, 0, 0.2);
+		//兼容ios,微信小程序
+		border-radius: 15rpx;
+		position: relative;
+		z-index: 1;
+		swiper {
+			width: 100%;
+			height: 100%;
+			swiper-item {
+				image {
+					width: 100%;
+					height: 100%;
+					border-radius: 15rpx;
+				}
+			}
+		}
+		.indicator {
+			position: absolute;
+			bottom: 20upx;
+			left: 20upx;
+			background-color: rgba(255, 255, 255, 0.4);
+			width: 150upx;
+			height: 5upx;
+			border-radius: 3upx;
+			overflow: hidden;
+			display: flex;
+			.dots {
+				width: 0upx;
+				background-color: rgba(255, 255, 255, 1);
+				transition: all 0.3s ease-out;
+				&.on {
+					width: (100%/3);
+				}
+			}
+		}
+	}
+}
+.notice-box{
+	padding: 40rpx 0rpx;
+	.notice-title{
+		padding-bottom: 30rpx;
+		image{
+			width:35rpx;
+			height: 32rpx;
+		}
+		.title{
+			font-size: 34rpx;
+			font-weight: bold;
+			font-style: italic;
+			color: #333333;
+			margin-left: 15rpx;
+		}
+	}
+	.notice-list{
+		.notice-tpl{
+			image{
+				width: 99rpx;
+				height: 113rpx;
+			}
+			.name{
+				font-size: 26rpx;
+				color: #5D616D;
+			}
+		}	
+	}
+}
+.logo-img{
+	width: 100%;
+	height: 210rpx;
+}
+.quotation-list{
+	display: flex;
+	flex-wrap: wrap;
+	.quotation-tpl{
+		position: relative;
+		padding: 22rpx 24rpx;
+		height: 220rpx;
+		overflow: hidden;
+		display: flex;
+		flex-direction: column;
+		width:31%;
+		margin-bottom: 4%;
+		margin-right: 2%;
+		// &:nth-child(2n + 1) {
+		// 	margin-right: 2%;
+		// }
+		.tpl{
+			z-index: 99;
+			position: relative;
+			font-size: 24rpx;
+			padding-bottom: 10rpx;
+		}
+		.title{
+			color: #333333;
+			font-weight: bold;
+			padding-bottom: 21rpx !important;
+		}
+		.num{
+			color: #FB3A2F;
+		}
+		.money{
+			color: #666666;
+		}
+		.tip-box{
+			image{
+				width: 100%;
+				height: 118rpx;
+				position: absolute;
+				bottom: 0;
+				left: 0;
+			}
+			.tip{
+				position: relative;
+				color: #FB3A2F;
+				font-size: 26rpx;
+				text-align: center;
+				font-weight: 600;
+				padding-top: 25rpx;
+			}
+			.grenn{
+				color: #606266;
+			}
+			
+		}
+	}
+}
+.list-box{
+	image{
+		width: 326rpx;
+		height: 210rpx;
+	}
+}
+</style>

+ 92 - 0
pages/index/information.vue

@@ -0,0 +1,92 @@
+<template>
+	<view class="container">
+		<view v-if="list.length > 0" class="list-box flex_item" v-for="(ls,index) in list" :key='index' @click="nav(index)">
+			<image :src="ls.image_input[0]"></image>
+			<view class="list-item">
+				<view class="title ellipsis">{{ls.title}}</view>
+				<!-- <view class="time">{{ls.add_time}}</view> -->
+			</view>
+		</view>
+		<view class="empty-box" v-show="list.length === 0"><empty></empty></view>
+	</view>
+</template>
+<script>
+import { article } from '@/api/index.js';
+import empty from '@/components/empty';
+export default {
+	components: {
+		empty
+	},
+	data() {
+		return {
+			list:''
+		};
+	},
+	onLoad(option){
+		this.loadData();
+	},
+	onShow() {
+		
+	},
+	methods: {
+		// 请求载入数据
+		async loadData() {
+			let obj = this;
+			article({
+				page:1,
+				limit:10000
+			},1).then(({ data }) => {
+				console.log(data)
+				obj.list = data;
+			});
+		},
+		nav(index){
+			uni.navigateTo({
+				url: '/pages/index/informationDetails?id=' + this.list[index].id
+			})
+		},
+	}
+};
+</script>
+
+<style lang="scss">
+page {
+	min-height: 100%;
+	background-color: #ffffff;
+	.container {
+		width: 100%;
+		padding: 25rpx 27rpx;
+		
+	}
+}
+.empty-box{
+	margin-top: 100rpx;
+	width: 100%;
+	height: 500rpx;
+}
+.list-box{
+	border-bottom: 1rpx solid #E3E3E3;
+	margin-bottom: 25rpx;
+	padding-bottom: 25rpx;
+	image{
+		width: 200rpx;
+		height: 160rpx;
+		border-radius: 15rpx;
+	}
+	.list-item{
+		padding-left: 16rpx;
+		width: 80%;
+		.title{
+			height: 80rpx;
+			color: #333333;
+			font-size: 30rpx;
+			font-weight: 500;
+		}
+		.time{
+			padding-top: 40rpx;
+			color: #999999;
+			font-size: 24rpx;
+		}
+	}
+}
+</style>

+ 84 - 0
pages/index/informationDetails.vue

@@ -0,0 +1,84 @@
+<template>
+	<view class="center">
+		<view class="bg">
+			<image :src="src" mode=""></image>
+		</view>
+		<view class="title">
+			{{ title }}
+		</view>
+		<view class="content">
+			{{ synopsis }}
+		</view>
+	</view>
+</template>
+
+<script>
+import { details } from '@/api/index.js';
+export default {
+	data(){
+		return{
+			src: '',
+			title: '',
+			synopsis:'',
+			time:'',
+		}
+	},
+	onLoad(option) {
+		this.loadData(option.id);
+	},
+	methods: {
+		async loadData(id){
+			let obj = this;
+			details({},id).then(e =>{
+				console.log(e);
+				obj.src = e.data.image_input[0];
+				obj.title = e.data.title;
+				obj.synopsis = e.data.synopsis;
+				obj.time = e.data.add_time;
+			})
+		}
+	}
+}
+</script>
+
+<style lang="scss">
+	.center{
+		height: 100%;
+	}
+	.bg{
+		width: 100%;
+		height: 474rpx;
+		image{
+			width: 100%;
+			height: 100%;
+		}
+	}
+	.title{
+		width: 90%;
+		margin: 0 auto;
+		font-size: 40rpx;
+		font-weight: 500;
+		color: #171313;
+		text-overflow: -o-ellipsis-lastline;
+		overflow: hidden;
+		display: -webkit-box;
+		-webkit-line-clamp: 2;
+		-webkit-box-orient: vertical;
+	}
+	.time {
+		width: 90%;
+		margin: 0 auto;
+		margin-top: 16rpx;
+		font-size: 24rpx;
+		font-weight: 500;
+		color: #656b6c;
+	}
+	.content{
+		width: 90%;
+		margin:0 auto;
+		margin-top: 20rpx;
+		font-size: 32rpx;
+		font-weight: 500;
+		color:#777777;
+	}
+</style>

+ 34 - 0
pages/index/introduce.vue

@@ -0,0 +1,34 @@
+<template>
+	<view class="container">
+	</view>
+</template>
+<script>
+// import { userinfo } from '@/api/user.js';
+export default {
+	data() {
+		return {
+			
+		};
+	},
+	onLoad(option){},
+	onShow() {
+		
+	},
+	//下拉刷新
+	onPullDownRefresh() {
+		this.loadData();
+	},
+	methods: {}
+};
+</script>
+
+<style lang="scss">
+page {
+	min-height: 100%;
+	background-color: #ffffff;
+	.container {
+		width: 100%;
+		
+	}
+}
+</style>

+ 112 - 0
pages/index/notice.vue

@@ -0,0 +1,112 @@
+<template>
+	<view class="container">
+		<view v-if="list.length > 0" class="list-box flex_item" v-for="(ls,index) in list" :key='index' @click="nav(index)">
+			<image :src="ls.image_input[0]"></image>
+			<view class="list-item">
+				<view class="item-box flex">
+					<view class="title">{{ls.title}}</view><!-- 
+					<view class="time">{{ls.add_time}}</view> -->
+				</view>
+				<view class="info flex">
+					<view class="clamp text-info">{{ls.synopsis}}</view>
+					<view class="info-tip"></view>
+				</view>
+			</view>
+		</view>
+		<view class="empty-box" v-show="list.length === 0"><empty></empty></view>
+	</view>
+</template>
+<script>
+import { article } from '@/api/index.js';
+import empty from '@/components/empty';
+export default {
+	components: {
+		empty
+	},
+	data() {
+		return {
+			list:''
+		};
+	},
+	onLoad(option){
+	   this.loadDate();
+	},
+	onShow() {
+		
+	},
+	methods: {
+		async loadDate(){
+			let obj = this;
+			article({
+				page:1,
+				limit:10000
+			},2).then(({ data }) => {
+				console.log(data)
+			});
+		},
+		nav(index){
+			uni.navigateTo({
+				url: '/pages/index/informationDetails?id=' + this.list[index].id
+			})
+		},
+	}
+};
+</script>
+
+<style lang="scss" scoped>
+page {
+	min-height: 100%;
+	background-color: #ffffff;
+	.container {
+		background-color: #FFFFFF;
+		width: 100%;
+		padding: 25rpx 25rpx;
+		
+	}
+}
+.empty-box{
+	margin-top: 100rpx;
+	width: 100%;
+	height: 500rpx;
+}
+.list-box{
+	border-bottom: 1rpx solid #E3E3E3;
+	padding: 25rpx 0rpx;
+	image{
+		width: 61rpx;
+		height: 61rpx;
+		border-radius: 100%;
+	}
+	.list-item{
+		padding-left: 25rpx;
+		width: 90%;
+		.item-box{
+			.title{
+				font-weight: bold;
+				color: #1D2023;
+				font-size: 30rpx;
+			}
+			.time{
+				font-weight: 500;
+				color: #999999;
+				font-size: 20rpx;
+			}
+		}
+		.info{
+			padding-top: 20rpx;
+			.text-info{
+				font-weight: 500;
+				color: #999999;
+				font-size: 24rpx;
+				width: 90%;
+			}
+			.info-tip{
+				width: 11rpx;
+				height: 11rpx;
+				background-color: #FB555C;
+				border-radius: 100%;
+			}
+		}
+	}
+}
+</style>

+ 92 - 0
pages/index/pingtai.vue

@@ -0,0 +1,92 @@
+<template>
+	<view class="container">
+		<view v-if="list.length > 0" class="list-box flex_item" v-for="(ls,index) in list" :key='index' @click="nav(index)">
+			<image :src="ls.image_input[0]"></image>
+			<view class="list-item">
+				<view class="title ellipsis">{{ls.title}}</view>
+				<!-- <view class="time">{{ls.add_time}}</view> -->
+			</view>
+		</view>
+		<view class="empty-box" v-show="list.length === 0"><empty></empty></view>
+	</view>
+</template>
+<script>
+import { article } from '@/api/index.js';
+import empty from '@/components/empty';
+export default {
+	components: {
+		empty
+	},
+	data() {
+		return {
+			list:''
+		};
+	},
+	onLoad(option){
+		this.loadData();
+	},
+	onShow() {
+		
+	},
+	methods: {
+		// 请求载入数据
+		async loadData() {
+			let obj = this;
+			article({
+				page:1,
+				limit:10000
+			},3).then(({ data }) => {
+				console.log(data)
+				obj.list = data;
+			});
+		},
+		nav(index){
+			uni.navigateTo({
+				url: '/pages/index/informationDetails?id=' + this.list[index].id
+			})
+		},
+	}
+};
+</script>
+
+<style lang="scss">
+page {
+	min-height: 100%;
+	background-color: #ffffff;
+	.container {
+		width: 100%;
+		padding: 25rpx 27rpx;
+		
+	}
+}
+.empty-box{
+	margin-top: 100rpx;
+	width: 100%;
+	height: 500rpx;
+}
+.list-box{
+	border-bottom: 1rpx solid #E3E3E3;
+	margin-bottom: 25rpx;
+	padding-bottom: 25rpx;
+	image{
+		width: 200rpx;
+		height: 160rpx;
+		border-radius: 15rpx;
+	}
+	.list-item{
+		padding-left: 16rpx;
+		width: 80%;
+		.title{
+			height: 80rpx;
+			color: #333333;
+			font-size: 30rpx;
+			font-weight: 500;
+		}
+		.time{
+			padding-top: 40rpx;
+			color: #999999;
+			font-size: 24rpx;
+		}
+	}
+}
+</style>

+ 162 - 0
pages/index/share.vue

@@ -0,0 +1,162 @@
+<template>
+	<view class="container">
+		<image @longtap="bc_code" class="backImg" :src="backImg"></image>
+		<view class="tki-qrcode">
+			<canvas @longtap="bc_code" canvas-id="qrcode" />
+		</view>
+	</view>
+</template>
+
+<script>
+import uQRCode from '@/components/Sansnn-uQRCode/uqrcode.js'
+import { getUserInfo,spread } from '@/api/user.js';
+export default {
+	props: {
+		qrval: {
+			// 要生成的二维码值
+			type: String
+		}
+	},
+	data() {
+		return {
+			url: '',
+			backImg:'',
+			userInfo:''
+		};
+	},
+	onLoad() {
+		this.spread();
+		this.getInfo();
+	},
+	computed: {
+			cpSize() {
+				if(this.unit == "upx"){
+					return uni.upx2px(this.size)
+				}else{
+					return this.size
+				}
+			}
+	},
+	methods: {
+		spread(){
+			let obj = this;
+			spread({
+				type:2
+			}).then(({ data }) => {
+				obj.backImg = data[0].wap_poster;
+			});
+		},
+		getInfo(){
+			let obj = this;
+			getUserInfo({}).then(({ data }) => {
+				obj.userInfo = data;
+				// obj.loadData()
+			});
+		},
+		bc_code(){
+			let that = this;
+			console.log('保存二维码',this.backImg)
+			uni.downloadFile({           //获得二维码的临时地址
+				url:this.backImg,
+				success:(res)=>{
+					//console.log('获取url',res)
+					if(res.statusCode == 200){
+						uni.saveImageToPhotosAlbum({
+							filePath:res.tempFilePath,//传入临时地址
+							success() {
+								that.$.ti_shi('保存成功')//封装的提示
+							},
+							fail() {
+								that.$.ti_shi('保存失败')
+							}
+						})
+					}
+				}
+			})
+		},
+		//生成二维码
+		  // make() {
+			 //  let obj = this;
+		  //     uQRCode.make({
+		  //       canvasId: 'qrcode',
+		  //       componentInstance: this,
+		  //       text: obj.url,
+		  //       size: 150,
+		  //       margin: 10,
+		  //       backgroundColor: '#ffffff',
+		  //       foregroundColor: '#000000',
+		  //       fileType: 'png',
+		  //       correctLevel: uQRCode.defaults.correctLevel,
+		  //       success: res => {
+		  //         // console.log(res)
+		  //       }
+		  //     })
+		  //   },
+		// 请求载入数据
+		// async loadData() {
+		// 	let obj = this;
+		// 	obj.url = 'http://btex.frp.liuniu946.com/?id='+ obj.userInfo.invite_code;
+		// 	obj.make();
+		// },
+	},
+};
+</script>
+
+<style lang="scss">
+	page{
+		width: 100%;
+		min-height: 100%;
+		.container{
+			width: 100%;
+			height: 100%;	
+		}
+	}
+	.backImg{
+		position: absolute;
+		width: 100%;
+		height: 100%;
+	}
+.portrait{
+	width: 100%;
+	text-align: center;
+	padding-top: 80rpx;
+	padding-bottom: 30rpx;
+	image{
+		width: 250rpx;
+		height: 250rpx;
+	}
+}
+.text{
+	text-align: center;
+	width: 100%;
+	color: #FFFFFF;
+	font-size:55rpx;
+	letter-spacing:15rpx;
+}
+.uid-name{
+	padding: 50rpx 0rpx;
+	text-align: center;
+	width: 100%;
+	color: #FFFFFF;
+}
+.copy-btn{
+	color: #FFFFFF;
+	background-color: #4BA6ED;
+	border-radius: 50rpx;
+	width: 170rpx;
+	line-height: 70rpx;
+	margin: 0rpx auto;
+	text-align: center;
+}
+.tki-qrcode{
+	position: fixed;
+	bottom: 10%;
+	left: 30%;
+}
+canvas{
+	width:150px;
+	height: 150px;
+	margin: auto;
+	
+}
+</style>

+ 177 - 0
pages/product/index.vue

@@ -0,0 +1,177 @@
+<template>
+	<view class="container">
+		<view class="swiper">
+			<view class="swiper-box">
+				<swiper circular="true" autoplay="true" @change="swiperChange">
+					<swiper-item v-for="swiper in banner" :key="swiper.id" @click="ToBanner(swiper)"><image :src="swiper.pic"></image></swiper-item>
+				</swiper>
+				<view class="indicator"><view class="dots" v-for="(swiper, index) in banner" :class="[swiperCurrent >= index ? 'on' : '']" :key="index"></view></view>
+			</view>
+		</view>
+		<view class="product-section">
+			<view class="product-item" @click="navTo(1)">
+				<view class="image-wrapper"><image src="../../static/img/img01.png" mode="scaleToFill"></image></view>
+				<view class="title-box">
+					<text class="title ellipsis">质押商品名称</text>
+					<view class="price flex_item">¥8888</view>
+				</view>
+			</view>
+			<view class="product-item" >
+				<view class="image-wrapper"><image src="../../static/img/img01.png" mode="scaleToFill"></image></view>
+				<view class="title-box">
+					<text class="title ellipsis">质押商品名称</text>
+					<view class="price flex_item">¥8888</view>
+				</view>
+			</view>
+			<view class="product-item" >
+				<view class="image-wrapper"><image src="../../static/img/img01.png" mode="scaleToFill"></image></view>
+				<view class="title-box">
+					<text class="title ellipsis">质押商品名称</text>
+					<view class="price flex_item">¥8888</view>
+				</view>
+			</view>
+			<view class="product-item" >
+				<view class="image-wrapper"><image src="../../static/img/img01.png" mode="scaleToFill"></image></view>
+				<view class="title-box">
+					<text class="title ellipsis">质押商品名称</text>
+					<view class="price flex_item">¥8888</view>
+				</view>
+			</view>
+			<view class="product-item" >
+				<view class="image-wrapper"><image src="../../static/img/img01.png" mode="scaleToFill"></image></view>
+				<view class="title-box">
+					<text class="title ellipsis">质押商品名称</text>
+					<view class="price flex_item">¥8888</view>
+				</view>
+			</view>
+		</view>
+	</view>
+</template>
+<script>
+// import { userinfo } from '@/api/user.js';
+export default {
+	data() {
+		return {
+			swiperCurrent: 0,
+			banner: [{
+				pic:'/static/img/img01.png'
+			}],
+		};
+	},
+	onLoad(option){},
+	onShow() {
+		
+	},
+	//下拉刷新
+	onPullDownRefresh() {
+		this.loadData();
+	},
+	methods: {
+		navTo(id){
+			uni.navigateTo({
+				url:'/pages/product/details?id='+id
+			})
+		},
+	}
+};
+</script>
+
+<style lang="scss">
+page {
+	min-height: 100%;
+	background-color: #ffffff;
+	.container {
+		width: 100%;
+		
+	}
+}
+//轮播图
+.swiper {
+	width: 100%;
+	display: flex;
+	justify-content: center;
+	.swiper-box {
+		width: 100%;
+		height: 260rpx;
+		padding: 0 30rpx;
+		overflow: hidden;
+		// box-shadow: 0upx 8upx 25upx rgba(0, 0, 0, 0.2);
+		//兼容ios,微信小程序
+		position: relative;
+		z-index: 1;
+		swiper {
+			width: 100%;
+			height: 100%;
+			swiper-item {
+				image {
+					width: 100%;
+					height: 100%;
+				}
+			}
+		}
+		.indicator {
+			position: absolute;
+			bottom: 20upx;
+			left: 20upx;
+			background-color: rgba(255, 255, 255, 0.4);
+			width: 150upx;
+			height: 5upx;
+			border-radius: 3upx;
+			overflow: hidden;
+			display: flex;
+			.dots {
+				width: 0upx;
+				background-color: rgba(255, 255, 255, 1);
+				transition: all 0.3s ease-out;
+				&.on {
+					width: (100%/3);
+				}
+			}
+		}
+	}
+}
+/* 猜你喜欢 */
+.product-section {
+	background-color: #ffffff;
+	display: flex;
+	flex-wrap: wrap;
+	padding: 0 28rpx;
+	margin-bottom: 20rpx;
+	margin-top: 30rpx;
+	.product-item {
+		overflow: hidden;
+		display: flex;
+		flex-direction: column;
+		width:48%;
+		margin-bottom: 4%;
+		&:nth-child(2n + 1) {
+			margin-right: 4%;
+		}
+	}
+	.image-wrapper {
+		width: 100%;
+		height: 267rpx;
+		border-radius: 3px;
+		overflow: hidden;
+		image {
+			width: 100%;
+			height: 100%;
+			opacity: 1;
+		}
+	}
+	.title-box {
+		padding: 25rpx 25rpx;
+	}
+	.title {
+		color: #343434 !important;
+		font-weight: bold;
+		height: 80rpx;
+	}
+	.price {
+		font-size:40rpx;
+		font-weight: bold;
+		color: #FB3A2F;
+		border-top: 2rpx solid #f0f0f0;
+	}
+}
+</style>

+ 205 - 0
pages/public/forget.vue

@@ -0,0 +1,205 @@
+<template>
+	<view class="container">
+		<view class="logo-img"><image src="../../static/img/logo1.png"></image></view>
+		<!-- <view class="logo">LOGO</view> -->
+		<view class="login_text">
+			<view class="login_input flex_item">
+				<view class="login_img"><image class="phone" src="/static/img/img25.png"></image></view>
+				<view class="login_name"><input class="uni-input" type="number" v-model="phone" focus placeholder="请输入手机号码" /></view>
+			</view>
+			<view class="login_input flex_item">
+				<view class="login_img"><image src="/static/img/img26.png"></image></view>
+				<view class="login_name"><input class="uni-input" type="password" v-model="password" focus placeholder=" 请输入新的不少于6位的密码" /></view>
+			</view>
+			<view class="login_input flex_item">
+				<view class="login_img"><image src="/static/img/img26.png"></image></view>
+				<view class="login_name"><input class="uni-input" type="password" v-model="password2" focus placeholder="请重复输入新密码" /></view>
+			</view>
+			<view class="login_input flex">
+				<view class="login_img"><image class="codeimg" src="/static/img/img27.png"></image></view>
+				<view class="login_name flex">
+					<input class="uni-input width" v-model="code" type="number" focus placeholder="请输入验证码" />
+					<view class="code" @click="verification">{{ countDown == 0 ? '发送验证码' : countDown }}</view>
+				</view>
+			</view>
+		</view>
+		<view class="login" @click="updatalogin">确认修改</view>
+	</view>
+</template>
+<script>
+import { updatalogin } from '@/api/set.js';
+import { verify } from '@/api/login.js';
+export default {
+	data() {
+		return {
+			phone: '', //用户
+			code: '', //验证码
+			password2:'',
+			password:'',
+			time: '', //保存倒计时对象
+			countDown: 0 //倒计时
+		};
+	},
+	onLoad() {},
+	watch: {
+		// 监听倒计时
+		countDown(i) {
+			if (i == 0) {
+				clearInterval(this.time);
+			}
+		}
+	},
+	methods: {
+		updatalogin() {
+			let obj = this;
+			if (obj.phone == '') {
+				obj.$api.msg('请输入手机号码');
+				return;
+			}
+			if (!/(^1[3|4|5|7|8][0-9]{9}$)/.test(obj.phone)) {
+				obj.$api.msg('请输入正确的手机号');
+				return;
+			}
+			if (obj.password == '') {
+				obj.$api.msg('请输入密码');
+				return;
+			}
+			if (obj.password2 == '') {
+				obj.$api.msg('请再次输入密码');
+				return;
+			}
+			if (obj.password2 != obj.password) {
+				obj.$api.msg('两次密码不正确');
+				return;
+			}
+			if (obj.code == '') {
+				obj.$api.msg('请输入验证码');
+				return;
+			}
+			updatalogin({
+				account: obj.phone, //账号
+				password:obj.password,
+				password2:obj.password2,
+				type:1,
+				captcha: obj.code
+			}).then(function(e) {
+				obj.$api.msg(e.msg);
+				uni.navigateTo({
+					url: '/pages/public/login'
+				});
+			}).catch((e) => {
+				console.log(e);
+			});
+		},
+		//发送验证码
+		verification() {
+			let obj = this;
+			if (this.phone == '') {
+				this.$api.msg('请输入电话号码');
+				return;
+			}
+			if (this.phone.length < 11) {
+				this.$api.msg('请输入正确的手机号');
+				return;
+			}
+			// 判断是否在倒计时
+			if (obj.countDown > 0) {
+				return false;
+			} else {
+				obj.countDown = 60;
+				obj.time = setInterval(() => {
+					obj.countDown--;
+				}, 1000);
+				//调用验证码接口
+				verify({
+					phone: obj.phone,
+					type: 'login'
+				})
+					.then(({ data }) => {})
+					.catch(err => {
+						console.log(err);
+					});
+			}
+		},
+	}
+};
+</script>
+
+<style lang="scss">
+page {
+		min-height: 100%;
+		background-color: #ffffff;
+		.container {
+			width: 100%;
+			padding: 60rpx 70rpx;
+		}
+	}
+	.logo-img{
+		width: 161rpx;
+		height: 161rpx;
+		margin: auto;
+		margin-bottom: 15rpx !important;
+		// background: #5771DF;
+		// box-shadow: 0px 12rpx 13rpx 0px rgba(51, 145, 255, 0.47);
+		border-radius: 50%;
+		image{
+			width: 161rpx;
+			height: 161rpx;	
+			border-radius: 50%;
+		}
+	}
+	.logo{
+		font-size: 36rpx;
+		font-weight: 400;
+		color: #5771DF;
+		text-align: center;
+	}
+	.phone{
+		height: 43rpx !important;
+		width: 27rpx !important;
+	}
+	.codeimg{
+		height: 39rpx !important;
+		width: 31rpx !important;
+	}
+.login_text {
+	border-radius: 20rpx;
+	margin-top: 80rpx;
+	.login_input {
+		// border-bottom: 1px solid #C5CEE0;
+		margin-bottom:35rpx;
+		padding-bottom: 60rpx;
+		.login_img image {
+			height: 35rpx;
+			width: 31rpx;
+			margin-right: 20rpx;
+		}
+		.uni-input {
+			text-align: left;
+			width: 400rpx;
+			font-size:32rpx !important;
+		}
+		.login_name {
+			color: #333333;
+			.code {
+				color: #5771DF;
+				font-size: 23rpx;
+				border-left: 1px solid #eeeeee;
+				width: 150rpx;
+				flex-shrink: 0;
+				text-align: center;
+			}
+		}
+	}
+}
+
+.login{
+	background-color: #5771DF;
+	margin-top: 96rpx;
+	color: #FFFFFF;
+	text-align: center;
+	padding: 26rpx 0rpx;
+	border-radius: 20rpx;
+}
+
+</style>

+ 141 - 0
pages/public/login.vue

@@ -0,0 +1,141 @@
+<template>
+	<view class="container">
+		<view class="loginTitle">Welcome鲲鹏云矿</view>
+		<view class="loginText">请使用您的账号登录</view>
+		<view class="login-box">
+			<view class="username">账号</view>
+			<input class="input-box" type="number" v-model="phone" placeholder="请输入账号" />
+		</view>
+		<view class="login-box">
+			<view class="username">密码</view>
+			<input class="input-box" type="password" v-model="password" placeholder="请输入密码" />
+		</view>
+		<view class="forget" @click="navTo('/pages/public/forget')">忘记密码</view>
+		<view class="login" @click="toLogin">登录</view>
+		<view class="login-tip">还没有账号?<text class="register" @click="navTo('/pages/public/register')">立即注册</text></view>
+	</view>
+</template>
+
+<script>
+import { mapMutations } from 'vuex';
+import { login } from '@/api/login.js';
+import { getUserInfo } from '@/api/user.js';
+export default {
+	data() {
+		return {
+			phone: '',
+			password: '',
+		};
+	},
+	onLoad() {},
+	methods: {
+		...mapMutations('user', ['setUserInfo', 'login']),
+		//登录
+		async toLogin() {
+			let obj = this;
+			obj.logining = true;
+			if (obj.phone == '') {
+				obj.$api.msg('请输入手机号');
+				return;
+			}
+			if (obj.password == '') {
+				obj.$api.msg('请输入密码');
+				return;
+			}
+			login({
+				account: obj.phone,
+				password: obj.password
+			})
+				.then(function(e) {
+					uni.setStorageSync('token', e.data.token);
+					getUserInfo({}).then(e => {
+						obj.login();
+						// 保存返回用户数据
+						obj.setUserInfo(e.data);
+						uni.switchTab({
+							url:'/pages/index/index'
+						})
+					});
+				})
+				.catch(function(e) {
+					console.log(e);
+				});
+		},
+		navTo(url) {
+			uni.navigateTo({
+				url
+			});
+		},
+		// 后退
+		navBack() {
+			uni.navigateBack();
+		}
+	}
+};
+</script>
+
+<style lang="scss">
+page {
+		min-height: 100%;
+		background-color: #ffffff;
+		.container {
+			width: 100%;
+			padding: 30% 60rpx;
+		}
+	}
+.loginTitle {
+	font-weight: bold;
+	color: #333333;
+	font-size: 58rpx;
+	padding-bottom: 34rpx;
+}
+.loginText {
+	font-weight: 500;
+	color: #333333;
+	font-size: 34rpx;
+	padding-bottom: 34rpx;
+}
+.login-box{
+	padding-top: 90rpx;
+	.username{
+		padding-bottom: 30rpx;
+		font-weight: 500;
+		color: #333333;
+		font-size: 32rpx;
+	}
+}
+.forget{
+	text-align: right;
+	margin: 70rpx 0rpx;
+	font-weight: 500;
+	color: #333333;
+	font-size: 28rpx;
+}
+.login{
+	background-color: #5771DF;
+	margin-top: 20rpx;
+	color: #FFFFFF;
+	text-align: center;
+	padding: 26rpx 0rpx;
+	border-radius: 50rpx;
+}
+.login-tip{
+	padding: 60rpx 0rpx;
+	text-align: center;
+	font-weight: 500;
+	color: #333333;
+	font-size: 28rpx;
+	.register{
+		color: #5771DF;
+	}
+}
+// /* input 样式 */
+// .input-placeholder {
+// 	color: #ffffff;
+// }
+
+// .placeholder {
+// 	color: #ffffff;
+// }
+
+</style>

+ 204 - 0
pages/public/register.vue

@@ -0,0 +1,204 @@
+<template>
+	<view class="container">
+		<view class="loginTitle">欢迎注册鲲鹏云矿</view>
+		<view class="loginText">请认真填写个人信息</view>
+		<view class="login-box">
+			<view class="username">账号</view>
+			<input class="input-box" type="number" v-model="phone" placeholder="请输入手机号" />
+		</view>
+		<view class="login-box">
+			<view class="username">验证码</view>
+			<view class="flex">
+				<input class="input-box" type="number" v-model="code" placeholder="请输入验证码" />
+				<view class="code" @click="verification">{{ countDown == 0 ? '获取验证码' : countDown }}</view>
+			</view>
+		</view>
+		<view class="login-box">
+			<view class="username">登录密码</view>
+			<input class="input-box" type="password" v-model="loginPass"  placeholder="请输入登录密码" />
+		</view>
+		<view class="login-box">
+			<view class="username">支付密码</view>
+			<input class="input-box" type="password" v-model="payPass" placeholder="请输入支付密码" />
+		</view>
+		<view class="login-box">
+			<view class="username">邀请码</view>
+			<input class="input-box" type="password" v-model="invitation"  placeholder="请输入邀请码" />
+		</view>
+		<view class="login" @click="register">注册</view>
+	</view>
+</template>
+
+<script>
+	import { register, verify } from '@/api/login.js';
+	export default {
+		data() {
+			return {
+				phone: '', //用户
+				loginPass: '', //密码
+				payPass: '',
+				invitation: '', //邀请码
+				code: '', //验证码
+				time: '', //保存倒计时对象
+				countDown: 0, //倒计时
+			};
+		},
+		onLoad() {
+			// 获取扫码邀请人id
+			this.invitation = uni.getStorageSync('spread') || '';
+		},
+		watch: {
+			// 监听倒计时
+			countDown(i) {
+				if (i == 0) {
+					clearInterval(this.time);
+				}
+			}
+		},
+		methods: {
+			// 注册
+			register() {
+				let obj = this;
+				if (obj.phone == '') {
+					obj.$api.msg('请输入电话号码');
+					return;
+				}
+				if (!/(^1[3|4|5|7|8][0-9]{9}$)/.test(obj.phone)) {
+					obj.$api.msg('请输入正确的手机号');
+					return;
+				}
+				if (obj.loginPass == '') {
+					obj.$api.msg('请输入登录密码');
+					return;
+				}
+				if (obj.payPass == '') {
+					obj.$api.msg('请输入支付密码');
+					return;
+				}
+				if (obj.code == '') {
+					obj.$api.msg('请输入验证码');
+					return;
+				}
+				if (obj.invitation == '') {
+					obj.$api.msg('请输入邀请码');
+					return;
+				}
+				register({
+					phone: obj.phone, //账号
+					captcha: obj.code, //验证码
+					password:obj.loginPass,
+					trade_password:obj.payPass,
+					invite_code:obj.invitation
+				}).then(function(e) {
+					uni.showToast({
+						title: '注册成功',
+						duration: 2000,
+						position: 'top',
+						icon: 'none'
+					});
+					setTimeout(function() {
+						uni.navigateTo({
+							url: '/pages/public/login'
+						});
+					}, 1000)
+
+				});
+				//调用注册接口,成功跳转登录页
+			},
+			//发送验证码
+			verification() {
+				let obj = this;
+				if (this.phone == '') {
+					this.$api.msg('请输入电话号码');
+					return;
+				}
+				if (this.phone.length < 11) {
+					this.$api.msg('请输入正确的手机号');
+					return;
+				}
+				// 判断是否在倒计时
+				if (obj.countDown > 0) {
+					return false;
+				} else {
+					obj.countDown = 60;
+					obj.time = setInterval(() => {
+						obj.countDown--;
+					}, 1000);
+					//调用验证码接口
+					verify({
+							phone: obj.phone,
+							type: 'register'
+						})
+						.then(({
+							data
+						}) => {})
+						.catch(err => {
+							console.log(err);
+						});
+				}
+			},
+		}
+	};
+</script>
+
+<style lang="scss">
+	page {
+		min-height: 100%;
+		background-color: #ffffff;
+
+		.container {
+			width: 100%;
+			padding: 10% 60rpx 0rpx 60rpx;
+		}
+	}
+
+	.loginTitle {
+		font-weight: bold;
+		color: #333333;
+		font-size: 58rpx;
+		padding-bottom: 25rpx;
+	}
+
+	.loginText {
+		font-weight: 500;
+		color: #333333;
+		font-size: 34rpx;
+	}
+
+	.login-box {
+		padding-top: 70rpx;
+		.username {
+			padding-bottom: 25rpx;
+			font-weight: 500;
+			color: #333333;
+			font-size: 32rpx;
+		}
+	}
+
+	.login {
+		background-color: #5771DF;
+		margin-top: 20rpx;
+		color: #FFFFFF;
+		text-align: center;
+		padding: 26rpx 0rpx;
+		border-radius: 50rpx;
+		margin-top: 60rpx;
+	}
+    .code{
+		background-color: #5771DF;
+		color: #FFFFFF;
+		border-radius: 10rpx;
+		font-weight: 500;
+		color: #FFFFFF;
+		font-size: 26rpx;
+		padding: 12rpx 19rpx;
+	}
+	// /* input 样式 */
+	// .input-placeholder {
+	// 	color: #ffffff;
+	// }
+
+	// .placeholder {
+	// 	color: #ffffff;
+	// }
+</style>

+ 83 - 0
pages/public/wxLogin.vue

@@ -0,0 +1,83 @@
+<template>
+	<view class="content">
+		<!-- #ifdef MP -->
+		<image class="bg-img" src="/static/img/img09.png" mode=" scaleToFill"></image>
+		<view class="logo-img-box">
+			<image class="logo-img" src="/static/img/img10.png" mode=" aspectFit"></image>
+			<button class="userInfo" type="warn" open-type="getUserInfo" @getuserinfo="userInfoData">
+				<text class="iconfont iconweixin"></text>
+				<text>微信授权登录</text>
+			</button>
+		</view>
+		<!-- #endif -->
+	</view>
+</template>
+
+<script>
+// #ifdef H5
+import { loginWinxin } from '@/utils/wxAuthorized';
+// #endif
+// #ifdef MP-WEIXIN
+import { loginWinxinMp } from '@/utils/wxMinProgram';
+// #endif
+import { mapMutations } from 'vuex';
+export default {
+	data() {
+		return {
+			userInfo: {}, //授权用户信息
+			code: '' //授权code
+		};
+	},
+	onLoad(option) {
+		this.loadData();
+	},
+	methods: {
+		loadData() {
+			// #ifdef H5
+			loginWinxin();
+			// #endif
+			// #ifdef MP-WEIXIN
+			loginWinxinMp({}).then(e => {
+				this.code = e.code;
+			});
+			// #endif
+		},
+		// 用户确认授权
+		userInfoData(e) {
+			console.log(e);
+			this.userInfo = e;
+			uni.navigateTo({
+				url: '/pages/redirect/redirect?code=' + this.code
+			});
+		}
+	}
+};
+</script>
+
+<style lang="scss">
+page,
+.content {
+	height: 100%;
+}
+.bg-img,
+.logo-img-box {
+	position: absolute;
+	top: 0;
+	left: 0;
+	width: 100%;
+	height: 100%;
+}
+.logo-img {
+	margin-top: 20vh;
+	margin-left: 176rpx;
+	width: 385rpx;
+	height: 394rpx;
+}
+.userInfo {
+	margin: 0 100rpx;
+	margin-top: 50rpx;
+	color: #ffffff;
+	border-radius: 99rpx;
+	background-color: $base-color;
+}
+</style>

+ 124 - 0
pages/redirect/redirect.vue

@@ -0,0 +1,124 @@
+<template>
+	<view>
+	</view>
+</template>
+<script>
+import { getUserInfo } from '@/api/login.js';
+import { mapMutations,mapState } from 'vuex';
+// #ifdef H5
+import { wechatAuth } from '@/api/wx';
+// #endif
+// #ifdef MP-WEIXIN
+import { wechatMpAuth } from '@/api/wx';
+// #endif
+export default {
+	computed: {
+		...mapState(['urlFile'])
+	},
+	onLoad(option) {
+		let obj = this;
+		// 判断是否需要保存定向地址
+		// #ifdef H5
+		this.loadH5()
+		// #endif
+		// #ifdef MP-WEIXIN
+		this.loadMp(option)
+		// #endif
+	},
+	methods: {
+		...mapMutations('user',['login', 'setUserInfo']),
+		// #ifdef H5
+		loadH5() {
+			let obj = this;
+			let url = window.location.href;
+			let code = url.match(/code=([0-9]|[a-z]|[A-Z])*/g)[0].replace('code=', '');
+			let spread = uni.getStorageSync('spread')||'';
+			wechatAuth({
+				code: code,
+				spread:spread,
+			}).then(({ data }) => {
+				obj.wchatAuth(data);
+			}).catch((e) => {
+				uni.showModal({
+					title: '错误',
+					content: JSON.stringify(e),
+					showCancel: false,
+				});
+			});;
+		},
+		// #endif
+		// #ifdef MP-WEIXIN
+		loadMp(option) {
+			let obj = this;
+			// 获取登录授权页数据
+			let user = obj.$api.prePage().userInfo;
+			// #ifndef MP
+			// 获取推广人id
+			let spread_spid = uni.getStorageSync('spread') || '';
+			// #endif
+			// #ifdef MP
+			// 小程序推广人
+			let spread_code = uni.getStorageSync('spread_code') || '';
+			// #endif
+			wechatMpAuth({
+				code: option.code,
+				iv: user.target.iv,
+				encryptedData: user.target.encryptedData,
+				// #ifndef MP
+				spread_spid: spread_spid,
+				// #endif
+				// #ifdef MP
+				spread_code:spread_code
+				// #endif
+			}).then(({ data }) => {
+				obj.wchatAuth(data);
+				// 设置成功后修改当前页面
+				history.replaceState({ name: '首页' }, '首页', obj.urlFile+'/#/pages/index/index');
+			}).catch((e) => {
+				uni.showModal({
+					title: '错误',
+					content: JSON.stringify(e),
+					showCancel: false,
+				});
+			});
+		},
+		// #endif
+		wchatAuth(data) {
+			let obj = this;
+			// 保存token
+			uni.setStorageSync('token', data.token);
+			// 获取用户基础信息
+			getUserInfo({}).then(e => {
+				obj.login();
+				// 保存返回用户数据
+				obj.setUserInfo(e.data);
+				let ur = uni.getStorageSync('present')|| '/pages/index/index';
+				// 用于处理缓存bug
+				if (ur=='pages/product/product') {
+					ur = '/pages/index/index'
+				}
+				uni.switchTab({
+					url: ur,
+					fail(e) {
+						uni.navigateTo({
+							url: ur,
+							fail(e) {
+								uni.navigateTo({
+									url: '/pages/index/index',
+								});
+							}
+						});
+					}
+				});
+			}).catch((e) => {
+				uni.showModal({
+					title: '错误',
+					content: JSON.stringify(e),
+					showCancel: false,
+				});
+			});;
+		}
+	}
+};
+</script>
+<style></style>

+ 103 - 0
pages/set/set.vue

@@ -0,0 +1,103 @@
+<template>
+	<view class="container">
+		<view class="row b-b flex">
+			<text class="tit">头像</text>
+			<image :src="userInfo.avatar"></image>
+		</view>
+		<view class="row b-b flex">
+			<text class="tit">昵称</text>
+			<input class="input" v-model="userInfo.nickname" type="text" disabled="true" placeholder-class="placeholder" />
+		</view>
+		<view class="row b-b flex">
+			<text class="tit">ID</text>
+			<input class="input" v-model="userInfo.uid" type="text" disabled="true" placeholder-class="placeholder" />
+		</view>
+		<view class="row b-b flex">
+			<text class="tit">用户账号</text>
+			<input class="input" v-model="userInfo.account" type="number" disabled="true" placeholder-class="placeholder" />
+		</view>
+		<view class="submit-box">
+			<view class="submit" @click="toLogout">退出登录</view>
+		</view>
+	</view>
+</template>
+<script>
+import uniList from '@/components/uni-list/uni-list.vue';
+import uniListItem from '@/components/uni-list-item/uni-list-item.vue';
+import { mapState, mapMutations } from 'vuex';
+import { logout } from '@/api/set.js';
+export default {
+	components: {
+		uniList,
+		uniListItem
+	},
+	data() {
+		return {
+			// nickName:'李淡淡',
+			// id:'HFBNXISN',
+			// account:'13745262356',
+			userInfo:'',
+		};
+	},
+	onLoad() {
+		this.userInfo = uni.getStorageSync('userInfo') || '';
+	},
+	methods: {
+		...mapMutations('user',['logout']),
+		//退出登录
+		toLogout() {
+			let obj = this;
+			uni.showModal({
+				content: '确定要退出登录么',
+				success: e => {
+					if (e.confirm) {
+						logout({}).then(e => {
+							obj.logout();
+							uni.navigateTo({
+								url:'/pages/public/login'
+							})
+						})
+						.catch(e => {
+							console.log(e);
+						});
+					}
+				}
+			});
+		},
+	}
+};
+</script>
+
+<style lang="scss">
+page {
+	min-height: 100%;
+	.container{
+		height: 100%;
+		
+	}
+}
+.row {
+	padding: 42rpx 25rpx;
+	font-size: 30rpx;
+	color: #333333;
+	image{
+		width: 80rpx;
+		height: 80rpx;
+		border-radius: 50%;
+	}
+	.input {
+		text-align: right;
+		color: #333333;
+	}
+}
+.submit-box{
+		padding: 157rpx 95rpx;
+		.submit{
+			background-color: #5771DF;
+			color: #FFFFFF;
+			text-align: center;
+			padding:26rpx 0rpx;
+			border-radius: 50rpx;
+		}
+	}
+</style>

+ 190 - 0
pages/user/loginPass.vue

@@ -0,0 +1,190 @@
+<template>
+	<view class="container">
+		<view class="list-box">
+			<view class="flex_item list-title">
+				<view class="tip"></view>
+				<view class="title">登录密码</view>
+			</view>
+			<view class="list-cell flex_item">
+				<view class="cell-name">新密码</view>
+				<input type="password" v-model="password" placeholder="请输入不小于6位数的密码" />
+			</view>
+			<view class="list-cell flex_item">
+				<view class="cell-name">重复密码</view>
+				<input type="password" v-model="password2" placeholder="请重复输入密码" />
+			</view>
+			<view class="list-cell flex_item">
+				<view class="cell-name nameCode">验证码</view>
+				<view class="code-box flex">
+					<input type="number" v-model="code" placeholder="请输入验证码" />
+					<view class="code" @click="verification">{{ countDown == 0 ? '验证码' : countDown }}</view>
+				</view>
+			</view>
+		</view>
+		<view class="submit" @click="updatalogin">确认</view>
+	</view>
+</template>
+<script>
+import { updatalogin } from '@/api/set.js';
+import { verify } from '@/api/login.js';
+export default {
+	data() {
+		return {
+			phone: '', //用户
+			code: '', //验证码
+			password2:'',
+			password:'',
+			time: '', //保存倒计时对象
+			countDown: 0 //倒计时
+		};
+	},
+	onLoad(option){
+		let userInfo = uni.getStorageSync('userInfo') || '';
+		this.phone = userInfo.account
+	},
+	onShow() {
+		
+	},
+	watch: {
+		// 监听倒计时
+		countDown(i) {
+			if (i == 0) {
+				clearInterval(this.time);
+			}
+		}
+	},
+	//下拉刷新
+	onPullDownRefresh() {
+		this.loadData();
+	},
+	methods: {
+		updatalogin() {
+			let obj = this;
+			if (obj.password == '') {
+				obj.$api.msg('请输入新密码');
+				return;
+			}
+			if (obj.password2 == '') {
+				obj.$api.msg('请再次输入密码');
+				return;
+			}
+			if (obj.password2 != obj.password) {
+				obj.$api.msg('两次密码不正确');
+				return;
+			}
+			if (obj.code == '') {
+				obj.$api.msg('请输入验证码');
+				return;
+			}
+			updatalogin({
+				account: obj.phone, //账号
+				password:obj.password,
+				password2:obj.password2,
+				type:1,
+				captcha: obj.code
+			}).then(function(e) {
+				obj.$api.msg(e.msg);
+				uni.switchTab({
+					url: '/pages/user/user'
+				})
+			}).catch((e) => {
+				console.log(e);
+			});
+		},
+		//发送验证码
+		verification() {
+			let obj = this;
+			if (this.phone == '') {
+				this.$api.msg('请输入电话号码');
+				return;
+			}
+			if (this.phone.length < 11) {
+				this.$api.msg('请输入正确的手机号');
+				return;
+			}
+			// 判断是否在倒计时
+			if (obj.countDown > 0) {
+				return false;
+			} else {
+				obj.countDown = 60;
+				obj.time = setInterval(() => {
+					obj.countDown--;
+				}, 1000);
+				//调用验证码接口
+				verify({
+					phone: obj.phone,
+					type: 'login'
+				})
+					.then(({ data }) => {})
+					.catch(err => {
+						console.log(err);
+					});
+			}
+		},
+	}
+};
+</script>
+
+<style lang="scss">
+page {
+	min-height: 100%;
+	background-color: #ffffff;
+	.container {
+		width: 100%;
+		padding: 27rpx 31rpx;
+		
+	}
+}
+.list-box{
+	.list-title{
+		font-size: 30rpx;
+		font-weight: 500;
+		color: #333333;
+		margin-bottom: 61rpx;
+		.tip{
+			width: 2rpx;
+			height: 30rpx;
+			background: #4C5D97;
+			margin-right:17rpx ;
+		}
+	}
+	.list-cell{
+		margin-bottom: 70rpx;
+		.cell-name{
+			width: 30%;
+			font-size: 26rpx;
+			font-weight: 500;
+			color: #333333;
+		}
+		.nameCode{
+			width: 42% !important;
+		}
+		.code-box{
+			width: 100% !important;
+			input{
+				width: 50%;
+			}
+			.code{
+				font-size: 26rpx;
+				font-weight: 500;
+				color: #5771DF;
+			}
+		}
+		input{
+			width: 60%;
+			text-align: left;
+			font-size: 26rpx;
+			font-weight: 500;
+		}
+	}
+}
+	.submit {
+		background-color: #5771DF;
+		margin-top: 20rpx;
+		color: #FFFFFF;
+		text-align: center;
+		padding: 20rpx 0rpx;
+		border-radius: 50rpx;
+		margin-top: 60rpx;
+	}
+</style>

+ 77 - 0
pages/user/meaasge.vue

@@ -0,0 +1,77 @@
+<template>
+	<view class="content">
+		<view v-if="list.length > 0" class="list-Box flex" v-for="(ls,index) in list" :key='index'>
+			<view class="list-info">
+				<view class="title">{{ls.title}}</view>
+				<view class="info">{{ls.synopsis}}</view>
+			</view>
+			<view class="time">{{ls.add_time}}</view>
+		</view>
+		<view class="empty-box" v-show="list.length === 0"><empty></empty></view>
+	</view>
+</template>
+
+<script>
+	import { article } from '@/api/index.js';
+	import empty from '@/components/empty';
+export default {
+	components: {
+		empty
+	},
+	data() {
+		return {
+			list:''
+		};
+	},
+	onLoad() {
+	   this.loadDate();
+	},
+	methods: {
+		async loadDate(){
+			let obj = this;
+			article({
+				page:1,
+				limit:10000
+			},2).then(({ data }) => {
+				console.log(data)
+			});
+		},
+	}
+};
+</script>
+
+<style lang="scss">
+page {
+	height: 100%;
+	.content {
+		height: 100%;
+		padding: 35rpx 29rpx;
+	}
+}
+.empty-box{
+	margin-top: 100rpx;
+	width: 100%;
+	height: 500rpx;
+}
+.list-Box{
+	margin-bottom: 60rpx;
+	.list-info{
+		.title{
+			font-size: 30rpx;
+			font-weight: 500;
+			color: #333333;
+			line-height: 55rpx;
+		}
+		.info{
+			font-size: 24rpx;
+			font-weight: 500;
+			color: #999999;
+		}
+	}
+	.time{
+		font-size: 22rpx;
+		font-weight: 500;
+		color: #333333;
+	}
+}
+</style>

+ 209 - 0
pages/user/myTeam.vue

@@ -0,0 +1,209 @@
+<template>
+	<view class="container">
+		<view class="list-box flex">
+			<view class="list-tpl">
+				<view class="num">{{data.recommend_num || 0}}</view>
+				<view class="name">你的矿工数</view>
+			</view>
+			<view class="list-tpl" @click="nav('/pages/finance/allMiner')">
+				<view class="num">{{data.group_num || 0}}</view>
+				<view class="name">总矿工数</view>
+			</view>
+			<!-- <view class="list-title">我的团队</view> -->
+		</view>
+		<view class="info-box">
+			<view class="info-name flex">
+				<view class="info-cell">
+					<view class="cell">{{data.recommend_achievement || 0}}T</view>
+					<view class="cell-title">分享业绩</view>
+				</view>
+				<view class="info-cell">
+					<view class="cell">{{data.group_achievenent || 0}}T</view>
+					<view class="cell-title">我的业绩</view>
+				</view>
+				<view class="info-cell">
+					<view class="cell">{{data.today_achievement || 0}}T</view>
+					<view class="cell-title">今日新增业绩</view>
+				</view>
+			</view>
+			<view class="list-cell" v-if="list.length > 0">
+				<view class="cell-name flex">
+					<view class="title">成员信息</view>
+					<view class="title-box flex">
+						<view class="title">等待算力</view>
+						<view class="title">算力</view>
+						<view class="title">等级</view>
+					</view>
+				</view>
+				<view class="cell-box flex" v-for="(ls,index) in list" :key='index'>
+					<view class="cell-tit flex_item">
+						<image :src="ls.avatar"></image>
+						<view class="tit-box">
+							<view class="tit-tpl clamp">{{ls.nickname}}</view>
+							<view class="tit-tip">{{ls.phone}}</view>
+						</view>
+					</view>
+					<view class="flex num-box">
+						<view class="num clamp">{{ls.wait_mining}}T</view>
+						<view class="num clamp">{{ls.mining}}T</view>
+						<view class="level">V{{ls.level}}</view>
+					</view>
+				</view>
+			</view>
+			<view class="empty-box" v-show="list.length === 0"><empty></empty></view>
+		</view>
+	</view>
+</template>
+<script>
+import { spread } from '@/api/finance.js';
+import empty from '@/components/empty';
+export default {
+	components: {
+		empty
+	},
+	data() {
+		return {
+			data:'',
+			list:'',
+		};
+	},
+	onLoad(option){
+		this.loadData();
+	},
+	onShow() {
+	},
+	methods: {
+		// 请求载入数据
+		async loadData() {
+			let obj = this;
+			spread({}).then(({ data }) => {
+				obj.data = data;
+				obj.list = data.list;
+			   console.log(obj.list)
+			});
+		},
+		nav(url){
+			uni.navigateTo({
+				url:url
+			})
+		}
+	}
+};
+</script>
+
+<style lang="scss">
+page {
+	min-height: 100%;
+	background-color: #ffffff;
+	.container {
+		width: 100%;
+	}
+}
+.list-box{
+	width: 100%;
+	padding: 50rpx 41rpx;
+	padding-top: 80rpx !important;
+	background-color: #5771DF;
+	position: relative;
+	.list-title{
+		position: absolute;
+		top: 80rpx;
+		color: #FFFFFF;
+		left: 40%;
+		font-size: 36rpx;
+	}
+	.list-tpl{
+		background-color: #FFFFFF;
+		width: 314rpx;
+		height: 168rpx;
+		text-align: center;
+		padding-top:40rpx;
+		border-radius: 15rpx;
+		.num{
+			font-size: 36rpx;
+			font-weight: bold;
+			color: #333333;
+			padding-bottom: 15rpx;
+		}
+		.name{
+			font-size: 26rpx;
+			font-weight: 500;
+			color: #999999;
+		}
+	}
+}
+.info-box{
+	// padding: 25rpx 25rpx;
+	.info-name{
+		padding: 40rpx 0rpx;
+		.info-cell{
+			width: 33.33%;
+			text-align: center;
+			.cell{
+				font-size: 38rpx;
+				font-weight: bold;
+				color: #333333;
+			}
+			.cell-title{
+				font-size: 26rpx;
+				font-weight: 500;
+				color: #999999;
+				padding-top: 20rpx;
+			}
+		}
+	}
+	.list-cell{
+		padding: 40rpx 25rpx;
+		.cell-name{
+			padding:50rpx 50rpx;
+			.title-box{
+				width: 60%;
+			}
+		}
+		.cell-box{
+			margin-bottom: 94rpx;
+			.cell-tit{
+				width: 40%;
+				image{
+					width: 80rpx;
+					height: 80rpx;
+					border-radius: 100%;
+				}
+				.tit-box{
+					padding-left: 15rpx;
+					width: 70%;
+					.tit-tpl{
+						font-size: 30rpx;
+						font-weight: 500;
+						color: #333333;
+					}
+					.tit-tip{
+						font-size: 24rpx;
+						font-weight: 500;
+						color: #999999;
+						padding-top: 20rpx;
+					}
+				}
+			}
+			.num-box{
+				width: 60%;
+				.num{
+					width: 33.33%;
+					text-align: center;
+				}
+				.level{
+					background-color: #FED82F;
+					border-radius: 25rpx;
+					padding: 8rpx 50rpx;
+					font-size: 26rpx;
+				}
+			}
+		}
+	}
+}
+.empty-box{
+	margin-top: 60rpx;
+	width: 100%;
+	height: 500rpx;
+}
+</style>

+ 190 - 0
pages/user/payment.vue

@@ -0,0 +1,190 @@
+<template>
+	<view class="container">
+		<view class="list-box">
+			<view class="flex_item list-title">
+				<view class="tip"></view>
+				<view class="title">支付密码</view>
+			</view>
+			<view class="list-cell flex_item">
+				<view class="cell-name">新密码</view>
+				<input type="password" v-model="password" placeholder="请输入不小于6位数的密码" />
+			</view>
+			<view class="list-cell flex_item">
+				<view class="cell-name">重复密码</view>
+				<input type="password" v-model="password2" placeholder="请重复输入密码" />
+			</view>
+			<view class="list-cell flex_item">
+				<view class="cell-name nameCode">验证码</view>
+				<view class="code-box flex">
+					<input type="number" v-model="code" placeholder="请输入验证码" />
+					<view class="code" @click="verification">{{ countDown == 0 ? '验证码' : countDown }}</view>
+				</view>
+			</view>
+		</view>
+		<view class="submit" @click="updatalogin">确认</view>
+	</view>
+</template>
+<script>
+import { updatalogin } from '@/api/set.js';
+import { verify } from '@/api/login.js';
+export default {
+	data() {
+		return {
+			phone: '', //用户
+			code: '', //验证码
+			password2:'',
+			password:'',
+			time: '', //保存倒计时对象
+			countDown: 0 //倒计时
+		};
+	},
+	onLoad(option){
+		let userInfo = uni.getStorageSync('userInfo') || '';
+		this.phone = userInfo.account
+	},
+	onShow() {
+		
+	},
+	watch: {
+		// 监听倒计时
+		countDown(i) {
+			if (i == 0) {
+				clearInterval(this.time);
+			}
+		}
+	},
+	//下拉刷新
+	onPullDownRefresh() {
+		this.loadData();
+	},
+	methods: {
+		updatalogin() {
+			let obj = this;
+			if (obj.password == '') {
+				obj.$api.msg('请输入新密码');
+				return;
+			}
+			if (obj.password2 == '') {
+				obj.$api.msg('请再次输入密码');
+				return;
+			}
+			if (obj.password2 != obj.password) {
+				obj.$api.msg('两次密码不正确');
+				return;
+			}
+			if (obj.code == '') {
+				obj.$api.msg('请输入验证码');
+				return;
+			}
+			updatalogin({
+				account: obj.phone, //账号
+				password:obj.password,
+				password2:obj.password2,
+				type:2,
+				captcha: obj.code
+			}).then(function(e) {
+				obj.$api.msg(e.msg);
+				uni.switchTab({
+					url: '/pages/user/user'
+				})
+			}).catch((e) => {
+				console.log(e);
+			});
+		},
+		//发送验证码
+		verification() {
+			let obj = this;
+			if (this.phone == '') {
+				this.$api.msg('请输入电话号码');
+				return;
+			}
+			if (this.phone.length < 11) {
+				this.$api.msg('请输入正确的手机号');
+				return;
+			}
+			// 判断是否在倒计时
+			if (obj.countDown > 0) {
+				return false;
+			} else {
+				obj.countDown = 60;
+				obj.time = setInterval(() => {
+					obj.countDown--;
+				}, 1000);
+				//调用验证码接口
+				verify({
+					phone: obj.phone,
+					type: 'login'
+				})
+					.then(({ data }) => {})
+					.catch(err => {
+						console.log(err);
+					});
+			}
+		},
+	}
+};
+</script>
+
+<style lang="scss">
+page {
+	min-height: 100%;
+	background-color: #ffffff;
+	.container {
+		width: 100%;
+		padding: 27rpx 31rpx;
+		
+	}
+}
+.list-box{
+	.list-title{
+		font-size: 30rpx;
+		font-weight: 500;
+		color: #333333;
+		margin-bottom: 61rpx;
+		.tip{
+			width: 2rpx;
+			height: 30rpx;
+			background: #4C5D97;
+			margin-right:17rpx ;
+		}
+	}
+	.list-cell{
+		margin-bottom: 70rpx;
+		.cell-name{
+			width: 30%;
+			font-size: 26rpx;
+			font-weight: 500;
+			color: #333333;
+		}
+		.nameCode{
+			width: 42% !important;
+		}
+		.code-box{
+			width: 100% !important;
+			input{
+				width: 50%;
+			}
+			.code{
+				font-size: 26rpx;
+				font-weight: 500;
+				color: #5771DF;
+			}
+		}
+		input{
+			width: 60%;
+			text-align: left;
+			font-size: 26rpx;
+			font-weight: 500;
+		}
+	}
+}
+	.submit {
+		background-color: #5771DF;
+		margin-top: 20rpx;
+		color: #FFFFFF;
+		text-align: center;
+		padding: 20rpx 0rpx;
+		border-radius: 50rpx;
+		margin-top: 60rpx;
+	}
+</style>

+ 306 - 0
pages/user/user.vue

@@ -0,0 +1,306 @@
+<template>
+	<view class="container">
+		<view class="user-box flex">
+			<view class="user-info">
+				<view class="name">我的</view>
+				<view class="phone">{{phone}}</view>
+				<view class="uuid">UID:{{userInfo.uid}}</view>
+				<view class="level-box">
+					<image class="image" src="../../static/img/img28.png"></image>
+					<view class="level">V{{userInfo.level}}</view>
+				</view>
+			</view>
+			<image class="header" :src="userInfo.avatar"></image>
+		</view>
+		<view class="list-box">
+			<view class="list-title">我的工具</view>
+			<view class="list-cell flex" @click="navTo('/pages/user/myTeam')">
+				<view class="cell-info flex_item">
+					<image src="../../static/img/img17.png"></image>
+					<view class="cell-name">我的分享</view>
+				</view>
+				<image src="../../static/img/img23.png"></image>
+			</view>
+			<view class="list-cell flex" @click="navTo('/pages/index/share')">
+				<view class="cell-info flex_item">
+					<image class="img1" src="../../static/img/img18.png"></image>
+					<view class="cell-name">邀请链接</view>
+				</view>
+				<image src="../../static/img/img23.png"></image>
+			</view>
+		     	<view class="list-cell flex" @click="navTo('/pages/user/payment')">
+				<view class="cell-info flex_item">
+					<image class="img2" src="../../static/img/img19.png"></image>
+					<view class="cell-name">支付密码</view>
+				</view>
+				<image src="../../static/img/img23.png"></image>
+			</view>
+			<view class="list-cell flex" @click="navTo('/pages/user/loginPass')">
+				<view class="cell-info flex_item">
+					<image class="img3" src="../../static/img/img20.png"></image>
+					<view class="cell-name">登录密码</view>
+				</view>
+				<image src="../../static/img/img23.png"></image>
+			</view>
+			<view class="list-cell flex" @click="navTo('/pages/user/meaasge')">
+				<view class="cell-info flex_item">
+					<image class="img4" src="../../static/img/img21.png"></image>
+					<view class="cell-name">消息通知</view>
+				</view>
+				<image src="../../static/img/img23.png"></image>
+			</view>
+			<view class="list-cell flex" @click="server()">
+				<view class="cell-info flex_item">
+					<image class="img4" src="../../static/img/img47.png"></image>
+					<view class="cell-name">联系客服</view>
+				</view>
+				<image src="../../static/img/img23.png"></image>
+			</view>
+			<view class="list-cell flex" @click="navTo('/pages/set/set')">
+				<view class="cell-info flex_item">
+					<image class="img5" src="../../static/img/img22.png"></image>
+					<view class="cell-name">设置</view>
+				</view>
+				<image src="../../static/img/img23.png"></image>
+			</view>
+		</view>
+		<!-- 申请退款弹窗 -->
+		<uni-popup ref="popup" type="center">
+			<view class="popup">
+				<view class="popup-dox">
+					<image class="popup-logo" src="../../static/img/img48.png"></image>
+					<view class="pop-title">已为您定制专属客服</view>
+					<image class="popup-text" src="../../static/img/img50.png"></image>
+					<view class="pop-tip">微信咨询客服</view>
+				</view>
+			</view>
+			<view class="close_icon" @click="close"><image src="../../static/img/img49.png"></image></view>
+		</uni-popup>
+	</view>
+</template>
+<script>
+import { getUserInfo,getUser } from '@/api/user.js';
+import { mapState, mapMutations } from 'vuex';
+import { saveUrl, interceptor } from '@/utils/loginUtils.js';
+import uniPopup from '@/components/uni-popup/uni-popup.vue';
+export default {
+	components: {
+		uniPopup
+	},
+	data() {
+		return {
+			userInfo:'',
+			phone:'',
+		};
+	},
+	onLoad(option){
+		saveUrl();
+	},
+	onShow() {
+		// 判断是否已经登录
+		if (this.hasLogin) {
+			this.loadBaseData();
+		} else {
+			this.userInfo = '';
+		}
+	},
+	//下拉刷新
+	onPullDownRefresh() {
+		this.loadBaseData();
+		setTimeout(function () {
+			uni.stopPullDownRefresh();
+		}, 1000);
+	},
+	computed: {
+		...mapState('user', ['hasLogin'])
+	},
+	methods: {
+		...mapMutations('user', ['setUserInfo']),
+		// 加载初始数据
+		loadBaseData() {
+			let obj = this;
+			getUserInfo({})
+				.then(({ data }) => {
+					obj.userInfo = data;
+					var tel = obj.userInfo.account;
+					var reg = /^(\d{3})\d{4}(\d{4})$/;
+					obj.phone = tel.replace(reg, "$1****$2");
+					obj.setUserInfo(data);
+				})
+				.catch(e => {
+					console.log(e);
+				});
+		},
+		server(){
+			this.$refs.popup.open();
+		},
+		close(){
+			this.$refs.popup.close();
+		},
+		/**
+		 * 统一跳转接口,拦截未登录路由
+		 * navigator标签现在默认没有转场动画,所以用view
+		 */
+		navTo(url) {
+			uni.navigateTo({
+				url
+			});
+		},
+	}
+};
+</script>
+
+<style lang="scss">
+page {
+	min-height: 100%;
+	background-color: #ffffff;
+	.container {
+		width: 100%;
+		padding-bottom: 50rpx;
+	}
+}
+.user-box{
+	width: 100%;
+	height: 440rpx;
+	padding: 60rpx 35rpx;
+	background-image: url(../../static/img/logo.png);
+	background-size: 100% 100%;
+	color: #FFFFFF;
+	align-items: flex-start;
+	.header{
+		width: 125rpx;
+		height: 125rpx;
+		border-radius: 100%;
+		margin-top: 10%;
+	}
+}
+	.user-info{
+		padding-left: 30rpx;
+		.name{
+			font-weight: 500;
+			font-size: 48rpx;
+		}
+		.phone{
+			font-size: 42rpx;
+			font-weight: 500;
+			color: #FFFFFF;
+			padding-top: 50rpx;
+		}
+		.uuid{
+			font-size: 30rpx;
+			padding-top: 20rpx;
+		}
+		.level-box{
+			margin-top: 25rpx;
+			position: relative;
+			.image{
+				width: 128rpx;
+				height:45rpx;
+			}
+			.level{
+				position: absolute;
+				top: 12rpx;
+				left: 62rpx;
+				font-size: 24rpx;
+				color: #826740;
+				font-weight: bold;
+			}
+		}
+	}
+.list-box{
+	width: 100%;
+	margin-top: -60rpx;
+	background-color: #FFFFFF;
+	border-top-right-radius: 70rpx;
+	border-top-left-radius: 70rpx;
+	padding: 60rpx 66rpx 0rpx 55rpx;
+	.list-title{
+		font-weight: bold;
+		color: #333333;
+		font-size: 36rpx;
+	}
+	.list-cell{
+		padding-top: 40rpx;
+		border-bottom: 1rpx solid #F3F3F3;
+		padding-bottom: 30rpx;
+		.cell-info{
+			image{
+				width: 49rpx;
+				height: 38rpx;
+			}
+			.cell-name{
+				padding-left: 17rpx;
+				color: #666666;
+				font-size: 30rpx;
+				font-weight: 500;
+			}
+		}
+		image{
+			width: 16rpx;
+			height: 25rpx;
+		}
+	}
+}
+.img1{
+	width: 46rpx !important;
+	height: 40rpx !important;
+}
+.img2{
+	width: 40rpx !important;
+	height: 42rpx !important;
+}
+.img3{
+	width: 42rpx !important;
+	height: 42rpx !important;
+}
+.img4{
+	width: 42rpx !important;
+	height: 41rpx !important;
+}
+.img5{
+	width: 44rpx !important;
+	height: 40rpx !important;
+}
+//弹窗
+.popup {
+	width: 640rpx;
+	background-color: #FFFFFF;
+	border-radius: 15rpx;
+	text-align: center;
+	.popup-dox{
+		position: relative;
+		top: -60rpx;
+		.popup-logo {
+			width: 460rpx;
+			height: 132rpx;
+		}
+		.pop-title{
+			font-size: 40rpx;
+			font-weight: bold;
+			color: #333333;
+			padding: 25rpx 0rpx;
+			margin-bottom: 50rpx;
+		}
+		.popup-text{
+			width: 400rpx;
+			height: 400rpx;
+			margin-bottom: 50rpx;
+		}
+		.pop-tip{
+			font-size: 30rpx;
+			font-weight: 500;
+			color: #333333;
+		}
+	}
+}
+
+.close_icon {
+	width: 60rpx;
+	height: 60rpx;
+	margin: 88rpx auto 0;
+	image {
+		width: 100%;
+		height: 100%;
+	}
+}
+</style>

+ 441 - 0
static/css/public.css

@@ -0,0 +1,441 @@
+/*初始化类*/
+@font-face {
+	font-family: 'iconfont';
+	/* project id 1482221 */
+	src: url('https://at.alicdn.com/t/font_1482221_x9emymthrxs.eot');
+	src: url('https://at.alicdn.com/t/font_1482221_x9emymthrxs.eot?#iefix') format('embedded-opentype'),
+		url('https://at.alicdn.com/t/font_1482221_x9emymthrxs.woff2') format('woff2'),
+		url('https://at.alicdn.com/t/font_1482221_x9emymthrxs.woff') format('woff'),
+		url('https://at.alicdn.com/t/font_1482221_x9emymthrxs.ttf') format('truetype'),
+		url('https://at.alicdn.com/t/font_1482221_x9emymthrxs.svg#iconfont') format('svg');
+}
+
+.iconfont {
+	font-family: "iconfont" !important;
+	font-size: 34rpx;
+	font-style: normal;
+	-webkit-font-smoothing: antialiased;
+	-webkit-text-stroke-width: 0rpx;
+	-moz-osx-font-smoothing: grayscale;
+}
+
+.iconedit:before {
+	content: "\e649";
+}
+
+.iconfavorfill:before {
+	content: "\e64b";
+}
+
+.iconfavor:before {
+	content: "\e64c";
+}
+
+.iconlocation:before {
+	content: "\e651";
+}
+
+.iconroundcheckfill:before {
+	content: "\e656";
+}
+
+.iconroundcheck:before {
+	content: "\e657";
+}
+
+.iconunfold:before {
+	content: "\e661";
+}
+
+.iconlikefill:before {
+	content: "\e668";
+}
+
+.iconlike:before {
+	content: "\e669";
+}
+
+.iconshop:before {
+	content: "\e676";
+}
+
+.iconcart:before {
+	content: "\e6af";
+}
+
+.icondelete:before {
+	content: "\e6b4";
+}
+
+.iconhome:before {
+	content: "\e6b8";
+}
+
+.iconcartfill:before {
+	content: "\e6b9";
+}
+
+.iconhomefill:before {
+	content: "\e6bb";
+}
+
+.iconlock:before {
+	content: "\e6c0";
+}
+
+.iconfriendadd:before {
+	content: "\e6ca";
+}
+
+.iconfold:before {
+	content: "\e6de";
+}
+
+.iconapps:before {
+	content: "\e729";
+}
+
+.iconadd:before {
+	content: "\e767";
+}
+
+.iconmove:before {
+	content: "\e768";
+}
+
+.icontriangledownfill:before {
+	content: "\e79b";
+}
+
+.icontriangleupfill:before {
+	content: "\e79c";
+}
+
+.iconshaixuan:before {
+	content: "\e74a";
+}
+
+.iconyanzhengma:before {
+	content: "\e684";
+}
+
+.iconjifen:before {
+	content: "\e60f";
+}
+
+.iconwuliuxinxi:before {
+	content: "\e62b";
+}
+
+.iconmessage:before {
+	content: "\e78a";
+}
+
+.iconsetting:before {
+	content: "\e78e";
+}
+
+.iconaddition:before {
+	content: "\e6e0";
+}
+
+.iconclose:before {
+	content: "\e6e9";
+}
+
+.iconenter:after {
+	content: "\e6f8";
+}
+
+.iconprompt:before {
+	content: "\e71b";
+}
+
+.iconreturn:before {
+	content: "\e720";
+}
+
+.iconsearch:before {
+	content: "\e741";
+}
+
+.iconpengyouquan:before {
+	content: "\e62c";
+}
+
+.iconweixin:before {
+	content: "\e60e";
+}
+
+.iconzhifubao:before {
+	content: "\e673";
+}
+
+.iconyue:before {
+	content: "\e618";
+}
+
+.iconweixin1:before {
+	content: "\e622";
+}
+
+.iconlock1:before {
+	content: "\e64d";
+}
+
+.iconuser:before {
+	content: "\e64e";
+}
+
+.iconchenggongtixianshouyi:before {
+	content: "\e64f";
+}
+
+.iconviptuiguangdingdan:before {
+	content: "\e650";
+}
+
+.icondaifukuan:before {
+	content: "\e652";
+}
+
+.icondaijiesuanshouyi:before {
+	content: "\e653";
+}
+
+.icondaidakuanshouyi:before {
+	content: "\e654";
+}
+
+.icondaifahuo:before {
+	content: "\e655";
+}
+
+.icondaishouhuoshouyi:before {
+	content: "\e658";
+}
+
+.icondaishouhuo:before {
+	content: "\e659";
+}
+
+.iconwuxiaoshouyi:before {
+	content: "\e65a";
+}
+
+.icontixianmingxi:before {
+	content: "\e65b";
+}
+
+.iconshouyi:before {
+	content: "\e65c";
+}
+
+.iconkouchutixianshouxufei:before {
+	content: "\e65d";
+}
+
+.iconyishenqingshouyi:before {
+	content: "\e65e";
+}
+
+.icontuihuanhuo:before {
+	content: "\e65f";
+}
+
+
+/*水平线*/
+.hr {
+	width: 100%;
+	position: relative;
+	border-bottom: 1px solid #dddddd;
+	/* height: 0.5rpx; */
+}
+
+/* 一行显示 */
+.clamp {
+	overflow: hidden;
+	text-overflow: ellipsis;
+	white-space: nowrap;
+	display: block;
+}
+/* 二行显示 */
+.ellipsis{
+	overflow:hidden; 
+	text-overflow:ellipsis;
+	display:-webkit-box; 
+	-webkit-box-orient:vertical;
+	-webkit-line-clamp:2;
+}
+.common-hover {
+	background: #f5f5f5;
+}
+
+/* 角标 */
+.corner{
+	background-color:#e51c23;
+	position: absolute;
+	right: -18rpx;
+	top: -18rpx;
+	color:#FFFFFF;
+	text-align: center;
+	border-radius: 999px;
+	font-size: 24rpx !important;
+	min-width: 35rpx;
+	min-height: 35rpx;
+	display: flex;
+	align-items: center;
+	justify-content: center;
+	line-height: 1;
+}
+/*文字对齐*/
+.text-left {
+	text-align: left !important;
+}
+
+.text-center {
+	text-align: center !important;
+}
+
+.text-justify {
+	text-align: justify !important;
+}
+
+.text-right {
+	text-align: right !important;
+}
+
+.text-default {
+	color: #212121 !important;
+}
+
+.text-white {
+	color: #ffffff !important;
+}
+
+.text-primary {
+	color: #00bcd4 !important;
+}
+
+.text-success {
+	color: #009688 !important;
+}
+
+
+.text-warning {
+	color: #ffc107 !important;
+}
+
+.text-danger {
+	color: #e51c23 !important;
+}
+
+.text-pink {
+	color: #e91e63 !important;
+}
+
+.text-purple {
+	color: #673ab7 !important;
+}
+
+.text-indigo {
+	color: #3f51b5 !important;
+}
+
+.text-gray {
+	color: #999999 !important;
+}
+
+.bg-default {
+	background-color: #f5f5f5 !important;
+}
+
+.bg-primary {
+	background-color: #00bcd4 !important;
+}
+
+.bg-success {
+	background-color: #009688 !important;
+}
+
+.bg-info {
+	background-color: #03a9f4 !important;
+}
+
+.bg-warning {
+	background-color: #FFB238 !important;
+}
+
+.bg-danger {
+	background-color: #DC4D46 !important;
+}
+
+.bg-pink {
+	background-color: #e91e63 !important;
+}
+
+.bg-purple {
+	background-color: #673ab7 !important;
+}
+
+.bg-indigo {
+	background-color: #3f51b5 !important;
+}
+
+.bg-white {
+	background-color: white !important;
+}
+
+.bg-gray {
+	background-color: #e3e3e3 !important;
+}
+
+/* 边框 */
+.border-radius-15 {
+	border-radius: 15rpx;
+}
+
+.border-radius-10 {
+	border-radius: 10rpx;
+}
+
+.border-radius-all {
+	border-radius: 1000rpx;
+}
+
+/* 底部边线 */
+.borde-b {
+	border-bottom: 1px solid #dddddd;
+}
+
+/* 弹性盒子 */
+.flex {
+	display: flex;
+	align-items: center;
+	justify-content: space-between;
+}
+/* 弹性盒子 */
+.flex_item {
+	display: flex;
+	align-items: center;
+	/* justify-content: space-between; */
+}
+.items-left {
+	justify-content: flex-start;
+}
+
+.items-right {
+	justify-content: flex-end;
+}
+
+.flex-shrink-false {
+	flex-shrink: 0;
+}
+
+.flex-grow-true {
+	flex-grow: 1;
+}
+
+.position-relative {
+	position: relative;
+}

BIN
static/img/add.png


BIN
static/img/after.png


BIN
static/img/befor.png


BIN
static/img/img01.png


BIN
static/img/img02.png


이 변경점에서 너무 많은 파일들이 변경되어 몇몇 파일들은 표시되지 않았습니다.