Parcourir la source

2023.12.03
- 项目优化和基础搭建

zweiqin il y a 1 an
Parent
commit
df9b0cc4eb

+ 26 - 0
.gitignore

@@ -0,0 +1,26 @@
+.DS_Storep
+.DS_Store
+# Editor directories and files
+.idea
+.vscode
+.hbuilderx
+*.suo
+*.ntvs*
+*.njsproj
+*.sln
+*.hbuilderx
+/unpackage/dist/dev
+/unpackage/dist/static
+/unpackage/dist/build
+/unpackage/dist/build/mp-alipay/
+/unpackage/dist/build/mp-weixin/
+/unpackage/dist/build/app-plus/
+/unpackage/dist/build/.automator
+/unpackage/cache/
+/unpackage/cache/apk
+/unpackage/release
+/unpackage/res
+/unpackage/resources
+/node_modules
+package-lock.json
+

+ 19 - 28
App.vue

@@ -1,33 +1,24 @@
-<style lang="scss">
-	@import "uview-ui/index.scss";
-</style>
 <script>
-	import {
-		request
-	} from '@/common/js/request'
-	export default {
-		onLaunch: function(options) {
-			console.log('App Launch')
-			console.log('options Launch', options)
-			uni.setStorageSync('options', options);
-			if (options.query.id)
-				uni.setStorageSync('id', options.query.id);
-			const logged = uni.getStorageSync('logged');
-			if (!logged) {
-				uni.navigateTo({
-					url: "/pages/login"
-				})
-			}
-		},
-		onShow: function(options) {
-			if (options.query.id)
-				uni.setStorageSync('id', options.query.id);
-		},
-		onHide: function() {
-			console.log('App Hide')
-		},
-		methods: {
+import { USER_INFO } from './constant'
 
+export default {
+	name: 'App',
+	onLaunch(options) {
+		if (!uni.getStorageSync(USER_INFO)) {
+			uni.navigateTo({
+				url: '/pages/login/login'
+			})
 		}
+	},
+	onShow(options) {
+	},
+	onHide() {
+	},
+	methods: {
 	}
+}
 </script>
+
+<style lang="scss">
+	@import "uview-ui/index.scss";
+</style>

+ 38 - 0
api/anotherTFInterface/index.js

@@ -0,0 +1,38 @@
+import { AnotherTFRequest } from '../../utils'
+
+/**
+ * @description 商城相关接口
+ */
+
+// 登录拿 新团蜂的 token
+export const getAnotherTFTokenApi = (data) => AnotherTFRequest('/app/tmpLoginOrRegByPhone', data)
+
+// 判断用户是否是商家
+export const getIsShopByUserApi = (data) => AnotherTFRequest('/shop/getShopByUser', data)
+
+// 查询名片信息
+export const getIdEnterpriseUserApi = (data) => AnotherTFRequest('/dtsEnterpriseUser/getId', data)
+
+// 保存名片信息
+export const addEnterpriseUserSaveApi = (data) => AnotherTFRequest('/dtsEnterpriseUser/save', data, 'POST')
+
+// 修改名片信息
+export const updateByIdEnterpriseUserApi = (data) => AnotherTFRequest('/dtsEnterpriseUser/updateById', data, 'POST')
+
+// 查询用户标签
+export const getUserIdEnterpriseUserLabelApi = (data) => AnotherTFRequest('/dtsEnterpriseUserLabel/getUserId', data)
+
+// 新增用户标签
+export const addEnterpriseUserLabelSaveApi = (data) => AnotherTFRequest('/dtsEnterpriseUserLabel/save', data, 'POST')
+
+// 修改用户标签
+export const updateByIdEnterpriseUserLabelApi = (data) => AnotherTFRequest('/dtsEnterpriseUserLabel/updateById', data, 'POST')
+
+// 删除用户标签
+export const deleteByIdEnterpriseUserLabelApi = (data) => AnotherTFRequest('/dtsEnterpriseUserLabel/deleteById', data, 'POST')
+
+// 点赞标签
+export const updateByLabelEnterpriseUserLikeApi = (data) => AnotherTFRequest('/dtsEnterpriseUserLike/getByLabel', data, 'POST')
+
+// 取消点赞标签
+export const updateByIdCanEnterpriseUserLikeApi = (data) => AnotherTFRequest('/dtsEnterpriseUserLike/likeByIdCan', data, 'POST')

+ 0 - 49
common/js/request.js

@@ -1,49 +0,0 @@
-import {
-	msg
-} from './util'
-
-/**
- * @param {String} cloudFnName
- * @param {String} operation  操作类型(增删改查)
- * @param {Object} data 请求参数
- * @param {Object} ext 附加参数
- */
-export const request = (cloudFnName, operation, data = {}, ext = {}) => {
-	return new Promise((resolve, reject) => {
-		if (ext.showLoading !== false) {
-			uni.showLoading()
-		}
-		uniCloud.callFunction({
-			name: cloudFnName,
-			data: {
-				operation,
-				data
-			}
-		}).then(res => {
-			if (ext.showLoading !== false) {
-				uni.hideLoading()
-			}
-			if(res.result.code!=200){
-				uni.showToast({
-					icon:"none",
-				    title: res.result.msg,
-				    duration: 2000
-				});
-				reject(res.result.msg);
-			}else{
-				console.log("requestResult",res)
-				resolve(res.result.data);
-			}
-		}).catch((err) => {
-			if (ext.showLoading !== false) {
-				uni.hideLoading()
-			}
-			uni.showToast({
-				icon:"none",
-			    title: err.toString().replace("Error:",""),
-			    duration: 2000
-			});
-			reject(err);
-		})
-	})
-}

+ 0 - 57
common/js/util.js

@@ -1,57 +0,0 @@
-let _debounceTimeout = null,
-	_throttleRunning = false
-
-/**
- * 防抖
- * @param {Function} 执行函数
- * @param {Number} delay 延时ms
- */
-export const debounce = (fn, delay=500) => {
-	clearTimeout(_debounceTimeout);
-	_debounceTimeout = setTimeout(() => {
-		fn();
-	}, delay);
-}
-/**
- * 节流
- * @param {Function} 执行函数
- * @param {Number} delay 延时ms
- */
-export const throttle = (fn, delay=500) => {
-	if(_throttleRunning){
-		return;
-	}
-	_throttleRunning = true;
-	fn();
-	setTimeout(() => {
-	    _throttleRunning = false;
-	}, delay);
-}
-/**
- * toast
- */
-export const msg = (title = '', param={}) => {
-	if(!title) return;
-	uni.showToast({
-		title,
-		duration: param.duration || 1500,
-		mask: param.mask || false,
-		icon: param.icon || 'none'
-	});
-}
-/**
- * 检查登录
- * @return {Boolean}
- */
-export const isLogin = (options={}) => {
-	const userInfo = uni.getStorageSync('userInfo');
-	if(userInfo){
-		return true;
-	}
-	if(options.nav !== false){
-		uni.navigateTo({
-			url: '/pages/login'
-		})
-	}
-	return false;
-}

+ 6 - 0
config/index.js

@@ -0,0 +1,6 @@
+// 团蜂H5项目地址
+export const A_TF_MAIN = 'https://www.tuanfengkeji.cn/TFShop_Uni_H5'
+// 新团蜂H5的接口路径
+export const ANOTHER_TF_INTERFACE = 'https://nsappapi.tuanfengkeji.cn'
+// export const ANOTHER_TF_INTERFACE = 'http://192.168.0.91:9107' // 本地
+export const ANOTHER_TF_UPLOAD = 'https://nsappapi.tuanfengkeji.cn/file/upload'

+ 16 - 0
constant/index.js

@@ -0,0 +1,16 @@
+// auth
+export const USER_ID = 'USER_ID'
+export const USER_TOKEN = 'USER_TOKEN'
+export const USER_INFO = 'user_INFO'
+export const T_STORAGE_KEY = 'T_STORAGE_KEY'
+
+export const clearAllCache = () => {
+	[
+		USER_ID,
+		USER_TOKEN,
+		USER_INFO,
+		T_STORAGE_KEY
+	].forEach((item) => {
+		uni.removeStorageSync(item)
+	})
+}

+ 101 - 6
main.js

@@ -1,15 +1,110 @@
 import Vue from 'vue'
 import App from './App'
-import store from './store/index.js';
-import * as util from '@/common/js/util.js'
-Vue.prototype.$util = util
-import uView from "uview-ui";
-Vue.use(uView);
+import store from './store/index.js'
+import uView from 'uview-ui'
+
+Vue.mixin({
+	data() {
+		return {
+			common: {
+				seamingImgUrl(url) {
+					if (!url) return ''
+					return url.startsWith('https://') ? url : 'https://www.tuanfengkeji.cn:9527/dts-admin-api/admin/storage/fetch/' + url
+				}
+			}
+		}
+	},
+	methods: {
+		setData(obj) {
+			const that = this
+			let keys = []
+			let val, data
+			Object.keys(obj).forEach(function (key) {
+				keys = key.split('.')
+				val = obj[key]
+				data = that.$data
+				keys.forEach(function (key2, index) {
+					if (index + 1 == keys.length) {
+						that.$set(data, key2, val)
+					} else if (!data[key2]) {
+						that.$set(data, key2, {})
+					}
+					data = data[key2]
+				})
+			})
+		},
+		$showToast(text, icon) {
+			uni.showToast({
+				title: text,
+				duration: 2000,
+				icon: icon || 'none'
+			})
+		},
+		go(url, param) {
+			if (!url) return
+			if (param) url = `${url}?detail=${encodeURIComponent(JSON.stringify(param)?.replace(/%/g, '%25'))}`
+			uni.navigateTo({
+				url
+			})
+		},
+		$getJumpParam(loadParam) {
+			if (typeof loadParam === 'object' && loadParam?.detail) return JSON.parse(decodeURIComponent(loadParam.detail))
+			return {}
+		},
+
+		$copy(text, title = '复制成功') {
+			uni.setClipboardData({
+				data: text,
+				success: () => {
+					uni.showToast({
+						title
+					})
+				}
+			})
+		},
+
+		$redirectTo(url) {
+			if (!url) return
+			uni.redirectTo({ url })
+		},
+
+		$switchTab(url) {
+			if (!url) return
+			uni.switchTab({ url })
+		},
+
+		getSize(selecter) {
+			const _this = this
+			return new Promise((resolve, reject) => {
+				const query = uni.createSelectorQuery().in(_this)
+				query
+					.select(selecter)
+					.boundingClientRect((data) => {
+						resolve(data)
+					})
+					.exec()
+			})
+		},
+
+		empty() {
+			uni.showToast({
+				title: '功能升级中...',
+				icon: 'none'
+			})
+		},
+
+		isLogin() {
+			return !!this.$store.state.userId
+		}
+	}
+})
+
+Vue.use(uView)
 Vue.config.productionTip = false
 
 App.mpType = 'app'
 const app = new Vue({
-    ...App,
+	...App,
 	store
 })
 app.$mount()

+ 4 - 4
manifest.json

@@ -1,5 +1,5 @@
 {
-    "name" : "基于云开发的微信小程序电子名片-CxCloud",
+    "name" : "card-wx-user",
     "appid" : "__UNI__2AD76E7",
     "description" : "电子名片",
     "versionName" : "1.0.0",
@@ -62,7 +62,7 @@
                 "oauth" : {
                     "apple" : {},
                     "weixin" : {
-                        "appid" : "wxffdd8fa6ec4ef2a0",
+                        "appid" : "wx984383bfd5405df1",
                         "appsecret" : "",
                         "UniversalLinks" : ""
                     },
@@ -71,7 +71,7 @@
                 "ad" : {},
                 "share" : {
                     "weixin" : {
-                        "appid" : "wxffdd8fa6ec4ef2a0",
+                        "appid" : "wx984383bfd5405df1",
                         "UniversalLinks" : ""
                     }
                 },
@@ -86,7 +86,7 @@
     },
     "quickapp" : {},
     "mp-weixin" : {
-        "appid" : "",
+        "appid" : "wx984383bfd5405df1",
         "setting" : {
             "urlCheck" : false,
             "es6" : false,

+ 9 - 1
package-lock.json

@@ -1,5 +1,13 @@
 {
     "name": "基于云开发的电子名片-CxCloud",
     "version": "1.0.1",
-    "lockfileVersion": 1
+    "lockfileVersion": 1,
+    "requires": true,
+    "dependencies": {
+        "uview-ui": {
+            "version": "2.0.10",
+            "resolved": "https://registry.npmjs.org/uview-ui/-/uview-ui-2.0.10.tgz",
+            "integrity": "sha512-O6gonHabyjBqZrTNS9ejAyUrcdSoXJeVcGHFflG4DsDi2Pahrh+ydoB/lDq2tMIvt2W2veMyShXVMnmruEWkrA=="
+        }
+    }
 }

+ 12 - 9
pages.json

@@ -2,27 +2,30 @@
 	"easycom": {
 		"^u-(.*)": "uview-ui/components/u-$1/u-$1.vue"
 	},
-	"pages": [{
-			"path": "pages/index",
+	"pages": [
+		{
+			"path": "pages/index/index",
 			"style": {
-				"navigationBarTitleText": "畅享云名片",
+				"navigationBarTitleText": "团蜂名片",
 				"navigationStyle": "default"
 			}
-		},{
-			"path": "pages/edit",
+		},
+		{
+			"path": "pages/edit/edit",
 			"style": {
 				"navigationBarTitleText": "编辑名片",
 				"navigationStyle": "default"
 			}
-		}, {
-			"path": "pages/login",
+		},
+		{
+			"path": "pages/login/login",
 			"style": {
 				"navigationBarTitleText": "登录",
 				"navigationStyle": "default"
 			}
 		},
 		{
-			"path": "pages/agree",
+			"path": "pages/agree/agree",
 			"style": {
 				"navigationBarTitleText": "用户协议",
 				"navigationStyle": "default"
@@ -36,4 +39,4 @@
 		"backgroundColor": "#F8F8F8",
 		"enablePullDownRefresh": false
 	}
-}
+}

+ 22 - 17
pages/agree.vue → pages/agree/agree.vue

@@ -1,9 +1,9 @@
 <template>
 	<view>
 		<view class="weui-desktop-panel_inner">
-			<h3 class="panel__title-center">畅享云名片小程序隐私保护指引</h3>
+			<h3 class="panel__title-center">团蜂名片小程序隐私保护指引</h3>
 			<view class="group-infos">
-				<text>本指引是畅享云名片小程序开发者 "常熟市畅享计算机信息技术有限公司"(以下简称“开发者”)为处理你的个人信息而制定。</text>
+				<text>本指引是团蜂名片小程序开发者 "广东团蜂科技有限公司"(以下简称“开发者”)为处理你的个人信息而制定。</text>
 			</view>
 			<view class="group-infos">
 				<view class="group-infos__hd">
@@ -23,7 +23,8 @@
 				</view>
 				<text class="group-infos_order">
 					关于收集你选中的照片或视频信息、收集你选中的照片或视频信息、收集你选中的文件、收集你选中的文件,你可以通过以下路径:小程序主页右上角“...” — “设置” —
-					“小程序已获取的信息” — 点击特定信息 — 点击“通知开发者删除”,开发者承诺收到通知后将删除信息。</text>
+					“小程序已获取的信息” — 点击特定信息 — 点击“通知开发者删除”,开发者承诺收到通知后将删除信息。
+				</text>
 				<text class="group-infos_order">关于你的个人信息,你可以通过以下方式与开发者联系,行使查阅、复制、更正、删除等法定权利。</text>
 			</view>
 			<view class="group-infos">
@@ -43,14 +44,17 @@
 				<view class="group-infos__hd">
 					<text class="group-infos__title">信息对外提供</text>
 				</view>
-				<text class="group-infos_order">开发者承诺,不会主动共享或转让你的信息至任何第三方,如存在确需共享或转让时,开发者应当直接征得或确认第三方征得你的单独同意。
+				<text class="group-infos_order">
+					开发者承诺,不会主动共享或转让你的信息至任何第三方,如存在确需共享或转让时,开发者应当直接征得或确认第三方征得你的单独同意。
 				</text>
 				<text class="group-infos_order">
-					开发者承诺,不会对外公开披露你的信息,如必须公开披露时,开发者应当向你告知公开披露的目的、披露信息的类型及可能涉及的信息,并征得你的单独同意。</text>
+					开发者承诺,不会对外公开披露你的信息,如必须公开披露时,开发者应当向你告知公开披露的目的、披露信息的类型及可能涉及的信息,并征得你的单独同意。
+				</text>
 			</view>
 			<view class="group-infos">
-					<text class="group-infos_order">
-						你认为开发者未遵守上述约定,或有其他的投诉建议、或未成年人个人信息保护相关问题,可通过以下方式与开发者联系;或者向微信进行投诉。</text>
+				<text class="group-infos_order">
+					你认为开发者未遵守上述约定,或有其他的投诉建议、或未成年人个人信息保护相关问题,可通过以下方式与开发者联系;或者向微信进行投诉。
+				</text>
 			</view>
 
 		</view>
@@ -58,21 +62,22 @@
 </template>
 
 <script>
-	export default {
-		name: "",
-		data() {
-			return {
+export default {
+	name: '',
+	data() {
+		return {
 
-			}
-		},
-		onLoad() {
+		}
+	},
+	onLoad() {
 
-		},
-		methods: {
+	},
+	methods: {
 
-		}
 	}
+}
 </script>
+
 <style scoped>
 	page {
 		background: #fff;

+ 0 - 207
pages/edit.vue

@@ -1,207 +0,0 @@
-<template>
-	<view>
-		<view class="wrap">
-			<u--form labelPosition="left" :model="cardObj" :rules="rules" ref="form1" labelWidth="80">
-				<u-form-item label="姓名" prop="cardObj.name" borderBottom>
-					<u--input v-model="cardObj.name" border="none"></u--input>
-				</u-form-item>
-				<u-form-item label="电话" prop="cardObj.phone" borderBottom>
-					<u--input v-model="cardObj.phone" border="none"></u--input>
-				</u-form-item>
-				<u-form-item label="公司" prop="company" borderBottom>
-					<u--input v-model="cardObj.company" border="none"></u--input>
-				</u-form-item>
-				<u-form-item label="地址" prop="address" borderBottom>
-					<u--input v-model="cardObj.address" border="none"></u--input>
-				</u-form-item>
-				<u-form-item label="职位" prop="job" borderBottom>
-					<u--input v-model="cardObj.job" border="none"></u--input>
-				</u-form-item>
-				<u-form-item label="微信" prop="wechat" borderBottom>
-					<u--input v-model="cardObj.wechat" border="none"></u--input>
-				</u-form-item>
-				<u-form-item label="QQ" prop="wechat" borderBottom>
-					<u--input v-model="cardObj.qq" border="none"></u--input>
-				</u-form-item>
-				<u-form-item label="邮箱" prop="email" borderBottom>
-					<u--input v-model="cardObj.email" border="none"></u--input>
-				</u-form-item>
-				<u-form-item label="业务介绍" prop="intro" borderBottom>
-					<u--textarea v-model="cardObj.intro" border="none"></u--textarea>
-				</u-form-item>
-				<u-form-item label="头像" prop="intro" borderBottom>
-					<u-upload :fileList="fileList1" @afterRead="afterRead" name="5" :maxCount="1" @delete="deletePic"
-						:previewFullImage="true">
-					</u-upload>
-				</u-form-item>
-			</u--form>
-			<view class="wrap">
-				<view style="float:left;width: 40px;">
-					<u-checkbox-group  v-model="checked" change="changeClick()">
-					<u-checkbox shape="circle" ></u-checkbox>
-					</u-checkbox-group>
-				</view>
-				<text style="float:left;color:#04498c" @click="goAgree()">同意用户服务协议&隐私政策</text>
-			</view>
-		</view>
-		<view class="bottom-block"></view>
-		<view class="bottombtn" type="primary" @click="onSave">立即保存</view>
-	</view>
-</template>
-
-<script>
-	import {
-		request
-	} from '@/common/js/request'
-	export default {
-		name: "Edit",
-		components: {},
-		data() {
-			return {
-				checked: false,
-				cardObj: {},
-				fileList1: [],
-				isAdd: true,
-				rules: {
-					'cardObj.name': {
-						type: 'string',
-						required: true,
-						message: '必填',
-						trigger: ['blur', 'change']
-					},
-					'cardObj.phone': {
-						type: 'string',
-						required: true,
-						message: '必填',
-						trigger: ['blur', 'change']
-					},
-				},
-			};
-		},
-		mounted() {},
-		async onLoad(options) {
-			const logged = uni.getStorageSync('logged');
-			if (logged) {
-				var user = uni.getStorageSync('userInfo');
-				const res = await request('uni-card', 'getMyCard', {
-					uid: user.id
-				}, {
-					showloading: true
-				});
-				if (res.uid == null)
-					this.isAdd = true;
-				else {
-					if (res.uid != user.id) {
-						uni.navigateTo({
-							url: "/pages/index"
-						})
-					}
-					this.cardObj = res;
-					this.isAdd = false;
-					this.fileList1.push({
-						url: res.head_img
-					})
-				}
-			}
-		},
-		methods: {
-			goAgree() {
-				uni.navigateTo({
-					url: "/pages/agree"
-				})
-			},
-			changeClick(){
-				console.log("this.checked",this.checked)
-			},
-			async onSave() {
-				if (!this.checked) {
-					this.$util.msg('请点击同意用户服务协议&隐私政策');
-					return;
-				}
-				if (!this.cardObj.name) {
-					this.$util.msg('请填写姓名');
-					return;
-				}
-				if (!this.cardObj.phone) {
-					this.$util.msg('请填写电话');
-					return;
-				}
-				var user = uni.getStorageSync('userInfo');
-				this.cardObj.uid = user.id;
-				const res = await request('uni-card', 'saveCard', this.cardObj, {
-					showloading: true
-				});
-				console.log("res", res)
-				this.$util.msg('保存成功');
-				uni.setStorageSync('id', res.id);
-				uni.navigateTo({
-					url: "/pages/index"
-				})
-			},
-			deletePic(event) {
-				this.fileList1 = [];
-				this.cardObj.head_img = "";
-			},
-			async afterRead(event) {
-				console.log("event", event)
-				const result = await this.uploadFilePromise(event.file.url)
-			},
-			uploadFilePromise(url) {
-				return new Promise((resolve, reject) => {
-					var $chars = 'ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz2345678';
-					var maxLen = $chars.length;
-					var noncestr = '';
-					for (var i = 0; i < 32; i++) {
-						noncestr += $chars.charAt(Math.floor(Math.random() * maxLen));
-					}
-					var that = this;
-					uniCloud.uploadFile({
-						filePath: url,
-						cloudPath: noncestr + ".jpg",
-						onUploadProgress: function(progressEvent) {
-							console.log("上传进度", progressEvent);
-							var percentCompleted = Math.round(
-								(progressEvent.loaded * 100) / progressEvent.total
-							);
-						},
-						success(e) {
-							console.log("uploadFile", e)
-							that.fileList1.push({
-								url: e.fileID
-							})
-							that.cardObj.head_img = e.fileID
-						},
-						fail() {},
-						complete() {}
-					});
-				})
-			},
-		}
-	};
-</script>
-
-<style>
-	/deep/.u-scroll-bar {
-		background: red !important;
-	}
-
-	.wrap {
-		padding: 20px;
-	}
-
-	.bottombtn {
-		position: fixed;
-		bottom: 0;
-		width: 100%;
-		height: 60px;
-		background: #007AFF;
-		color: #fff;
-		line-height: 60px;
-		text-align: center;
-	}
-	.bottom-block {
-		display: block;
-		width: 100%;
-		height: 80px;
-	}
-</style>

+ 206 - 0
pages/edit/edit.vue

@@ -0,0 +1,206 @@
+<template>
+	<view>
+		<view class="wrap">
+			<u--form ref="form1" label-position="left" :model="cardObj" :rules="rules" label-width="80">
+				<u-form-item label="姓名" prop="cardObj.name" border-bottom>
+					<u--input v-model="cardObj.name" border="none"></u--input>
+				</u-form-item>
+				<u-form-item label="电话" prop="cardObj.phone" border-bottom>
+					<u--input v-model="cardObj.phone" border="none"></u--input>
+				</u-form-item>
+				<u-form-item label="公司" prop="company" border-bottom>
+					<u--input v-model="cardObj.company" border="none"></u--input>
+				</u-form-item>
+				<u-form-item label="地址" prop="address" border-bottom>
+					<u--input v-model="cardObj.address" border="none"></u--input>
+				</u-form-item>
+				<u-form-item label="职位" prop="job" border-bottom>
+					<u--input v-model="cardObj.job" border="none"></u--input>
+				</u-form-item>
+				<u-form-item label="微信" prop="wechat" border-bottom>
+					<u--input v-model="cardObj.wechat" border="none"></u--input>
+				</u-form-item>
+				<u-form-item label="QQ" prop="wechat" border-bottom>
+					<u--input v-model="cardObj.qq" border="none"></u--input>
+				</u-form-item>
+				<u-form-item label="邮箱" prop="email" border-bottom>
+					<u--input v-model="cardObj.email" border="none"></u--input>
+				</u-form-item>
+				<u-form-item label="业务介绍" prop="intro" border-bottom>
+					<u--textarea v-model="cardObj.intro" border="none"></u--textarea>
+				</u-form-item>
+				<u-form-item label="头像" prop="intro" border-bottom>
+					<u-upload
+						:file-list="fileList1" name="5" :max-count="1" :preview-full-image="true"
+						@afterRead="afterRead"
+						@delete="deletePic"
+					>
+					</u-upload>
+				</u-form-item>
+			</u--form>
+			<view class="wrap">
+				<view style="float:left;width: 40px;">
+					<u-checkbox-group v-model="checked" change="changeClick()">
+						<u-checkbox shape="circle"></u-checkbox>
+					</u-checkbox-group>
+				</view>
+				<text style="float:left;color:#04498c" @click="goAgree()">同意用户服务协议&隐私政策</text>
+			</view>
+		</view>
+		<view class="bottom-block"></view>
+		<view class="bottombtn" type="primary" @click="onSave">立即保存</view>
+	</view>
+</template>
+
+<script>
+import {
+	request
+} from '@/utils/request'
+import { USER_INFO } from '../../constant'
+export default {
+	name: 'Edit',
+	components: {},
+	data() {
+		return {
+			checked: false,
+			cardObj: {},
+			fileList1: [],
+			isAdd: true,
+			rules: {
+				'cardObj.name': {
+					type: 'string',
+					required: true,
+					message: '必填',
+					trigger: ['blur', 'change']
+				},
+				'cardObj.phone': {
+					type: 'string',
+					required: true,
+					message: '必填',
+					trigger: ['blur', 'change']
+				}
+			}
+		}
+	},
+	mounted() { },
+	async onLoad(options) {
+		if (uni.getStorageSync(USER_INFO)) {
+			var user = uni.getStorageSync(USER_INFO)
+			const res = await request('uni-card', 'getMyCard', {
+				uid: user.id
+			}, {
+				showloading: true
+			})
+			if (res.uid == null) { this.isAdd = true } else {
+				if (res.uid != user.id) {
+					uni.navigateTo({
+						url: '/pages/index'
+					})
+				}
+				this.cardObj = res
+				this.isAdd = false
+				this.fileList1.push({
+					url: res.head_img
+				})
+			}
+		}
+	},
+	methods: {
+		goAgree() {
+			uni.navigateTo({
+				url: '/pages/agree'
+			})
+		},
+		changeClick() {
+			console.log('this.checked', this.checked)
+		},
+		async onSave() {
+			if (!this.checked) {
+				this.$showToast('请点击同意用户服务协议&隐私政策')
+				return
+			}
+			if (!this.cardObj.name) {
+				this.$showToast('请填写姓名')
+				return
+			}
+			if (!this.cardObj.phone) {
+				this.$showToast('请填写电话')
+				return
+			}
+			var user = uni.getStorageSync(USER_INFO)
+			this.cardObj.uid = user.id
+			const res = await request('uni-card', 'saveCard', this.cardObj, {
+				showloading: true
+			})
+			console.log('res', res)
+			this.$showToast('保存成功')
+			uni.navigateTo({
+				url: '/pages/index'
+			})
+		},
+		deletePic(event) {
+			this.fileList1 = []
+			this.cardObj.head_img = ''
+		},
+		async afterRead(event) {
+			console.log('event', event)
+			const result = await this.uploadFilePromise(event.file.url)
+		},
+		uploadFilePromise(url) {
+			return new Promise((resolve, reject) => {
+				var $chars = 'ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz2345678'
+				var maxLen = $chars.length
+				var noncestr = ''
+				for (var i = 0; i < 32; i++) {
+					noncestr += $chars.charAt(Math.floor(Math.random() * maxLen))
+				}
+				var that = this
+				uniCloud.uploadFile({
+					filePath: url,
+					cloudPath: noncestr + '.jpg',
+					onUploadProgress(progressEvent) {
+						console.log('上传进度', progressEvent)
+						var percentCompleted = Math.round((progressEvent.loaded * 100) / progressEvent.total)
+					},
+					success(e) {
+						console.log('uploadFile', e)
+						that.fileList1.push({
+							url: e.fileID
+						})
+						that.cardObj.head_img = e.fileID
+					},
+					fail() { },
+					complete() { }
+				})
+			})
+		}
+	}
+}
+</script>
+
+<style>
+/deep/.u-scroll-bar {
+	background: red !important;
+}
+
+.wrap {
+	padding: 20px;
+}
+
+.bottombtn {
+	position: fixed;
+	bottom: 0;
+	width: 100%;
+	height: 60px;
+	background: #007AFF;
+	color: #fff;
+	line-height: 60px;
+	text-align: center;
+}
+
+.bottom-block {
+	display: block;
+	width: 100%;
+	height: 80px;
+}
+</style>

+ 0 - 603
pages/index.vue

@@ -1,603 +0,0 @@
-<template>
-	<view class="content">
-		<view class="content-box">
-			<view class="top-main-box">
-				<view class="zzbg">
-					<image class="mpimg" src="/static/images/mpbg1.jpg" mode="widthFix"></image>
-				</view>
-				<view class="topmain">
-					<view class="leftimg">
-						<u-avatar size="60" :src="cardObj.head_img" shape="square"></u-avatar>
-					</view>
-					<view class="rightcont">
-						<view class="name">{{cardObj.name}}</view>
-						<view class="tip">{{cardObj.job}}</view>
-						<view class="tipa">{{cardObj.company}}</view>
-					</view>
-				</view>
-				<view class="btnmain">
-					<u-icon name="map-fill"></u-icon><text>{{cardObj.address}}</text>
-				</view>
-			</view>
-
-
-
-			<view class="top-mainb">
-				<view class="conta">
-					<view class="cont" v-if="cardObj.phone" @click="onPhone()">
-						<view class="box">
-							<u-icon name="phone-fill" color="#007AFF" size="40"> </u-icon>
-							<view class="right">
-								<text class="tit">拨打电话</text>
-								<text>{{cardObj.phone}}</text>
-							</view>
-						</view>
-					</view>
-					<view class="cont" v-if="cardObj.wechat" @click="onCopy(cardObj.wechat)">
-						<view class="box">
-							<u-icon name="weixin-fill" color="#007AFF" size="40"> </u-icon>
-							<view class="right">
-								<text class="tit">加微信</text>
-								<text>{{cardObj.wechat}}</text>
-							</view>
-						</view>
-					</view>
-					<view class="cont" v-if="cardObj.qq" @click="onCopy(cardObj.qq)">
-						<view class="box">
-							<u-icon name="qq-fill" color="#007AFF" size="40"> </u-icon>
-							<view class="right">
-								<text class="tit">QQ</text>
-								<text>{{cardObj.qq}}</text>
-							</view>
-						</view>
-					</view>
-					<view class="cont" v-if="cardObj.email" @click="onCopy(cardObj.email)">
-						<view class="box">
-							<u-icon name="email-fill" color="#007AFF" size="40"> </u-icon>
-							<view class="right">
-								<text class="tit">邮箱</text>
-								<text>{{cardObj.email}}</text>
-							</view>
-						</view>
-					</view>
-				</view>
-			</view>
-			<view class="top-maina">
-				<button class="left" @click="onAdd()">
-					同步到通讯录
-				</button>
-				<button class="right" open-type="share">
-					分享名片
-				</button>
-			</view>
-			<view class="top-mainc">
-				<view class="left">
-					<u-avatar-group :urls="headerList" size="35" gap="0.4" :default-url="headerImg" randomBgColor>
-					</u-avatar-group>
-					<text>{{visitorCount}}人浏览</text>
-				</view>
-			</view>
-			<view class="top-main-tit">
-				<u-icon name="file-text-fill" color="#007AFF" size="40"> </u-icon>
-				<text>业务介绍</text>
-			</view>
-			<view class="top-maind">
-				<view class="topmain">
-					<view class="leftimg">
-						<u-avatar size="60" :src="cardObj.head_img" shape="square"></u-avatar>
-					</view>
-					<view class="rightcont">
-						<view class="name" v-if="!cardObj.intro">Hi~欢迎访问我的名片,了解更多内容请直接咨询我。</view>
-						<view class="name" v-if="cardObj.intro">{{cardObj.intro}}</view>
-					</view>
-				</view>
-			</view>
-
-		</view>
-		<view class="bottom-block"></view>
-		<view class="bottombtn" type="primary" @click="gotoEdit">编辑我的名片</view>
-	</view>
-</template>
-
-<script>
-	import {
-		request
-	} from '@/common/js/request'
-	export default {
-		data() {
-			return {
-				id: "",
-				headerImg: "/static/images/userimg.png",
-				cardObj: {},
-				visitorList: [],
-				visitorCount: 0,
-				headerList: []
-			}
-		},
-		async onShow(options) {
-			console.log("onLoad options", options);
-			const logged = uni.getStorageSync('logged');
-			if (logged) {
-				var id = uni.getStorageSync('id');
-				var user = uni.getStorageSync('userInfo');
-				if (id != null && id != "") {
-					this.id = id;
-					const card = await request('uni-card', 'getCard', {
-						id: id,
-						uid: user.id
-					}, {
-						showloading: true
-					});
-					if (card._id == "") {
-						this.getDefault();
-					} else {
-						const visitorList = await request('uni-card', 'getVisitorList', {
-							card_id: id,
-							skip: 0,
-							limit: 8
-						}, {
-							showloading: true
-						});
-						this.cardObj = card;
-						this.visitorCount = visitorList.total;
-						visitorList.items.forEach((arr, index) => {
-							if (arr.head_img)
-								this.headerList.push(arr.head_img)
-							else
-								this.headerList.push("/static/images/userimg.png")
-						})
-					}
-				} else {
-					const mycard = await request('uni-card', 'getMyCard', {
-						uid: user.id
-					}, {
-						showloading: true
-					});
-					if (mycard._id == "") {
-						this.getDefault();
-					} else {
-						const myVisitorList = await request('uni-card', 'getMyVisitorList', {
-							uid: user.id,
-							skip: 0,
-							limit: 8
-						}, {
-							showloading: true
-						});
-						this.cardObj = mycard;
-						this.visitorCount = myVisitorList.total;
-						myVisitorList.items.forEach((arr, index) => {
-							if (arr.head_img)
-								this.headerList.push(arr.head_img)
-							else
-								this.headerList.push("/static/images/userimg.png")
-						})
-					}
-				}
-			}
-		},
-		onShareAppMessage(res) {
-			if (this.id == "" || this.id == null) {
-				this.id = "61b30b8091a7500001dea375"
-			}
-			return {
-				title: '您好,这是我的名片,望惠存',
-				path: '/pages/index?id=' + this.id
-			}
-		},
-		methods: {
-			async getDefault() {
-				const card = await request('uni-card', 'getCard', {
-					id: "61b30b8091a7500001dea375",
-					uid: "61b30b4e7964120001e32f41"
-				}, {
-					showloading: true
-				});
-				if (card._id == "") {
-					this.gotoEdit();
-				}
-				const visitorList = await request('uni-card', 'getVisitorList', {
-					card_id: "61b30b8091a7500001dea375",
-					skip: 0,
-					limit: 8
-				}, {
-					showloading: true
-				});
-				this.cardObj = card;
-				this.visitorCount = visitorList.total;
-				visitorList.items.forEach((arr, index) => {
-					if (arr.head_img)
-						this.headerList.push(arr.head_img)
-					else
-						this.headerList.push("/static/images/userimg.png")
-				})
-			},
-			onAdd() {
-				uni.addPhoneContact({
-					organization: this.cardObj.company,
-					firstName: this.cardObj.name,
-					title: this.cardObj.job,
-					email: this.cardObj.email,
-					mobilePhoneNumber: this.cardObj.phone,
-					weChatNumber: this.cardObj.wechat,
-					remark: this.cardObj.address,
-					success: function() {
-						console.log('success');
-					},
-					fail: function() {
-						console.log('fail');
-					}
-				});
-			},
-			onPhone() {
-				uni.makePhoneCall({
-					phoneNumber: this.cardObj.phone,
-					success: (res) => {
-						console.log('调用成功!')
-					},
-					fail: (res) => {
-						console.log('调用失败!')
-					}
-				})
-			},
-			onCopy(data) {
-				uni.setClipboardData({
-					data: data, //要被复制的内容
-					success: function() {
-						//重点~做笔记
-						//在success中加入uni.hideToast()可以解决
-						uni.showToast({
-							title: '复制成功',
-							duration: 2000,
-							icon: 'none'
-						});
-						//以下就可自定义操作了~
-					},
-					fail: function(err) {
-						uni.showToast({
-							title: '复制失败',
-							duration: 2000,
-							icon: 'none'
-						});
-					}
-				});
-			},
-			gotoEdit() {
-				uni.navigateTo({
-					url: "/pages/edit"
-				})
-			}
-		}
-	}
-</script>
-
-<style>
-	page {
-		background: #f7f7f7;
-	}
-
-	.content {
-		display: flex;
-		flex-direction: column;
-		align-items: center;
-		justify-content: center;
-	}
-
-	.content-box {
-		width: 100%;
-		box-sizing: border-box;
-		padding: 0 5%;
-	}
-
-	.content-box .top-main-box {
-		width: 100%;
-		box-sizing: border-box;
-		border-radius: 15rpx;
-		height: 52vw;
-		overflow: hidden;
-		position: relative;
-		box-shadow: 0px 0px 10px #cccccc;
-	}
-
-	.content-box .top-main-box .zzbg {
-		width: 100%;
-		position: absolute;
-		top: 0;
-		left: 0;
-		background: rgba(139, 139, 139, 0.5);
-		z-index: 1;
-	}
-
-	.content-box .top-main-box .mpimg {
-		width: 100%;
-	}
-
-	.content-box .top-main-box .topmain {
-		width: 100%;
-		box-sizing: border-box;
-		padding: 40rpx 5%;
-		display: flex;
-		align-items: flex-start;
-		position: relative;
-		z-index: 4;
-	}
-
-	.content-box .top-main-box .topmain .leftimg {
-		width: 150rpx;
-		height: 150rpx;
-		border-radius: 15rpx;
-		overflow: hidden;
-	}
-
-	.content-box .top-main-box .topmain .leftimg .tximg {
-		width: 100%;
-	}
-
-	.content-box .top-main-box .topmain .rightcont {
-		color: #fff;
-		flex: 1;
-		box-sizing: border-box;
-		padding-left: 25rpx;
-	}
-
-	.content-box .top-main-box .topmain .rightcont .name {
-		font-size: 42rpx;
-		padding-bottom: 10rpx;
-	}
-
-	.content-box .top-main-box .topmain .rightcont .tip,
-	.content-box .top-main-box .topmain .rightcont .tipa {
-		font-size: 34rpx;
-		text-shadow: 1px 1px 1px #000;
-	}
-
-	.content-box .top-main-box .btnmain {
-		width: 100%;
-		position: absolute;
-		left: 0;
-		bottom: 0px;
-		z-index: 5;
-		box-sizing: border-box;
-		padding: 25rpx 5%;
-		background: #fff;
-		display: inline;
-		align-items: center;
-		justify-content: space-between;
-		text-align: left;
-	}
-
-	.content-box .top-main-box .btnmain view {
-		float: left;
-	}
-
-	.content-box .top-main-box .btnmain text {
-		font-size: 24rpx;
-		color: #333333;
-		padding-left: 10rpx;
-		float: left;
-	}
-
-	.content-box .top-maina {
-		width: 100%;
-		box-sizing: border-box;
-		display: flex;
-		align-items: center;
-		justify-content: space-between;
-		margin: 20rpx auto;
-	}
-
-	.content-box .top-maina view {
-		width: 48%;
-		border-radius: 15rpx;
-		text-align: center;
-		padding: 25rpx 0;
-		font-size: 18px;
-	}
-
-	.content-box .top-maina .left {
-		border: 1px solid #007AFF;
-		color: #007AFF;
-		width: 48%;
-	}
-
-	.content-box .top-maina .right {
-		background: #007AFF;
-		border: 1px solid #007AFF;
-		color: #fff;
-		width: 48%;
-	}
-
-	.content-box .top-mainb {
-		width: 100%;
-		overflow: scroll;
-		padding: 15rpx 0;
-		overflow-x: hidden;
-	}
-
-	.content-box .top-mainb .conta {
-		width: 100%;
-		overflow-x: auto;
-		word-break: keep-all;
-		/* 不换行 */
-		white-space: nowrap;
-		/* 不换行 */
-		padding-bottom: 20rpx;
-	}
-
-	.content-box .top-mainb .conta .cont {
-		display: inline-block;
-		margin-right: 20rpx;
-		background: #fff;
-		box-shadow: 0px 0px 8px #cccccc;
-		border-radius: 10rpx;
-		overflow: hidden;
-	}
-
-	.content-box .top-mainb .conta .cont .box {
-		display: flex;
-		align-items: center;
-		justify-content: space-between;
-		box-sizing: border-box;
-		padding: 15rpx 20rpx;
-	}
-
-	.content-box .top-mainb .conta .cont .box image {
-		width: 80rpx;
-		height: 80rpx;
-	}
-
-	.content-box .top-mainb .conta .cont .box .right {
-		flex: 1;
-		box-sizing: border-box;
-		padding-left: 10rpx;
-	}
-
-	.content-box .top-mainb .conta .cont .box .right text {
-		display: block;
-		font-size: 30rpx;
-	}
-
-	.content-box .top-mainb .conta .cont .box .right .tit {
-		font-size: 34rpx;
-	}
-
-	.content-box .top-mainc {
-		width: 100%;
-		box-sizing: border-box;
-		padding: 20rpx 10rpx;
-		display: flex;
-		align-items: center;
-		justify-content: space-between;
-		margin: 10rpx auto;
-		background: #fff;
-	}
-
-	.content-box .top-mainc .left {
-		flex: 1;
-		display: flex;
-		align-items: center;
-	}
-
-	.content-box .top-mainc .left text {
-		font-size: 28rpx;
-		color: #555555;
-	}
-
-	.content-box .top-mainc .left image {
-		width: 60rpx;
-		height: 60rpx;
-		margin-right: 5rpx;
-		border-radius: 10rpx;
-	}
-
-	.content-box .top-mainc .right {
-		display: flex;
-		align-items: center;
-		justify-content: space-between;
-	}
-
-	.content-box .top-mainc .right text {
-		font-size: 28rpx;
-		color: #555555;
-		padding-right: 10rpx;
-	}
-
-	.content-box .top-mainc .right image {
-		width: 40rpx;
-		height: 40rpx;
-	}
-
-	.content-box .top-main-tit {
-		width: 100%;
-		box-sizing: border-box;
-		padding: 20rpx 10rpx;
-		display: flex;
-		align-items: center;
-	}
-
-	.content-box .top-main-tit image {
-		width: 60rpx;
-		height: 60rpx;
-	}
-
-	.content-box .top-main-tit text {
-		color: #333;
-		font-size: 18px;
-		padding-left: 10rpx;
-	}
-
-	.content-box .top-maind {
-		width: 100%;
-		box-sizing: border-box;
-		padding: 40rpx 5%;
-		background: #fff;
-		box-shadow: 0px 0px 8px #cccccc;
-	}
-
-	.content-box .top-maind .topmain {
-		width: 100%;
-		box-sizing: border-box;
-		display: flex;
-		align-items: flex-start;
-	}
-
-	.content-box .top-maind .topmain .leftimg {
-		width: 120rpx;
-		height: 120rpx;
-		border-radius: 15rpx;
-		overflow: hidden;
-	}
-
-	.content-box .top-maind .topmain .leftimg .tximg {
-		width: 100%;
-	}
-
-	.content-box .top-maind .topmain .rightcont {
-		color: #555;
-		flex: 1;
-		box-sizing: border-box;
-		padding-left: 25rpx;
-		line-height: 42rpx;
-		font-size: 28rpx;
-	}
-
-	.content-box .top-maind .toptip {
-		width: 100%;
-	}
-
-	.content-box .top-maind .toptip .box {
-		display: inline-block;
-		margin-top: 25rpx;
-		padding: 10rpx 15rpx;
-		background: #e6e6e6;
-		border-radius: 10rpx;
-		overflow: hidden;
-		margin-right: 20rpx;
-	}
-
-	.content-box .top-maind .toptip .box image {
-		width: 30rpx;
-		height: 30rpx;
-	}
-
-	.content-box .top-maind .toptip .box text {
-		font-size: 28rpx;
-		padding-left: 10rpx;
-	}
-
-	.bottombtn {
-		position: fixed;
-		bottom: 0;
-		width: 100%;
-		height: 60px;
-		background: #007AFF;
-		color: #fff;
-		line-height: 60px;
-		text-align: center;
-	}
-
-	.bottom-block {
-		display: block;
-		width: 100%;
-		height: 80px;
-	}
-</style>

+ 592 - 0
pages/index/index.vue

@@ -0,0 +1,592 @@
+<template>
+	<view class="content">
+		<view class="content-box">
+			<view class="top-main-box">
+				<view class="zzbg">
+					<image class="mpimg" src="/static/images/mpbg1.jpg" mode="widthFix"></image>
+				</view>
+				<view class="topmain">
+					<view class="leftimg">
+						<u-avatar size="60" :src="cardObj.head_img" shape="square"></u-avatar>
+					</view>
+					<view class="rightcont">
+						<view class="name">{{ cardObj.name }}</view>
+						<view class="tip">{{ cardObj.job }}</view>
+						<view class="tipa">{{ cardObj.company }}</view>
+					</view>
+				</view>
+				<view class="btnmain">
+					<u-icon name="map-fill"></u-icon><text>{{ cardObj.address }}</text>
+				</view>
+			</view>
+
+			<view class="top-mainb">
+				<view class="conta">
+					<view v-if="cardObj.phone" class="cont" @click="onPhone()">
+						<view class="box">
+							<u-icon name="phone-fill" color="#007AFF" size="40"> </u-icon>
+							<view class="right">
+								<text class="tit">拨打电话</text>
+								<text>{{ cardObj.phone }}</text>
+							</view>
+						</view>
+					</view>
+					<view v-if="cardObj.wechat" class="cont" @click="onCopy(cardObj.wechat)">
+						<view class="box">
+							<u-icon name="weixin-fill" color="#007AFF" size="40"> </u-icon>
+							<view class="right">
+								<text class="tit">加微信</text>
+								<text>{{ cardObj.wechat }}</text>
+							</view>
+						</view>
+					</view>
+					<view v-if="cardObj.qq" class="cont" @click="onCopy(cardObj.qq)">
+						<view class="box">
+							<u-icon name="qq-fill" color="#007AFF" size="40"> </u-icon>
+							<view class="right">
+								<text class="tit">QQ</text>
+								<text>{{ cardObj.qq }}</text>
+							</view>
+						</view>
+					</view>
+					<view v-if="cardObj.email" class="cont" @click="onCopy(cardObj.email)">
+						<view class="box">
+							<u-icon name="email-fill" color="#007AFF" size="40"> </u-icon>
+							<view class="right">
+								<text class="tit">邮箱</text>
+								<text>{{ cardObj.email }}</text>
+							</view>
+						</view>
+					</view>
+				</view>
+			</view>
+			<view class="top-maina">
+				<button class="left" @click="onAdd()">
+					同步到通讯录
+				</button>
+				<button class="right" open-type="share">
+					分享名片
+				</button>
+			</view>
+			<view class="top-mainc">
+				<view class="left">
+					<u-avatar-group :urls="headerList" size="35" gap="0.4" :default-url="headerImg" random-bg-color>
+					</u-avatar-group>
+					<text>{{ visitorCount }}人浏览</text>
+				</view>
+			</view>
+			<view class="top-main-tit">
+				<u-icon name="file-text-fill" color="#007AFF" size="40"> </u-icon>
+				<text>业务介绍</text>
+			</view>
+			<view class="top-maind">
+				<view class="topmain">
+					<view class="leftimg">
+						<u-avatar size="60" :src="cardObj.head_img" shape="square"></u-avatar>
+					</view>
+					<view class="rightcont">
+						<view v-if="!cardObj.intro" class="name">Hi~欢迎访问我的名片,了解更多内容请直接咨询我。</view>
+						<view v-if="cardObj.intro" class="name">{{ cardObj.intro }}</view>
+					</view>
+				</view>
+			</view>
+
+		</view>
+		<view class="bottom-block"></view>
+		<view class="bottombtn" type="primary" @click="gotoEdit">编辑我的名片</view>
+	</view>
+</template>
+
+<script>
+import {
+	request
+} from '@/utils/request'
+import { USER_INFO } from '../../constant'
+export default {
+	name: 'Index',
+	data() {
+		return {
+			id: '',
+			headerImg: '/static/images/userimg.png',
+			cardObj: {},
+			visitorList: [],
+			visitorCount: 0,
+			headerList: []
+		}
+	},
+	async onShow(options) {
+		console.log('onLoad options', options)
+		if (uni.getStorageSync(USER_INFO)) {
+			var user = uni.getStorageSync(USER_INFO)
+			if (id != null && id != '') {
+				this.id = id
+				const card = await request('uni-card', 'getCard', {
+					id,
+					uid: user.id
+				}, {
+					showloading: true
+				})
+				if (card._id == '') {
+					this.getDefault()
+				} else {
+					const visitorList = await request('uni-card', 'getVisitorList', {
+						card_id: id,
+						skip: 0,
+						limit: 8
+					}, {
+						showloading: true
+					})
+					this.cardObj = card
+					this.visitorCount = visitorList.total
+					visitorList.items.forEach((arr, index) => {
+						if (arr.head_img) { this.headerList.push(arr.head_img) } else { this.headerList.push('/static/images/userimg.png') }
+					})
+				}
+			} else {
+				const mycard = await request('uni-card', 'getMyCard', {
+					uid: user.id
+				}, {
+					showloading: true
+				})
+				if (mycard._id == '') {
+					this.getDefault()
+				} else {
+					const myVisitorList = await request('uni-card', 'getMyVisitorList', {
+						uid: user.id,
+						skip: 0,
+						limit: 8
+					}, {
+						showloading: true
+					})
+					this.cardObj = mycard
+					this.visitorCount = myVisitorList.total
+					myVisitorList.items.forEach((arr, index) => {
+						if (arr.head_img) { this.headerList.push(arr.head_img) } else { this.headerList.push('/static/images/userimg.png') }
+					})
+				}
+			}
+		}
+	},
+	onShareAppMessage(res) {
+		if (this.id == '' || this.id == null) {
+			this.id = '61b30b8091a7500001dea375'
+		}
+		return {
+			title: '您好,这是我的名片,望惠存',
+			path: '/pages/index?id=' + this.id
+		}
+	},
+	methods: {
+		async getDefault() {
+			const card = await request('uni-card', 'getCard', {
+				id: '61b30b8091a7500001dea375',
+				uid: '61b30b4e7964120001e32f41'
+			}, {
+				showloading: true
+			})
+			if (card._id == '') {
+				this.gotoEdit()
+			}
+			const visitorList = await request('uni-card', 'getVisitorList', {
+				card_id: '61b30b8091a7500001dea375',
+				skip: 0,
+				limit: 8
+			}, {
+				showloading: true
+			})
+			this.cardObj = card
+			this.visitorCount = visitorList.total
+			visitorList.items.forEach((arr, index) => {
+				if (arr.head_img) { this.headerList.push(arr.head_img) } else { this.headerList.push('/static/images/userimg.png') }
+			})
+		},
+		onAdd() {
+			uni.addPhoneContact({
+				organization: this.cardObj.company,
+				firstName: this.cardObj.name,
+				title: this.cardObj.job,
+				email: this.cardObj.email,
+				mobilePhoneNumber: this.cardObj.phone,
+				weChatNumber: this.cardObj.wechat,
+				remark: this.cardObj.address,
+				success() {
+					console.log('success')
+				},
+				fail() {
+					console.log('fail')
+				}
+			})
+		},
+		onPhone() {
+			uni.makePhoneCall({
+				phoneNumber: this.cardObj.phone,
+				success: (res) => {
+					console.log('调用成功!')
+				},
+				fail: (res) => {
+					console.log('调用失败!')
+				}
+			})
+		},
+		onCopy(data) {
+			uni.setClipboardData({
+				data, // 要被复制的内容
+				success() {
+					// 重点~做笔记
+					// 在success中加入uni.hideToast()可以解决
+					uni.showToast({
+						title: '复制成功',
+						duration: 2000,
+						icon: 'none'
+					})
+					// 以下就可自定义操作了~
+				},
+				fail(err) {
+					uni.showToast({
+						title: '复制失败',
+						duration: 2000,
+						icon: 'none'
+					})
+				}
+			})
+		},
+		gotoEdit() {
+			uni.navigateTo({
+				url: '/pages/edit/edit'
+			})
+		}
+	}
+}
+</script>
+
+<style>
+page {
+	background: #f7f7f7;
+}
+
+.content {
+	display: flex;
+	flex-direction: column;
+	align-items: center;
+	justify-content: center;
+}
+
+.content-box {
+	width: 100%;
+	box-sizing: border-box;
+	padding: 0 5%;
+}
+
+.content-box .top-main-box {
+	width: 100%;
+	box-sizing: border-box;
+	border-radius: 15rpx;
+	height: 52vw;
+	overflow: hidden;
+	position: relative;
+	box-shadow: 0px 0px 10px #cccccc;
+}
+
+.content-box .top-main-box .zzbg {
+	width: 100%;
+	position: absolute;
+	top: 0;
+	left: 0;
+	background: rgba(139, 139, 139, 0.5);
+	z-index: 1;
+}
+
+.content-box .top-main-box .mpimg {
+	width: 100%;
+}
+
+.content-box .top-main-box .topmain {
+	width: 100%;
+	box-sizing: border-box;
+	padding: 40rpx 5%;
+	display: flex;
+	align-items: flex-start;
+	position: relative;
+	z-index: 4;
+}
+
+.content-box .top-main-box .topmain .leftimg {
+	width: 150rpx;
+	height: 150rpx;
+	border-radius: 15rpx;
+	overflow: hidden;
+}
+
+.content-box .top-main-box .topmain .leftimg .tximg {
+	width: 100%;
+}
+
+.content-box .top-main-box .topmain .rightcont {
+	color: #fff;
+	flex: 1;
+	box-sizing: border-box;
+	padding-left: 25rpx;
+}
+
+.content-box .top-main-box .topmain .rightcont .name {
+	font-size: 42rpx;
+	padding-bottom: 10rpx;
+}
+
+.content-box .top-main-box .topmain .rightcont .tip,
+.content-box .top-main-box .topmain .rightcont .tipa {
+	font-size: 34rpx;
+	text-shadow: 1px 1px 1px #000;
+}
+
+.content-box .top-main-box .btnmain {
+	width: 100%;
+	position: absolute;
+	left: 0;
+	bottom: 0px;
+	z-index: 5;
+	box-sizing: border-box;
+	padding: 25rpx 5%;
+	background: #fff;
+	display: inline;
+	align-items: center;
+	justify-content: space-between;
+	text-align: left;
+}
+
+.content-box .top-main-box .btnmain view {
+	float: left;
+}
+
+.content-box .top-main-box .btnmain text {
+	font-size: 24rpx;
+	color: #333333;
+	padding-left: 10rpx;
+	float: left;
+}
+
+.content-box .top-maina {
+	width: 100%;
+	box-sizing: border-box;
+	display: flex;
+	align-items: center;
+	justify-content: space-between;
+	margin: 20rpx auto;
+}
+
+.content-box .top-maina view {
+	width: 48%;
+	border-radius: 15rpx;
+	text-align: center;
+	padding: 25rpx 0;
+	font-size: 18px;
+}
+
+.content-box .top-maina .left {
+	border: 1px solid #007AFF;
+	color: #007AFF;
+	width: 48%;
+}
+
+.content-box .top-maina .right {
+	background: #007AFF;
+	border: 1px solid #007AFF;
+	color: #fff;
+	width: 48%;
+}
+
+.content-box .top-mainb {
+	width: 100%;
+	overflow: scroll;
+	padding: 15rpx 0;
+	overflow-x: hidden;
+}
+
+.content-box .top-mainb .conta {
+	width: 100%;
+	overflow-x: auto;
+	word-break: keep-all;
+	/* 不换行 */
+	white-space: nowrap;
+	/* 不换行 */
+	padding-bottom: 20rpx;
+}
+
+.content-box .top-mainb .conta .cont {
+	display: inline-block;
+	margin-right: 20rpx;
+	background: #fff;
+	box-shadow: 0px 0px 8px #cccccc;
+	border-radius: 10rpx;
+	overflow: hidden;
+}
+
+.content-box .top-mainb .conta .cont .box {
+	display: flex;
+	align-items: center;
+	justify-content: space-between;
+	box-sizing: border-box;
+	padding: 15rpx 20rpx;
+}
+
+.content-box .top-mainb .conta .cont .box image {
+	width: 80rpx;
+	height: 80rpx;
+}
+
+.content-box .top-mainb .conta .cont .box .right {
+	flex: 1;
+	box-sizing: border-box;
+	padding-left: 10rpx;
+}
+
+.content-box .top-mainb .conta .cont .box .right text {
+	display: block;
+	font-size: 30rpx;
+}
+
+.content-box .top-mainb .conta .cont .box .right .tit {
+	font-size: 34rpx;
+}
+
+.content-box .top-mainc {
+	width: 100%;
+	box-sizing: border-box;
+	padding: 20rpx 10rpx;
+	display: flex;
+	align-items: center;
+	justify-content: space-between;
+	margin: 10rpx auto;
+	background: #fff;
+}
+
+.content-box .top-mainc .left {
+	flex: 1;
+	display: flex;
+	align-items: center;
+}
+
+.content-box .top-mainc .left text {
+	font-size: 28rpx;
+	color: #555555;
+}
+
+.content-box .top-mainc .left image {
+	width: 60rpx;
+	height: 60rpx;
+	margin-right: 5rpx;
+	border-radius: 10rpx;
+}
+
+.content-box .top-mainc .right {
+	display: flex;
+	align-items: center;
+	justify-content: space-between;
+}
+
+.content-box .top-mainc .right text {
+	font-size: 28rpx;
+	color: #555555;
+	padding-right: 10rpx;
+}
+
+.content-box .top-mainc .right image {
+	width: 40rpx;
+	height: 40rpx;
+}
+
+.content-box .top-main-tit {
+	width: 100%;
+	box-sizing: border-box;
+	padding: 20rpx 10rpx;
+	display: flex;
+	align-items: center;
+}
+
+.content-box .top-main-tit image {
+	width: 60rpx;
+	height: 60rpx;
+}
+
+.content-box .top-main-tit text {
+	color: #333;
+	font-size: 18px;
+	padding-left: 10rpx;
+}
+
+.content-box .top-maind {
+	width: 100%;
+	box-sizing: border-box;
+	padding: 40rpx 5%;
+	background: #fff;
+	box-shadow: 0px 0px 8px #cccccc;
+}
+
+.content-box .top-maind .topmain {
+	width: 100%;
+	box-sizing: border-box;
+	display: flex;
+	align-items: flex-start;
+}
+
+.content-box .top-maind .topmain .leftimg {
+	width: 120rpx;
+	height: 120rpx;
+	border-radius: 15rpx;
+	overflow: hidden;
+}
+
+.content-box .top-maind .topmain .leftimg .tximg {
+	width: 100%;
+}
+
+.content-box .top-maind .topmain .rightcont {
+	color: #555;
+	flex: 1;
+	box-sizing: border-box;
+	padding-left: 25rpx;
+	line-height: 42rpx;
+	font-size: 28rpx;
+}
+
+.content-box .top-maind .toptip {
+	width: 100%;
+}
+
+.content-box .top-maind .toptip .box {
+	display: inline-block;
+	margin-top: 25rpx;
+	padding: 10rpx 15rpx;
+	background: #e6e6e6;
+	border-radius: 10rpx;
+	overflow: hidden;
+	margin-right: 20rpx;
+}
+
+.content-box .top-maind .toptip .box image {
+	width: 30rpx;
+	height: 30rpx;
+}
+
+.content-box .top-maind .toptip .box text {
+	font-size: 28rpx;
+	padding-left: 10rpx;
+}
+
+.bottombtn {
+	position: fixed;
+	bottom: 0;
+	width: 100%;
+	height: 60px;
+	background: #007AFF;
+	color: #fff;
+	line-height: 60px;
+	text-align: center;
+}
+
+.bottom-block {
+	display: block;
+	width: 100%;
+	height: 80px;
+}
+</style>

+ 214 - 0
pages/login/accountLogin.vue

@@ -0,0 +1,214 @@
+<template>
+	<view class="container flex-column">
+		<view style="padding: 30upx 20upx 0;color: #000000;">
+			<JHeader width="50" height="50" title=""></JHeader>
+		</view>
+		<view class="register" @click="handleClickRegister">
+			注册
+		</view>
+		<view class="PhoneAuthentication">
+			<text class="textRL">手机号快捷登录</text>
+			<text class="textTips">请先注册账号再登录</text>
+		</view>
+		<view class="LoginForm">
+			<view class="iphoneNum-box">
+				<text class="labels">手机号</text>
+				<input v-model="loginForm.username" type="text" placeholder="请输入手机号">
+			</view>
+			<view class="iphoneNum-box">
+				<text class="labels">密码</text>
+				<input v-model="loginForm.password" password type="text" placeholder="请输入密码">
+			</view>
+			<view class="ReadingAgreement">
+				<radio
+					style="transform:scale(0.8)" color="#CE2601" :checked="isReadAgreement"
+					@click="isReadAgreement = !isReadAgreement"
+				/>
+				<view class="Agreement">
+					我已阅读并同意<text class="redText">《巨蜂商城用户服务协议》</text>以及<text class="redText">《隐私政策》</text>
+				</view>
+			</view>
+		</view>
+		<tui-button
+			:disabled="!isReadAgreement" type="danger" width="650rpx" margin="0 auto"
+			height="82rpx"
+			style="margin-top: 60rpx;" @click="handleLogin"
+		>
+			立即登录
+		</tui-button>
+		<view class="problem">
+			<text @click="handleClickRegister">没有账号?<text class="redText">去注册</text></text>
+			<text>无法接收验证码?</text>
+		</view>
+	</view>
+</template>
+
+<script>
+import { userLoginApi } from '../../api/auth'
+import {
+	J_USER_INFO,
+	J_USER_TOKEN,
+	J_TOKEN_EXPIRE,
+	J_USER_ID,
+	J_BRAND_ID,
+	J_NEW_BIND_TYPE
+} from '../../constant'
+export default {
+	name: 'Login',
+	data() {
+		return {
+			redirect: '',
+			loginForm: {
+				username: '',
+				password: ''
+			},
+			isReadAgreement: false
+		}
+	},
+	onLoad(options) {
+		this.redirect = options.redirect
+	},
+
+	methods: {
+		handleClickRegister() {
+			uni.reLaunch({ url: '/pages/register/register?type=register' })
+		},
+		handleLogin() {
+			const { username, password } = this.loginForm
+			if (!username || !password) {
+				this.$showToast('手机号或密码不能为空')
+				return
+			}
+			if (
+				!/^1[3456789]\d{9}$/.test(username)
+			) {
+				uni.showToast({
+					title: '手机号格式不正确',
+					duration: 2000,
+					icon: 'none'
+				})
+				return
+			}
+			if (password.length < 6) {
+				this.$showToast('密码不能小于六位')
+				return
+			}
+			userLoginApi({
+				...this.loginForm
+			}).then((res) => {
+				uni.setStorageSync(J_USER_INFO, res.data.userInfo)
+				uni.setStorageSync(J_USER_TOKEN, res.data.token)
+				uni.setStorageSync(J_USER_ID, res.data.userInfo.userId)
+				uni.setStorageSync(J_BRAND_ID, res.data.userInfo.brandId)
+				uni.setStorageSync(J_TOKEN_EXPIRE, new Date(res.data.tokenExpire).getTime())
+				this.$parent.$root.connectSocket()
+				this.$showToast('登录成功', 'success')
+				setTimeout(() => {
+					if (uni.getStorageSync(J_NEW_BIND_TYPE)) {
+						uni.redirectTo({ url: '/pages/jump/jump' })
+					} else if (this.redirect) {
+						uni.redirectTo({
+							url: this.redirect
+						})
+					} else {
+						this.$switchTab('/pages/store/store')
+					}
+				}, 2000)
+			})
+		}
+	}
+}
+</script>
+
+<style lang="less" scoped>
+.container {
+	box-sizing: border-box;
+	background-color: #FFFFFF;
+
+	.redText {
+		color: #CE2601;
+	}
+
+	.register {
+		margin-top: 30rpx;
+		position: relative;
+		text-align: right;
+		padding-right: 40rpx;
+	}
+
+	.PhoneAuthentication {
+		margin-top: 15rpx;
+		font-family: Source Han Sans CN;
+		width: 466rpx;
+		height: 100rpx;
+		display: flex;
+		flex-direction: column;
+		padding: 0px 30rpx;
+		gap: 8rpx;
+
+		.textRL {
+			font-size: 44rpx;
+			font-weight: 600;
+			line-height: 60rpx;
+			color: #222229;
+		}
+
+		.textTips {
+			font-size: 24rpx;
+			font-weight: 350;
+			line-height: 32rpx;
+			color: #888889;
+		}
+	}
+
+	.LoginForm {
+		margin-top: 50rpx;
+		width: 750rpx;
+
+		.iphoneNum-box {
+			/* 自动布局 */
+			margin: 0 auto;
+			height: 114rpx;
+			display: flex;
+			flex-direction: row;
+			align-items: center;
+			gap: 32rpx;
+			border-bottom: 2rpx solid #E6E6E8;
+			width: 690rpx;
+			color: #222229;
+
+			.labels {
+				font-size: 32rpx;
+				font-weight: normal;
+				line-height: 48rpx;
+			}
+		}
+
+		.ReadingAgreement {
+			width: 710rpx;
+			margin: 0 auto;
+			margin-top: 33rpx;
+			gap: 32rpx;
+			display: flex;
+			align-items: center;
+			font-size: 24rpx;
+
+			.Agreement {
+				margin-left: -15rpx;
+			}
+		}
+	}
+
+	.problem {
+		margin: 0 auto;
+		margin-top: 30rpx;
+		width: 654rpx;
+		display: flex;
+		justify-content: space-between;
+		font-size: 24rpx;
+		font-weight: 350;
+		line-height: 32rpx;
+		color: #878788;
+	}
+}
+</style>

+ 294 - 0
pages/login/bind-phone.vue

@@ -0,0 +1,294 @@
+<template>
+	<view class="login-container">
+		<image class="back-icon" src="../../static/back.png" mode="" @click="handleBack" />
+
+		<view class="login-main-area">
+			<h1>绑定手机号</h1>
+
+			<tui-form ref="form">
+				<tui-input
+					v-model="bindForm.phone" label="手机号码" padidng="0 0 28rpx 0" border-top
+					placeholder="请输入手机号码"
+					color="#141000"
+				></tui-input>
+
+				<tui-input
+					v-model="bindForm.code" class="reset-wrapper" label="验证码" padidng="0 0 28rpx 0"
+					border-top
+					placeholder="请输入验证码" color="#141000"
+				>
+					<block slot="right">
+						<button v-show="!timer" class="uni-btn get-code" @click="onGetCode">
+							获取验证码
+						</button>
+
+						<view v-show="timer" class="awaiting">
+							<text class="second-text">{{ awaitSecond }}s</text>
+							<text>后重新获取</text>
+						</view>
+					</block>
+				</tui-input>
+			</tui-form>
+
+			<button class="bind-btn uni-btn" :style="{ background: btnStatus ? '#FFC117' : '' }" @click="onBind">
+				确定
+			</button>
+		</view>
+		<tui-toast ref="toast"></tui-toast>
+	</view>
+</template>
+
+<script>
+import {
+	getCodeApi,
+	bindMobileForWXApi
+} from '../../api/auth'
+import {
+	throttle
+} from '../../utils'
+import { J_USER_ID, J_USER_INFO, J_USER_TOKEN, J_NEW_BIND_TYPE } from '../../constant'
+
+export default {
+	name: 'BindPhone',
+	data() {
+		return {
+			bindForm: {
+				'openId': '',
+				'phone': '',
+				'code': ''
+			},
+			onGetCode: '',
+			onBind: '',
+			timer: null,
+			awaitSecond: 60,
+			userId: null
+		}
+	},
+
+	onLoad(options) {
+		this.onGetCode = throttle(this.handleGetCode, 1000)
+		this.onBind = throttle(this.handleBindMobile, 1000)
+		this.bindForm.openId = options.openId
+		this.userId = options.userId
+	},
+
+	onUnload() {
+		this.timer && clearInterval(this.timer)
+	},
+
+	computed: {
+		btnStatus() {
+			return this.bindForm.code && this.bindForm.phone
+		}
+	},
+
+	methods: {
+		// 获取验证码
+		async handleGetCode() {
+			if (this.bindForm.phone.length !== 11) {
+				this.ttoast({
+					type: 'fail',
+					title: '请输入合法的手机号码'
+				})
+				return
+			}
+			uni.showLoading({
+				title: '加载中...'
+			})
+			try {
+				await getCodeApi({
+					phone: this.bindForm.phone,
+					flag: 2
+				})
+				this.timer = setInterval(() => {
+					this.awaitSecond--
+					if (this.awaitSecond === 0) {
+						this.awaitSecond = 60
+						clearInterval(this.timer)
+						this.timer = null
+					}
+				}, 1000)
+			} catch (error) {
+				this.ttoast({
+					type: 'fail',
+					title: '验证码发送失败',
+					content: '请稍后重试'
+				})
+			} finally {
+				uni.hideLoading()
+			}
+		},
+
+		handleBack() {
+			uni.navigateBack()
+		},
+
+		async handleBindMobile() {
+			if (!this.bindForm.code) {
+				this.ttoast({
+					type: 'fail',
+					title: '请输入验证码'
+				})
+				return
+			}
+			if (!this.bindForm.phone) {
+				this.ttoast({
+					type: 'fail',
+					title: '请输入绑定的手机号'
+				})
+				return
+			}
+			if (this.bindForm.phone.length !== 11) {
+				this.ttoast({
+					type: 'fail',
+					title: '请输入合法的手机号码'
+				})
+				return
+			}
+			const { data } = await bindMobileForWXApi(this.bindForm)
+			this.ttoast('绑定成功')
+			uni.setStorageSync(J_USER_ID, data.userInfo.userId)
+			uni.setStorageSync(J_USER_INFO, data.userInfo)
+			uni.setStorageSync(J_USER_TOKEN, data.token)
+			if (uni.getStorageSync(J_NEW_BIND_TYPE)) {
+				setTimeout(() => {
+					uni.redirectTo({
+						url: '/pages/jump/jump'
+					})
+				}, 1000)
+			} else {
+				setTimeout(() => {
+					this.$switchTab('/')
+				}, 1000)
+			}
+		}
+	}
+}
+</script>
+
+<style lang="less" scoped>
+view,
+text {
+	line-height: 1.5;
+}
+
+.login-container {
+	width: 100vw;
+	min-height: 100vh;
+	background: url('../../static/bg.png') no-repeat;
+	background-size: cover;
+
+	.back-icon {
+		position: relative;
+		top: 30upx;
+		left: 20upx;
+		width: 80upx;
+		height: 80upx;
+		z-index: 1000;
+	}
+
+	.login-main-area {
+		padding: 90upx 80upx 0;
+
+		h1 {
+			color: #141000;
+			font-size: 64upx;
+			font-weight: 400;
+			margin-bottom: 120upx;
+		}
+
+		/deep/ .tui-input__wrap {
+			padding: 0 0 28upx 0 !important;
+			flex-direction: column;
+			align-items: flex-start;
+			background: transparent !important;
+			margin-bottom: 72upx !important;
+
+			&::before {
+				display: none;
+			}
+		}
+
+		/deep/ .tui-input__label {
+			text {
+				margin-bottom: 12upx;
+				font-size: 24upx !important;
+				color: #b3b2ad !important;
+			}
+		}
+
+		/deep/ .uni-input-wrapper {
+			margin-top: 12upx;
+
+			input {
+				padding-bottom: 28upx !important;
+			}
+		}
+
+		/deep/ .tui-line__left::after {
+			left: 0 !important;
+		}
+
+		.reset-wrapper {
+			/deep/ .tui-input__wrap {
+				flex-wrap: wrap !important;
+				flex-direction: row !important;
+				margin-bottom: 10upx !important;
+
+				.tui-input__label {
+					flex: 0 0 100%;
+				}
+			}
+		}
+
+		.password-status {
+			width: 48upx;
+			height: 48upx;
+			flex-shrink: 0;
+			margin-top: 12upx;
+		}
+	}
+
+	.bind-btn {
+		width: 606upx;
+		height: 96upx;
+		border-radius: 100px;
+		margin: 80upx 0 40upx 0;
+		background-color: #ffe6a2;
+		color: #fff;
+		line-height: 96upx;
+		font-size: 32upx;
+		font-weight: 500;
+		transition: all 100ms;
+		opacity: 1;
+
+		&:active {
+			opacity: 0.3;
+		}
+	}
+
+	.get-code {
+		color: #ffc117;
+		font-size: 28upx;
+		margin-top: 24upx;
+	}
+
+	.awaiting {
+		font-size: 28upx;
+		color: #b3b2ad;
+		margin-top: 12upx;
+
+		.second-text {
+			color: #605d52;
+		}
+	}
+}
+
+.skip {
+	display: flex;
+	justify-content: flex-end;
+	align-items: center;
+	font-size: 24upx;
+	color: rgb(153, 153, 153);
+}
+</style>

+ 296 - 0
pages/login/login copy.vue

@@ -0,0 +1,296 @@
+<template>
+	<view class="container">
+		<view style="padding: 68upx 0 0 56upx;color: #ffffff;">
+			<view style="font-weight: bold;font-style: oblique;">
+				<view style="font-size: 58upx;">欢迎来到</view>
+				<view style="font-size: 62upx;">巨蜂本地生活</view>
+			</view>
+			<view style="margin-top: 12upx;;font-size: 30upx;">
+				<text>数字化营销的领跑者</text>
+			</view>
+		</view>
+
+		<view style="display: flex;flex-direction: column;justify-content: center;align-items: center;margin-top: 80upx;">
+			<view
+				v-if="(loginForm.terminal === 3) || (loginForm.terminal === 2)" style="text-align: center;"
+				@click="handleWXLogin"
+			>
+				<image style="width: 118upx;height: 98upx;" src="../../static/images/icon/we-chat.png" mode="" />
+				<tui-button type="white" width="480rpx" height="82rpx" margin="40upx 0 0" shape="circle" @click="handleWXLogin">
+					微信一键登录
+				</tui-button>
+			</view>
+			<!-- #ifdef MP-ALIPAY -->
+			<tui-button type="danger" width="480rpx" height="82rpx" margin="70upx 0 0" shape="circle">
+				支付宝登录
+			</tui-button>
+			<!-- #endif -->
+			<tui-button
+				type="white" width="480rpx" height="82rpx" margin="70upx 0 0"
+				shape="circle"
+				@click="$switchTab('/pages/index/index')"
+			>
+				去首页逛逛
+			</tui-button>
+		</view>
+
+		<view class="otherLoginButton">
+			<view class="orderButtonItem">
+				<view style="display: flex;flex-direction: column;align-items: center;">
+					<view style="width: fit-content;padding: 12upx;background-color: #ffffff;border-radius: 48upx;">
+						<tui-icon name="pwd" color="#ce2601" :size="24" @click="go('/pages/login/accountLogin')"></tui-icon>
+					</view>
+					<view style="margin-top: 12upx;font-size: 26upx;color: #ffffff;">密码登录</view>
+				</view>
+				<view style="display: flex;flex-direction: column;align-items: center;">
+					<view style="width: fit-content;padding: 12upx;background-color: #ffffff;border-radius: 48upx;">
+						<tui-icon
+							name="wealth-fill" color="#ce2601" :size="24"
+							@click="$redirectTo('/pages/register/register?type=register')"
+						></tui-icon>
+					</view>
+					<view style="margin-top: 12upx;font-size: 26upx;color: #ffffff;">注册</view>
+				</view>
+				<view style="display: flex;flex-direction: column;align-items: center;">
+					<view style="width: fit-content;padding: 12upx;background-color: #ffffff;border-radius: 48upx;">
+						<tui-icon
+							name="mail-fill" color="#ce2601" :size="24"
+							@click="$redirectTo('/pages/register/register?type=forgetPwd')"
+						></tui-icon>
+					</view>
+					<view style="margin-top: 12upx;font-size: 26upx;color: #ffffff;">找回密码</view>
+				</view>
+			</view>
+		</view>
+		<view class="agreement">
+			登录即同意<text class="colorText">《联通统一认证服务条款》</text>和<text class="colorText">《巨蜂商城用户 服务协议》</text>、<text
+				class="colorText"
+			>
+				《隐私政策》
+			</text>并使用本机号码登陆
+		</view>
+	</view>
+</template>
+
+<script>
+import { userLoginApi, wxLoginApi, updateNotBindingWxPhone } from '../../api/auth'
+import {
+	J_USER_INFO,
+	J_USER_TOKEN,
+	J_TOKEN_EXPIRE,
+	J_USER_ID,
+	J_BRAND_ID,
+	J_NEW_BIND_TYPE
+} from '../../constant'
+import { getUrlCode, isInWx } from '../../utils'
+export default {
+	name: 'Login',
+	data() {
+		return {
+			type: '',
+			redirect: '',
+			loginForm: {
+				username: '',
+				password: '',
+				terminal: ''
+			}
+		}
+	},
+	onLoad(options) {
+		if (isInWx()) {
+			this.loginForm.terminal = 3
+		} else {
+			// #ifdef H5
+			this.loginForm.terminal = 5 // H5包含pc和移动端浏览器和微信浏览器的可能
+			// #endif
+			// #ifdef APP
+			this.loginForm.terminal = 1
+			// #endif
+			// #ifdef MP-WEIXIN
+			this.loginForm.terminal = 2
+			// #endif
+			// #ifdef MP-ALIPAY
+			this.loginForm.terminal = 4
+			// #endif
+		}
+		this.type = options.type
+		this.redirect = options.redirect
+		if (this.type === 'register') {
+			this.$showToast('注册成功', 'success')
+		} else if (uni.getStorageSync(J_NEW_BIND_TYPE)) {
+			if (uni.getStorageSync(J_USER_ID) && uni.getStorageSync(J_USER_INFO)) {
+				uni.redirectTo({ url: '/pages/jump/jump' })
+			}
+		} else if (this.type === 'forget') {
+			this.$showToast('密码重置成功', 'success')
+		}
+	},
+	onShow() {
+		// #ifdef H5
+		const code = getUrlCode().code
+		if (code) this.handleWXLogin()
+		// #endif
+	},
+
+	methods: {
+		handleLogin() {
+			const { username, password } = this.loginForm
+			if (!username || !password) {
+				this.$showToast('手机号或密码不能为空')
+				return
+			}
+			if (
+				!/^1[3456789]\d{9}$/.test(username)
+			) {
+				uni.showToast({
+					title: '手机号格式不正确',
+					duration: 2000,
+					icon: 'none'
+				})
+				return
+			}
+			if (password.length < 6) {
+				this.$showToast('密码不能小于六位')
+				return
+			}
+			userLoginApi({
+				...this.loginForm
+			}).then((res) => {
+				uni.setStorageSync(J_USER_INFO, res.data.userInfo)
+				uni.setStorageSync(J_USER_TOKEN, res.data.token)
+				uni.setStorageSync(J_USER_ID, res.data.userInfo.userId)
+				uni.setStorageSync(J_BRAND_ID, res.data.userInfo.brandId)
+				uni.setStorageSync(J_TOKEN_EXPIRE, new Date(res.data.tokenExpire).getTime())
+				this.$parent.$root.connectSocket()
+				this.$showToast('登录成功', 'success')
+				this.handleLoginSuccess()
+			})
+		},
+
+		// 点击微信登录
+		async handleWXLogin() {
+			// #ifdef H5
+			const appid = 'wx603b04a561e4683e'
+			const local = 'https://h5.jfcmei.com/#/pages/login/login'
+			const code = getUrlCode().code
+			// console.log('获取code', code)
+			if (code === null || code === undefined || code === '') {
+				window.location.href =
+					'https://open.weixin.qq.com/connect/oauth2/authorize?appid=' +
+					appid +
+					'&redirect_uri=' +
+					encodeURIComponent(local) +
+					'&response_type=code&scope=snsapi_userinfo#wechat_redirect'
+			} else {
+				const { data } = await wxLoginApi({ code })
+				console.log(data) // {token,status,userInfo}
+				uni.setStorageSync(J_USER_ID, data.userInfo.userId)
+				uni.setStorageSync(J_USER_INFO, data.userInfo)
+				uni.setStorageSync(J_USER_TOKEN, data.token)
+				this.$parent.$root.connectSocket()
+				// ofxYi6eg9rdj8qZx3rwSecysgePo
+				if (!data.status) {
+					uni.showModal({
+						title: '提示',
+						content: '您还未绑定手机号,请先绑定',
+						success: ({ confirm }) => {
+							if (confirm) {
+								uni.navigateTo({
+									url: '/pages/login/bind-phone?openId=' + data.userInfo.openId
+								})
+							} else {
+								uni.showLoading()
+								updateNotBindingWxPhone({
+									// openId: data.userInfo.openId,
+									// nickname: data.userInfo.nickname,
+									// sex: data.userInfo.gender,
+									// headimgurl: data.userInfo.avatarUrl,
+									// unionid: data.userInfo.unionid
+									...data.userInfo
+								})
+									.then((res) => {
+										uni.hideLoading()
+										this.$showToast('正在跳转...')
+										this.handleLoginSuccess('WX')
+									})
+									.catch(() => {
+										uni.removeStorageSync(J_USER_ID, data.userInfo.userId)
+										uni.removeStorageSync(J_USER_INFO, data.userInfo)
+										uni.removeStorageSync(J_USER_TOKEN, data.token)
+										uni.hideLoading()
+									})
+							}
+						}
+					})
+				} else {
+					this.$showToast('登录成功', 'success')
+					this.handleLoginSuccess('WX')
+				}
+			}
+			// #endif
+		},
+
+		handleLoginSuccess(type) {
+			if (type === 'WX') {
+				setTimeout(() => {
+					if (uni.getStorageSync(J_NEW_BIND_TYPE)) {
+						window.location.replace('https://h5.jfcmei.com/#/pages/jump/jump')
+					} else if (this.redirect) {
+						window.location.replace(`https://h5.jfcmei.com/#${this.redirect}`)
+					} else {
+						window.location.replace('https://h5.jfcmei.com/#/pages/store/store')
+					}
+				}, 2000)
+			} else {
+				setTimeout(() => {
+					if (uni.getStorageSync(J_NEW_BIND_TYPE)) {
+						uni.redirectTo({ url: '/pages/jump/jump' })
+					} else if (this.redirect) {
+						uni.redirectTo({
+							url: this.redirect
+						})
+					} else {
+						this.$switchTab('/pages/store/store')
+					}
+				}, 2000)
+			}
+		}
+	}
+}
+</script>
+
+<style lang="less" scoped>
+.container {
+	background-color: #b9452b;
+	min-height: 100vh;
+
+	.otherLoginButton {
+		margin-top: 195rpx;
+		display: flex;
+		flex-direction: column;
+		align-items: center;
+
+		.orderButtonItem {
+			display: flex;
+			justify-content: space-around;
+			white-space: nowrap;
+
+			&>view:not(:first-child) {
+				padding-left: 48upx;
+			}
+		}
+	}
+
+	.agreement {
+		margin-top: 120rpx;
+		padding: 75upx;
+		font-size: 24rpx;
+		text-align: center;
+		color: #000000;
+
+		.colorText {
+			color: #faf9f9;
+		}
+	}
+}
+</style>

+ 53 - 51
pages/login.vue → pages/login/login.vue

@@ -2,7 +2,7 @@
 	<view>
 		<view class="login-main">
 			<image class="user" src="/static/images/userimg.png"></image>
-			<view class="name">好 </view>
+			<view class="name">好 </view>
 			<view class="tip">为了您的最佳体验,请登录</view>
 		</view>
 
@@ -14,66 +14,68 @@
 </template>
 
 <script>
-	import {
-		request
-	} from '@/common/js/request'
-	export default {
-		name: "",
-		data() {
-			return {
-				logged: uni.getStorageSync("logged"),
-			}
-		},
-		onLoad() {
-
+import {
+	request
+} from '@/utils/request'
+import { USER_INFO } from '../../constant'
+export default {
+	name: 'Login',
+	data() {
+		return {
+		}
+	},
+	methods: {
+		async mpWxLogin(userInfoData) {
+			console.log('登陆')
+			await this.mpWxGetUserInfo(userInfoData)
+			this.$showToast('登陆成功')
+			uni.navigateTo({
+				url: '/pages/index'
+			})
 		},
-		methods: {
-			async mpWxLogin(userInfoData) {
-				console.log("登陆")
-				await this.mpWxGetUserInfo(userInfoData)
-				this.$util.msg('登陆成功');
-				this.logged = true;
-				await uni.setStorageSync("logged", true)
-				uni.navigateTo({
-					url: "/pages/index"
-				})
-			},
-			// 获取用户信息
-			async mpWxGetUserInfo(userInfoData) {
-				return new Promise((resolve, reject) => {
-					if (!userInfoData.detail.userInfo) {
-						reject(new Error('未拿到用户信息'))
-					}
-					this.$util.throttle(async () => {
-						const [loginErr, loginData] = await uni.login({
-							provider: 'weixin'
-						})
-						const [err, userData] = await uni.getUserInfo();
-						const res = await request('uni-card', 'loginByWx', {
-							code: loginData.code,
-							encryptedData: userData.encryptedData,
-							iv: userData.iv
-						}, {
-							showLoading: true
-						});
-						console.log("res", res)
-						resolve(res)
+		// 获取用户信息
+		async mpWxGetUserInfo(userInfoData) {
+			return new Promise(async (resolve, reject) => {
+				if (!userInfoData.detail.userInfo) {
+					reject(new Error('未拿到用户信息'))
+				}
+				try {
+					uni.showLoading({
+						mask: true,
+						title: '请稍候...'
 					})
-				}).then(async userInfo => {
-					console.log("mpWxGetUserInfo", userInfo)
-					this.$store.dispatch('setUserData', userInfo);
-					await uni.setStorageSync("userInfo", userInfo);
-					return userInfo
-				})
-			},
+					const [loginErr, loginData] = await uni.login({ provider: 'weixin' })
+					const [err, userData] = await uni.getUserInfo()
+					const res = await request('uni-card', 'loginByWx', {
+						code: loginData.code,
+						encryptedData: userData.encryptedData,
+						iv: userData.iv
+					}, {
+						showLoading: true
+					})
+					console.log('res', res)
+					uni.hideLoading()
+					resolve(res)
+				} catch (e) {
+					uni.hideLoading()
+					reject(e)
+				}
+			}).then(async (userInfo) => {
+				this.$store.dispatch('setUserData', userInfo)
+				await uni.setStorageSync(USER_INFO, userInfo)
+				return userInfo
+			})
 		}
 	}
+}
 </script>
+
 <style>
 	page {
 		background: #fff;
 	}
 </style>
+
 <style scoped>
 	.login-main {
 		width: 100%;

+ 111 - 20
store/index.js

@@ -1,3 +1,5 @@
+import { T_STORAGE_KEY, USER_INFO } from '../constant'
+import { getAnotherTFTokenApi } from '../api/anotherTFInterface'
 import Vue from 'vue'
 import Vuex from 'vuex'
 
@@ -5,48 +7,137 @@ Vue.use(Vuex)
 
 const store = new Vuex.Store({
 	state: {
-		userInfo: {}
+		userInfo: uni.getStorageSync(USER_INFO)
 	},
 	getters: {
 		userId(state) {
-			return state.userInfo.id || null;
+			return state.userInfo.id || null
 		}
 	},
 	mutations: {
-		//更新state数据
+		// 更新state数据
 		setStateAttr(state, param) {
 			if (param instanceof Array) {
-				for (let item of param) {
-					state[item.key] = item.val;
+				for (const item of param) {
+					state[item.key] = item.val
 				}
 			} else {
-				state[param.key] = param.val;
+				state[param.key] = param.val
 			}
+		},
+
+		'CHNAGE_USER_INFO'(state, userInfo) {
+			state.userInfo = userInfo
+			uni.setStorageSync(USER_INFO, userInfo)
 		}
 	},
 	actions: {
-		async setUserData({
-			state,
-			commit
-		}, data) {
+		setUserData({ state, commit }, data) {
 			commit('setStateAttr', {
 				key: 'userInfo',
 				val: data
 			})
-			uni.setStorageSync('userInfo', data);
+			uni.setStorageSync(USER_INFO, data)
 		},
-		logout({
-			state,
-			commit
-		}) {
-			commit('setStateAttr', {
-				key: 'userInfo',
-				val: {}
+
+		// 密码登录
+		loginAction({ commit, dispatch }, loginData) {
+			return new Promise((resolve, reject) => {
+				loginApi({ ...loginData })
+					.then(async ({ data }) => {
+						commit('CHNAGE_USER_INFO', data.userInfo)
+						uni.showToast({
+							title: '登录成功'
+						})
+						console.log(data)
+						await dispatch('updateStorageKeyToken')
+						resolve(data)
+					})
+					.catch((err) => {
+						reject(err)
+					})
+			})
+		},
+
+		// 验证码登录
+		codeLoginAction({ commit, dispatch }, loginData) {
+			return new Promise((resolve, reject) => {
+				verificationCodeApi({ ...loginData })
+					.then(async ({ data }) => {
+						commit('CHNAGE_USER_INFO', data.userInfo)
+						uni.showToast({
+							title: '登录成功'
+						})
+						console.log(data)
+						await dispatch('updateStorageKeyToken')
+						resolve(data)
+					})
+					.catch((err) => {
+						reject(err)
+					})
+			})
+		},
+
+		// 微信登陆
+		wxLogin({ commit, dispatch }, code) {
+			return new Promise((resolve, reject) => {
+				wxLoginApi({ code })
+					.then(async ({ data }) => {
+						commit('CHNAGE_USER_INFO', data.userInfo)
+						uni.showToast({
+							title: '登录成功'
+						})
+						await dispatch('updateStorageKeyToken')
+						resolve(data)
+					})
+					.catch((err) => {
+						reject(err)
+					})
+			})
+		},
+
+		logout({ commit }, isQuiet) {
+			uni.removeStorageSync(USER_INFO)
+			commit(CHNAGE_USER_INFO, '')
+			clearAllCache()
+			if (isQuiet) {
+				uni.showToast({
+					title: '退出成功'
+				})
+				setTimeout(() => {
+					uni.switchTab({
+						url: '/pages/community-center/community-centerr'
+					})
+				}, 2000)
+			}
+		},
+
+		// 获取新团蜂token
+		updateStorageKeyToken({ state, dispatch, commit }) {
+			return new Promise((resolve, reject) => {
+				const userInfo = uni.getStorageSync(USER_INFO)
+				if (userInfo && userInfo.phone) {
+					uni.showLoading({ mask: true })
+					getAnotherTFTokenApi({ phone: userInfo.phone })
+						.then((res) => {
+							uni.setStorageSync(T_STORAGE_KEY, res.data)
+							uni.hideLoading()
+							resolve(res.data)
+						})
+						.catch((err) => {
+							uni.hideLoading()
+							resolve(err)
+						})
+					dispatch('updateIdentityInfo')
+				} else {
+					uni.showToast({
+						title: '缺少用户手机号码'
+					})
+					resolve('缺少用户手机号码')
+				}
 			})
-			uni.removeStorageSync('userInfo');
 		}
 	}
 })
 
-
 export default store

+ 54 - 53
uni-starter.config.js

@@ -1,69 +1,70 @@
-//这是应用的配置页面,App.vue挂载到getApp().globalData.config
+// 这是应用的配置页面,App.vue挂载到getApp().globalData.config
 module.exports = {
-	"h5": {
-		"url": "https://uni-card.dcloud.net.cn/", //	前端网页托管的域名
-		 // 在h5端全局悬浮引导用户下载app的功能 更多自定义要求在/common/openApp.js中修改
-		"openApp": {
-			//点击悬浮下载栏后打开的网页链接
-			"openUrl": '/#/pages/ucenter/invite/invite',
-			//左侧显示的应用名称
-			"appname": 'uni-card',
-			//应用的图标
-			"logo": './static/logo.png',
+	'h5': {
+		'url': 'https://uni-card.dcloud.net.cn/', //	前端网页托管的域名
+		// 在h5端全局悬浮引导用户下载app的功能 更多自定义要求在/common/openApp.js中修改
+		'openApp': {
+			// 点击悬浮下载栏后打开的网页链接
+			'openUrl': '/#/pages/ucenter/invite/invite',
+			// 左侧显示的应用名称
+			'appname': 'uni-card',
+			// 应用的图标
+			'logo': './static/logo.png'
 		}
 	},
-	"mp": {
-		"weixin": {
-			//微信小程序原始id,微信小程序分享时
-			"id": "gh_33446d7f7a26"
+	'mp': {
+		'weixin': {
+			// 微信小程序原始id,微信小程序分享时
+			'id': 'gh_47dc8ea7762a'
 		}
 	},
-	"router": {
-		//needLogin:配置强制需要登陆的页面,在打开这些页面之前会自动检查(前端校验)uni_id_token的值是否有效,如果无效会自动跳转到登陆页面
-		"needLogin": [
-			"/pages/ucenter/userinfo/userinfo",
-			"/uni_modules/uni-news-favorite/pages/uni-news-favorite/list",
-			"/uni_modules/uni-feedback/pages/uni-feedback/add"
+	'router': {
+		// needLogin:配置强制需要登陆的页面,在打开这些页面之前会自动检查(前端校验)uni_id_token的值是否有效,如果无效会自动跳转到登陆页面
+		'needLogin': [
+			'/pages/ucenter/userinfo/userinfo',
+			'/uni_modules/uni-news-favorite/pages/uni-news-favorite/list',
+			'/uni_modules/uni-feedback/pages/uni-feedback/add'
 		],
+
 		/*
 		login:配置登陆类型与优先级
 			未列举到的,或设备环境不支持的选项,将被隐藏。如果你需要在不同平台有不同的配置,直接用条件编译即可
 			根据数组的第0项,决定登录方式的第一优先级。
 		*/
-		"login": ["username","smsCode","univerify", "weixin", "apple"],
+
+		'login': ['username', 'smsCode', 'univerify', 'weixin', 'apple']
 	},
-	//关于应用
-	"about": {
-		//应用名称
-		"appName": "uni-card",
-		//应用logo
-		"logo": "/static/logo.png",
-		//公司名称
-		"company": "常熟市畅享计算机信息技术有限公司",
-		//口号
-		"slogan": "云端一体应用快速开发模版",
-		//政策协议
-		"agreements": [{
-				"title": "用户服务协议", //协议名称
-				"url": "https://ask.dcloud.net.cn/protocol.html" //对应的网络链接
-			},
-			{
-				"title": "隐私政策",
-				"url": "https://ask.dcloud.net.cn/protocol.html"
-			}
-		],
-		//应用的链接,用于分享到第三方平台和生成关于我们页的二维码
-		"download": "https://m3w.cn/uniapp",
-		//version
-		"version":"1.0.0" //用于非app端显示,app端自动获取
+	// 关于应用
+	'about': {
+		// 应用名称
+		'appName': 'uni-card',
+		// 应用logo
+		'logo': '/static/logo.png',
+		// 公司名称
+		'company': '广东团蜂科技有限公司',
+		// 口号
+		'slogan': '科技成团,蜂创未来',
+		// 政策协议
+		'agreements': [{
+			'title': '用户服务协议', // 协议名称
+			'url': 'https://ask.dcloud.net.cn/protocol.html' // 对应的网络链接
+		},
+		{
+			'title': '隐私政策',
+			'url': 'https://ask.dcloud.net.cn/protocol.html'
+		}],
+		// 应用的链接,用于分享到第三方平台和生成关于我们页的二维码
+		'download': 'https://m3w.cn/uniapp',
+		// version
+		'version': '1.0.0' // 用于非app端显示,app端自动获取
 	},
-	"download":{ //用于生成二合一下载页面
-		"ios":"https://itunes.apple.com/cn/app/hello-uni-app/id1417078253?mt=8",
-		"android":"https://vkceyugu.cdn.bspapp.com/VKCEYUGU-97fca9f2-41f6-449f-a35e-3f135d4c3875/6d754387-a6c3-48ed-8ad2-e8f39b40fc01.apk"
+	'download': { // 用于生成二合一下载页面
+		'ios': 'https://itunes.apple.com/cn/app/hello-uni-app/id1417078253?mt=8',
+		'android': 'https://vkceyugu.cdn.bspapp.com/VKCEYUGU-97fca9f2-41f6-449f-a35e-3f135d4c3875/6d754387-a6c3-48ed-8ad2-e8f39b40fc01.apk'
 	},
-	//用于打开应用市场评分界面
-	"marketId":{
-		"ios":"id1417078253",
-		"android":"123456"
+	// 用于打开应用市场评分界面
+	'marketId': {
+		'ios': 'id1417078253',
+		'android': '123456'
 	}
 }

+ 64 - 0
utils/AnotherTFRequest.js

@@ -0,0 +1,64 @@
+import { ANOTHER_TF_INTERFACE } from '../config'
+import { T_STORAGE_KEY } from '../constant'
+import store from '../store'
+
+const request = (base_url) => function (url, data = {}, method = 'GET', cb, header = {}) {
+	return new Promise((resolve, reject) => {
+		header['Content-Type'] = 'application/json'
+		const res = uni.getStorageSync(T_STORAGE_KEY) || {}
+		if (res.token) header.Authorization = res.token
+		if (res.ssoUserInfo && res.ssoUserInfo.token) header['satoken-user'] = res.ssoUserInfo.token
+		// showLoading()
+		uni.request({
+			url: base_url + url,
+			data,
+			method,
+			header,
+			success: (res) => {
+				// console.log('拦截器', JSON.stringify(res))
+				// console.log('拦截器', res)
+				// hideLoading()
+				if (res.statusCode == 200) {
+					if (res.data.code === '200' || res.data.code === '') {
+						resolve(res.data)
+					} else if (res.data.code === '20004' || res.data.code === '20005') {
+						uni.showModal({
+							title: '提示',
+							content: '账号未登录,请重新登陆!',
+							success(res) {
+								if (res.confirm) {
+									store.dispatch('auth/logout')
+									setTimeout(() => {
+										uni.navigateTo({
+											url: '/pages/login/login'
+										})
+									}, 1000)
+								} else if (res.cancel) {
+									// uni.navigateBack();
+								}
+							}
+						})
+						reject(res.data)
+					} else {
+						uni.showToast({
+							title: res.data.message,
+							icon: 'none'
+						})
+						reject(res.data.message)
+					}
+				} else {
+					reject(res)
+				}
+			},
+			fail: (res) => {
+				// hideLoading()
+				reject(res)
+			},
+			complete: () => {
+				cb && typeof cb === 'function' && cb()
+			}
+		})
+	})
+}
+
+export const AnotherTFRequest = request(ANOTHER_TF_INTERFACE)

+ 386 - 0
utils/Commonutils.js

@@ -0,0 +1,386 @@
+// import { whoami } from '../api/auth'
+import { USER_ID, T_STORAGE_KEY, USER_INFO } from '../constant'
+// import { isNull } from 'lodash-es'
+
+/**
+ * @description 解决小数计算精度问题(en,你应该使用big.js)
+ * @param {Number, String} data 数字
+ * @param {Number} accuracy 保留几位小数
+ * @returns
+ */
+
+export const fomartNumber = (data, accuracy = 2) => {
+	const temp = data + ''
+	if (temp.includes('.')) {
+		return (data * 1).toFixed(accuracy)
+	}
+	return data
+}
+
+/**
+ * @description 批量清除缓存
+ * @param {String[]} cacheArr 要清除的缓存string数组
+ */
+
+export const removeCache = (cacheArr) => {
+	if (!Array.isArray(cacheArr)) {
+		return
+	}
+
+	for (const item of cacheArr) {
+		uni.removeStorageSync(item)
+	}
+}
+
+/**
+ * 检测登录是否有效
+ */
+
+export const checkWhoami = () => {
+	new Promise(async (resolve, reject) => {
+		const userId = getUserId()
+		const res = await whoami(userId)
+		if (res.errno !== 0) {
+			uni.navigateTo({
+				url: '/pages/login/login'
+			})
+		}
+	})
+}
+
+/**
+ * 获取用户userid
+ * @returns
+ */
+
+export const getUserId = () => {
+	const userId = uni.getStorageSync(USER_ID)
+	if (!userId) {
+		// uni.showToast({
+		//   title: "登录已失效,请重新登录",
+		//   duration: 2000,
+		//   icon: "none",
+		// });
+
+		// uni.navigateTo({
+		//   url: "/pages/login/login",
+		// });
+		uni.showModal({
+			title: '提示',
+			content: '您还未登录,是否去登录?',
+			success(res) {
+				if (res.confirm) {
+					uni.navigateTo({
+						url: '/pages/login/login'
+					})
+				} else if (res.cancel) {
+					// uni.navigateBack();
+				}
+			}
+		})
+		return
+	}
+	return userId
+}
+
+/**
+ * 获取新团蜂token
+ * @returns
+ */
+
+export const getStorageKeyToken = () => {
+	const userInfo = uni.getStorageSync(USER_INFO)
+	if (!userInfo || !userInfo.userId) {
+		return uni.showModal({
+			title: '提示',
+			content: '您还未登录,是否去登录?',
+			success(res) {
+				if (res.confirm) {
+					uni.navigateTo({
+						url: '/pages/login/login'
+					})
+				} else if (res.cancel) {
+					// uni.navigateBack();
+				}
+			}
+		})
+	}
+	if (!userInfo || !userInfo.phone) {
+		return uni.showModal({
+			title: '提示',
+			content: '未绑定手机号码,是否去绑定?',
+			success(res) {
+				if (res.confirm) {
+					uni.switchTab({
+						url: '/'
+					})
+				} else if (res.cancel) {
+					// uni.navigateBack();
+				}
+			}
+		})
+	}
+	const storageKey = uni.getStorageSync(T_STORAGE_KEY)
+	if (!storageKey || !storageKey.token) {
+		return uni.showModal({
+			title: '提示',
+			content: '系统出错,请重新登陆',
+			success(res) {
+				if (res.confirm) {
+					uni.navigateTo({
+						url: '/pages/login/login'
+					})
+				} else if (res.cancel) {
+					// uni.navigateBack();
+				}
+			}
+		})
+	}
+	return storageKey.token
+}
+
+/**
+ * 跳转到新团蜂入驻端项目
+ * @returns
+ */
+
+export const jumpToOtherProject = (url, cb = () => { }) => {
+	// #ifdef H5
+	window.location.href = url
+	// #endif
+	// #ifdef APP
+	plus.runtime.openURL(url, cb)
+	// #endif
+	// #ifdef MP
+	uni.redirectTo({
+		url: `/user/view?target=${url}`
+	})
+	// #endif
+}
+
+/**
+ * 点击复制
+ * @param {*} text
+ */
+
+export const useCopy = (text) => {
+	const input = document.createElement('input')
+	input.value = text
+	document.body.appendChild(input)
+	input.select()
+	document.execCommand('Copy')
+	document.body.removeChild(input)
+	uni.showToast({
+		title: '单号复制成功'
+	})
+}
+
+/**
+ * @description 防抖函数
+ * @param {*} func
+ * @param {*} wait
+ * @param {*} immediate
+ * @returns
+ */
+
+export function handleDebounce(func, wait, immediate) {
+	let timeout
+
+	return function () {
+		const context = this
+		const args = arguments
+
+		if (timeout) clearTimeout(timeout)
+		if (immediate) {
+			var callNow = !timeout
+			timeout = setTimeout(() => {
+				timeout = null
+			}, wait)
+			if (callNow) func.apply(context, args)
+		} else {
+			timeout = setTimeout(function () {
+				func.apply(context, args)
+			}, wait)
+		}
+	}
+}
+
+export function getRandom(min, max) {
+	return Math.floor(Math.random() * (max - min) + min)
+}
+
+export const randomRGB = () => {
+	const r = Math.floor(Math.random() * 255)
+	const g = Math.floor(Math.random() * 255)
+	const b = Math.floor(Math.random() * 255)
+	return `rgb(${r}, ${g}, ${b})`
+}
+
+export const timestampToTime = (timestamp) => {
+	// 时间戳为10位需*1000,时间戳为13位不需乘1000
+	// var date = new Date(timestamp * 1000);
+	var date = new Date(timestamp)
+	var Y = date.getFullYear() + '-'
+	var M = (date.getMonth() + 1 < 10 ? '0' + (date.getMonth() + 1) : date.getMonth() + 1) + '-'
+	var D = (date.getDate() < 10 ? '0' + date.getDate() : date.getDate()) + ' '
+	var h = date.getHours() + ':'
+	var m = date.getMinutes() + ':'
+	var s = date.getSeconds()
+	return Y + M + D + h + m + s
+	// console.log(timestampToTime(1670145353)); //2022-12-04 17:15:53
+}
+
+/**
+ * 时间格式化
+ */
+
+export const timeFormatting = (timeDifference) => {
+	// 天数
+	const day = Math.floor(timeDifference / 3600 / 24)
+	// 小时
+	const hr = Math.floor(timeDifference / 3600 % 24)
+	// 分钟
+	const min = Math.floor(timeDifference / 60 % 60)
+	// 秒
+	const sec = Math.floor(timeDifference % 60)
+	return {
+		day: day < 10 ? '0' + day : day,
+		hour: hr < 10 ? '0' + hr : hr,
+		min: min < 10 ? '0' + min : min,
+		sec: sec < 10 ? '0' + sec : sec
+	}
+}
+
+export const throttle = (fn, interval) => {
+	let lastTime = 0
+	const _throttle = function (...args) {
+		const nowTime = new Date().getTime()
+		const remainTime = interval - (nowTime - lastTime)
+		if (remainTime <= 0) {
+			fn.apply(this, args)
+			lastTime = nowTime
+		}
+	}
+	return _throttle
+}
+
+// 获取 微信 code
+// #ifdef H5
+export const getUrlCode = () => {
+	var url = location.search
+	var theRequest = new Object()
+	if (url.indexOf('?') != -1) {
+		var str = url.substr(1)
+		var strs = str.split('&')
+		for (var i = 0; i < strs.length; i++) {
+			theRequest[strs[i].split('=')[0]] = strs[i].split('=')[1]
+		}
+	}
+
+	console.log('code结果', theRequest)
+	return theRequest
+}
+// #endif
+
+// 判断当前是否处于微信环境
+export const isInWx = () => {
+	// #ifdef H5
+	var ua = navigator.userAgent.toLowerCase()
+	return ua.match(/MicroMessenger/i) == 'micromessenger'
+	// #endif
+
+	// #ifdef APP
+	return false
+	// #endif
+}
+
+/**
+ * 大数转小数 12345.123 = 1.23万
+ */
+
+export const convertToDecimal = (number) => {
+	if (!number || isNull(number)) return 0
+	if (number < 10000) {
+		return number.toString()
+	} else if (number < 100000000) {
+		const decimalNumber = (number / 10000).toFixed(2)
+		return decimalNumber + '万'
+	}
+	const decimalNumber = (number / 100000000).toFixed(2)
+	return decimalNumber + '亿'
+}
+
+export const isSubarray = (arr, subarr) => {
+	const mainSet = new Set(arr)
+	for (const element of subarr) {
+		if (!mainSet.has(element)) {
+			return false
+		}
+	}
+	return true
+}
+
+export const tradeOrderNo = function () {
+	const now = new Date()
+	const year = now.getFullYear()
+	let month = now.getMonth() + 1
+	let day = now.getDate()
+	let hour = now.getHours()
+	let minutes = now.getMinutes()
+	let seconds = now.getSeconds()
+	String(month).length < 2 ? month = Number('0' + month) : month
+	String(day).length < 2 ? day = Number('0' + day) : day
+	String(hour).length < 2 ? hour = Number('0' + hour) : hour
+	String(minutes).length < 2 ? minutes = Number('0' + minutes) : minutes
+	String(seconds).length < 2 ? seconds = Number('0' + seconds) : seconds
+	const yyyyMMddHHmmss = `${year}${month}${day}${hour}${minutes}${seconds}`
+	return yyyyMMddHHmmss + Math.random().toString(36)
+		.substr(2, 9)
+}
+
+/**
+ * 判断当前H5是否在webview中打开
+ */
+
+export const isH5InWebview = () => {
+	const ua = navigator.userAgent.toLowerCase()
+	return typeof ua === 'string' && (ua.includes('webview') || ua.includes('miniprogramhtmlwebview'))
+}
+
+/**
+ * 判断当前资源是否是视频格式
+ * @param {string} url
+ * @returns {boolean}
+ */
+
+// export function isVideo(url) {
+// 	// ['png', 'jpg', 'jpeg', 'bmp', 'gif','webp'] ['mp4', 'm2v', 'mkv', 'webm', 'ogg', 'flv']
+// 	const videoExtensions = ['.avi', '.wmv', '.mpg', '.mpeg', '.mov', '.rm', '.ram', '.swf', '.flv', '.mp4']
+// 	const lowercasedUrl = url.toLowerCase()
+// 	return videoExtensions.some(type => lowercasedUrl.includes(type))
+// }
+export function isVideoSource(src) {
+	// return ['.avi', '.wmv', '.mpg', '.mpeg', '.mov', '.rm', '.ram', '.swf', '.flv', '.mp4'].some((item) => src.indexOf(item) !== -1)
+	return ['.avi', '.wmv', '.mpg', '.mpeg', '.mov', '.rm', '.ram', '.swf', '.flv', '.mp4'].includes(src.substring(src.lastIndexOf('.')))
+}
+
+export const saveImg = (url, cb) => {
+	// #ifdef H5
+	const uniappA = document.createElement('a')
+	uniappA.download = ''
+	uniappA.href = url
+	document.body.appendChild(uniappA)
+	uniappA.click()
+	uniappA.remove()
+	cb && typeof cb === 'function' && cb()
+	// #endif
+
+	// #ifdef APP
+	uni.saveImageToPhotosAlbum({
+		filePath: url,
+		success() {
+			cb && typeof cb === 'function' && cb()
+		}
+	})
+	// #endif
+}

+ 66 - 0
utils/common/js/util.js

@@ -0,0 +1,66 @@
+import { USER_INFO } from '../../../constant'
+
+let _debounceTimeout = null
+let _throttleRunning = false
+
+/**
+ * 防抖
+ * @param {Function} 执行函数
+ * @param {Number} delay 延时ms
+ */
+
+export const debounce = (fn, delay = 500) => {
+	clearTimeout(_debounceTimeout)
+	_debounceTimeout = setTimeout(() => {
+		fn()
+	}, delay)
+}
+
+/**
+ * 节流
+ * @param {Function} 执行函数
+ * @param {Number} delay 延时ms
+ */
+
+export const throttle = (fn, delay = 500) => {
+	if (_throttleRunning) {
+		return
+	}
+	_throttleRunning = true
+	fn()
+	setTimeout(() => {
+	    _throttleRunning = false
+	}, delay)
+}
+
+/**
+ * toast
+ */
+
+export const msg = (title = '', param = {}) => {
+	if (!title) return
+	uni.showToast({
+		title,
+		duration: param.duration || 1500,
+		mask: param.mask || false,
+		icon: param.icon || 'none'
+	})
+}
+
+/**
+ * 检查登录
+ * @return {Boolean}
+ */
+
+export const isLogin = (options = {}) => {
+	const userInfo = uni.getStorageSync(USER_INFO)
+	if (userInfo) {
+		return true
+	}
+	if (options.nav !== false) {
+		uni.navigateTo({
+			url: '/pages/login'
+		})
+	}
+	return false
+}

+ 0 - 0
common/util.js → utils/common/util.js


+ 24 - 0
utils/index.js

@@ -0,0 +1,24 @@
+export { AnotherTFRequest } from './AnotherTFRequest.js'
+export {
+	fomartNumber,
+	removeCache,
+	getUserId,
+	getStorageKeyToken,
+	checkWhoami,
+	useCopy,
+	handleDebounce,
+	getRandom,
+	randomRGB,
+	timestampToTime,
+	timeFormatting,
+	throttle,
+	isInWx,
+	isVideoSource,
+	convertToDecimal,
+	isSubarray,
+	tradeOrderNo,
+	jumpToOtherProject,
+	isH5InWebview,
+	isVideo,
+	saveImg
+} from './Commonutils'

+ 45 - 0
utils/request.js

@@ -0,0 +1,45 @@
+/**
+ * @param {String} cloudFnName
+ * @param {String} operation  操作类型(增删改查)
+ * @param {Object} data 请求参数
+ * @param {Object} ext 附加参数
+ */
+
+export const request = (cloudFnName, operation, data = {}, ext = {}) => new Promise((resolve, reject) => {
+	if (ext.showLoading !== false) {
+		uni.showLoading()
+	}
+	uniCloud.callFunction({
+		name: cloudFnName,
+		data: {
+			operation,
+			data
+		}
+	}).then((res) => {
+		if (ext.showLoading !== false) {
+			uni.hideLoading()
+		}
+		if (res.result.code != 200) {
+			uni.showToast({
+				icon: 'none',
+				title: res.result.msg,
+				duration: 2000
+			})
+			reject(res.result.msg)
+		} else {
+			console.log('requestResult', res)
+			resolve(res.result.data)
+		}
+	})
+		.catch((err) => {
+			if (ext.showLoading !== false) {
+				uni.hideLoading()
+			}
+			uni.showToast({
+				icon: 'none',
+				title: err.toString().replace('Error:', ''),
+				duration: 2000
+			})
+			reject(err)
+		})
+})