Commit c1dbe7b8 by yewills

feat: 初始出来的项目接入业务后,修改的代码

parent 3fc4f2db
# uniapp-project # 拼团小程序
## Project setup ## Project setup
``` ```
...@@ -57,21 +57,6 @@ npm run prepare ...@@ -57,21 +57,6 @@ npm run prepare
响应拦截中有未登录处理,错误处理等。 响应拦截中有未登录处理,错误处理等。
```javascript
// Promise 写法
this.$request.get('xxx').then(res => {})
// async/await 写法
const res = await this.$request.post('xxx')
// 传参
const params = {}
this.$request.get('xxx', {
params
})
this.$request.post('xxx', params)
```
## 登录 ## 登录
提供了 `phone-login` 组件,用来调用手机号授权登录 提供了 `phone-login` 组件,用来调用手机号授权登录
...@@ -80,26 +65,7 @@ this.$request.post('xxx', params) ...@@ -80,26 +65,7 @@ this.$request.post('xxx', params)
## 埋点 ## 埋点
目前前端的埋点库还不支持小程序,所以在 `utils/util.js` 里面封装了一个埋点请求,`sendTrackData`. 目前前端的埋点库还不支持小程序,所以在 `utils/util.js` 里面封装了一个埋点请求,`sendTrackData`
埋点封装的函数中的 `app_name` 参数需要根据实际项目定义填写进去。
埋点示例如下:
```javascript
setTrackData({
events: [
{
event_id: 'page_visit',
event_custom_properties: {
part: 'xxx',
position: '',
element: '',
},
},
],
})
```
## 代码风格 ## 代码风格
......
...@@ -73,7 +73,9 @@ ...@@ -73,7 +73,9 @@
"axios": "^0.27.2", "axios": "^0.27.2",
"axios-adapter-uniapp": "^0.1.4", "axios-adapter-uniapp": "^0.1.4",
"core-js": "^3.6.5", "core-js": "^3.6.5",
"dayjs": "^1.11.7",
"flyio": "^0.6.2", "flyio": "^0.6.2",
"lodash": "^4.17.21",
"uview-ui": "^2.0.35", "uview-ui": "^2.0.35",
"vue": "^2.6.11", "vue": "^2.6.11",
"vuex": "^3.2.0" "vuex": "^3.2.0"
......
<script> <script>
import { setTrackData } from '@/utils/util'
export default { export default {
onLaunch: function () { onLaunch: function (e) {
console.log('App Launch') console.log('App Launch', e)
// 获取openId
if (!this.$store.state.user.openId) {
this.$store.dispatch('user/getOpenId')
}
// 小程序launch埋点
const part = {
'pages/home/home': 'listener_list_page',
'pages/confide/confide': `listener_detail_${e.query.listenerId}`,
}
if (part[e.path]) {
setTrackData({
events: [
{
event_id: 'app_activation',
event_custom_properties: {
part: part[e.path],
position: '',
element: '',
traffic_source_type: e.query.fromOpenId ? 3 : '', // 3代表小程序分享流量,空代表自然流量
traffic_source: e.query.fromOpenId || '',
},
},
],
})
}
}, },
onShow: function () { onShow: function () {
console.log('App Show') console.log('App Show')
...@@ -14,6 +41,7 @@ export default { ...@@ -14,6 +41,7 @@ export default {
<style lang="scss"> <style lang="scss">
@import 'uview-ui/index.scss'; @import 'uview-ui/index.scss';
@import '@/style/common.scss';
uni-page-body, uni-page-body,
html, html,
body { body {
......
<template>
<view>
<audio
style="text-align: left"
:src="current.src"
:poster="current.poster"
:name="current.name"
:author="current.author"
:action="audioAction"
controls
></audio>
</view>
</template>
<script>
export default {
props: {
audioSrc: {
type: String,
required: true,
},
},
}
</script>
<style></style>
...@@ -23,10 +23,10 @@ export default { ...@@ -23,10 +23,10 @@ export default {
} }
}, },
async mounted() { async mounted() {
// 获取最新code
if (!this.$store.state.user.code) { if (!this.$store.state.user.code) {
this.uniLogin() this.uniLogin()
} else { } else {
// eslint-disable-next-line
uni.checkSession({ uni.checkSession({
success: res => { success: res => {
if (res.errMsg !== 'checkSession:ok') { if (res.errMsg !== 'checkSession:ok') {
...@@ -37,10 +37,12 @@ export default { ...@@ -37,10 +37,12 @@ export default {
} }
}, },
methods: { methods: {
// 获取手机号
async getPhoneNumber({ detail: { errMsg, encryptedData, iv } }) { async getPhoneNumber({ detail: { errMsg, encryptedData, iv } }) {
if (errMsg === 'getPhoneNumber:ok') { if (errMsg === 'getPhoneNumber:ok') {
try { try {
this.loading = true this.loading = true
// 登录
await this.$store.dispatch('user/login', { await this.$store.dispatch('user/login', {
encryptedData, encryptedData,
iv, iv,
...@@ -54,7 +56,6 @@ export default { ...@@ -54,7 +56,6 @@ export default {
this.loading = false this.loading = false
} }
} else { } else {
// eslint-disable-next-line
uni.showToast({ uni.showToast({
title: '获取手机号失败', title: '获取手机号失败',
duration: 3000, duration: 3000,
......
...@@ -2,16 +2,26 @@ const isDevelopment = process.env.NODE_ENV === 'development' ...@@ -2,16 +2,26 @@ const isDevelopment = process.env.NODE_ENV === 'development'
let hostPrefix let hostPrefix
let apiPrefix let apiPrefix
let h2Prefix
let ydlH5Prefix
if (isDevelopment) { if (isDevelopment) {
hostPrefix = 'https://testnewm.ydl.com' // hostPrefix = 'https://testnewm.ydl.com'
apiPrefix = 'https://testapi.ydl.com' // apiPrefix = 'https://testapi.ydl.com'
hostPrefix = 'https://newm-test.ydl.com' // 下云
apiPrefix = 'https://api-test.ydl.com' // 下云
h2Prefix = 'https://h2.yidianling.com'
ydlH5Prefix = 'https://testh5.ydl.com'
} else { } else {
hostPrefix = 'https://m.ydl.com' hostPrefix = 'https://m.ydl.com'
apiPrefix = 'https://api.ydl.com' apiPrefix = 'https://api.ydl.com'
h2Prefix = 'https://h2.yidianling.com'
ydlH5Prefix = 'https://h5.ydl.com'
} }
module.exports = { module.exports = {
hostPrefix, hostPrefix,
apiPrefix, apiPrefix,
h2Prefix,
ydlH5Prefix,
} }
...@@ -3,11 +3,13 @@ import App from '@/App' ...@@ -3,11 +3,13 @@ import App from '@/App'
import store from '@/store' import store from '@/store'
import request from '@/plugins/request.js' import request from '@/plugins/request.js'
import uView from 'uview-ui' import uView from 'uview-ui'
import dayjs from 'dayjs'
Vue.config.productionTip = false Vue.config.productionTip = false
Vue.prototype.$store = store Vue.prototype.$store = store
Vue.prototype.$request = request Vue.prototype.$request = request
Vue.prototype.$dayjs = dayjs
Vue.use(uView) Vue.use(uView)
......
{ {
"name": "", "name" : "壹点拼团",
"appid": "", "appid" : "",
"description": "", "description" : "",
"versionName": "1.0.0", "versionName" : "1.0.0",
"versionCode": "100", "versionCode" : "100",
"transformPx": false, "transformPx" : false,
"app-plus": { /* 5+App特有相关 */ "app-plus" : {
"usingComponents": true, /* 5+App特有相关 */
"splashscreen": { "usingComponents" : true,
"alwaysShowBeforeRender": true, "splashscreen" : {
"waiting": true, "alwaysShowBeforeRender" : true,
"autoclose": true, "waiting" : true,
"delay": 0 "autoclose" : true,
}, "delay" : 0
"modules": { /* 模块配置 */ },
"modules" : {},
}, /* 模块配置 */
"distribute": { /* 应用发布信息 */ "distribute" : {
"android": { /* android打包配置 */ /* 应用发布信息 */
"permissions": ["<uses-permission android:name=\"android.permission.CHANGE_NETWORK_STATE\"/>", "android" : {
"<uses-permission android:name=\"android.permission.MOUNT_UNMOUNT_FILESYSTEMS\"/>", /* android打包配置 */
"<uses-permission android:name=\"android.permission.READ_CONTACTS\"/>", "permissions" : [
"<uses-permission android:name=\"android.permission.VIBRATE\"/>", "<uses-permission android:name=\"android.permission.CHANGE_NETWORK_STATE\"/>",
"<uses-permission android:name=\"android.permission.READ_LOGS\"/>", "<uses-permission android:name=\"android.permission.MOUNT_UNMOUNT_FILESYSTEMS\"/>",
"<uses-permission android:name=\"android.permission.ACCESS_WIFI_STATE\"/>", "<uses-permission android:name=\"android.permission.READ_CONTACTS\"/>",
"<uses-feature android:name=\"android.hardware.camera.autofocus\"/>", "<uses-permission android:name=\"android.permission.VIBRATE\"/>",
"<uses-permission android:name=\"android.permission.WRITE_CONTACTS\"/>", "<uses-permission android:name=\"android.permission.READ_LOGS\"/>",
"<uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\"/>", "<uses-permission android:name=\"android.permission.ACCESS_WIFI_STATE\"/>",
"<uses-permission android:name=\"android.permission.CAMERA\"/>", "<uses-feature android:name=\"android.hardware.camera.autofocus\"/>",
"<uses-permission android:name=\"android.permission.RECORD_AUDIO\"/>", "<uses-permission android:name=\"android.permission.WRITE_CONTACTS\"/>",
"<uses-permission android:name=\"android.permission.GET_ACCOUNTS\"/>", "<uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\"/>",
"<uses-permission android:name=\"android.permission.MODIFY_AUDIO_SETTINGS\"/>", "<uses-permission android:name=\"android.permission.CAMERA\"/>",
"<uses-permission android:name=\"android.permission.READ_PHONE_STATE\"/>", "<uses-permission android:name=\"android.permission.RECORD_AUDIO\"/>",
"<uses-permission android:name=\"android.permission.CHANGE_WIFI_STATE\"/>", "<uses-permission android:name=\"android.permission.GET_ACCOUNTS\"/>",
"<uses-permission android:name=\"android.permission.WAKE_LOCK\"/>", "<uses-permission android:name=\"android.permission.MODIFY_AUDIO_SETTINGS\"/>",
"<uses-permission android:name=\"android.permission.CALL_PHONE\"/>", "<uses-permission android:name=\"android.permission.READ_PHONE_STATE\"/>",
"<uses-permission android:name=\"android.permission.FLASHLIGHT\"/>", "<uses-permission android:name=\"android.permission.CHANGE_WIFI_STATE\"/>",
"<uses-permission android:name=\"android.permission.ACCESS_COARSE_LOCATION\"/>", "<uses-permission android:name=\"android.permission.WAKE_LOCK\"/>",
"<uses-feature android:name=\"android.hardware.camera\"/>", "<uses-permission android:name=\"android.permission.CALL_PHONE\"/>",
"<uses-permission android:name=\"android.permission.ACCESS_FINE_LOCATION\"/>", "<uses-permission android:name=\"android.permission.FLASHLIGHT\"/>",
"<uses-permission android:name=\"android.permission.WRITE_SETTINGS\"/>" "<uses-permission android:name=\"android.permission.ACCESS_COARSE_LOCATION\"/>",
] "<uses-feature android:name=\"android.hardware.camera\"/>",
}, "<uses-permission android:name=\"android.permission.ACCESS_FINE_LOCATION\"/>",
"ios": { /* ios打包配置 */ "<uses-permission android:name=\"android.permission.WRITE_SETTINGS\"/>"
]
}, },
"sdkConfigs": { /* SDK配置 */ "ios" : {},
/* ios打包配置 */
} "sdkConfigs" : {}
} }
}, },
"quickapp": { /* 快应用特有相关 */ /* SDK配置 */
"quickapp" : {},
}, /* 快应用特有相关 */
"mp-weixin": { /* 微信小程序特有相关 */ "mp-weixin" : {
"appid": "wx1106c32a36d87d49", "appid" : "",
"setting": { "setting" : {
"urlCheck": false "urlCheck" : false,
}, "es6" : false,
"usingComponents": true "postcss" : true,
}, "minified" : true
"mp-alipay" : { },
"usingComponents" : true "usingComponents" : true
}, },
"mp-baidu" : { "mp-alipay" : {
"usingComponents" : true "usingComponents" : true
}, },
"mp-toutiao" : { "mp-baidu" : {
"usingComponents" : true "usingComponents" : true
}, },
"mp-qq" : { "mp-toutiao" : {
"usingComponents" : true "usingComponents" : true
} },
} "mp-qq" : {
"usingComponents" : true
}
}
...@@ -4,25 +4,68 @@ ...@@ -4,25 +4,68 @@
}, },
"pages": [ "pages": [
{ {
"path" : "pages/home/home", "path": "pages/home/home",
"style" : "style": {
{
"navigationBarTitleText": "首页", "navigationBarTitleText": "首页",
"enablePullDownRefresh": false "enablePullDownRefresh": false
} }
}, },
{ {
"path" : "pages/my/my", "path": "pages/home/expert-search",
"style" : "style": {
{ "navigationBarTitleText": "搜索",
"navigationBarTitleText": "我的", "enablePullDownRefresh": false
}
},
{
"path": "pages/my/my",
"style": {
"navigationStyle": "custom",
"navigationBarTextStyle": "black",
"enablePullDownRefresh": false
}
},
{
"path": "pages/web/web",
"style": {
"enablePullDownRefresh": false
}
},
{
"path": "pages/login/login",
"style": {
"navigationStyle": "custom",
"navigationBarTextStyle": "black",
"enablePullDownRefresh": false
}
},
{
"path": "pages/order/order",
"style": {
"navigationBarTitleText": "我的订单",
"enablePullDownRefresh": true,
"onReachBottomDistance": 50
}
},
{
"path": "pages/confide/confide",
"style": {
"navigationStyle": "custom",
"navigationBarTextStyle": "black",
"enablePullDownRefresh": false
}
},
{
"path": "pages/pay/pay",
"style": {
"navigationBarTitleText": "支付",
"enablePullDownRefresh": false "enablePullDownRefresh": false
} }
} }
], ],
"globalStyle": { "globalStyle": {
"navigationBarTextStyle": "black", "navigationBarTextStyle": "black",
"navigationBarTitleText": "壹点灵心理咨询", "navigationBarTitleText": "壹点拼团",
"navigationBarBackgroundColor": "#ffffff", "navigationBarBackgroundColor": "#ffffff",
"backgroundColor": "#ffffff", "backgroundColor": "#ffffff",
"backgroundTextStyle": "dark" "backgroundTextStyle": "dark"
...@@ -35,11 +78,15 @@ ...@@ -35,11 +78,15 @@
"list": [ "list": [
{ {
"text": "首页", "text": "首页",
"pagePath": "pages/home/home" "pagePath": "pages/home/home",
"iconPath": "/static/tab_home.png",
"selectedIconPath": "/static/tab_home_selected.png"
}, },
{ {
"text": "我的", "text": "我的",
"pagePath": "pages/my/my" "pagePath": "pages/my/my",
"iconPath": "/static/tab_my.png",
"selectedIconPath": "/static/tab_my_selected.png"
} }
] ]
} }
......
<template> <template>
<view class="content"> <view class="container home">
<image <!-- 筛选条件 -->
class="logo" <screen-box
src="/static/logo.png" :url-params="urlParams"
></image> :allow-home-scroll.sync="allowHomeScroll"
<view> @screenDoctor="onScreenDoctor"
<text class="title">{{ title }}</text> ></screen-box>
<!-- 专家列表 -->
<scroll-view
v-if="doctorArr.length"
class="consult-list box-c"
:scroll-y="allowHomeScroll"
:refresher-enabled="true"
:refresher-triggered="scrollBottomRefresher"
:refresher-threshold="100"
@refresherrefresh="onRefresh"
@scrolltolower="handleScrollBottom"
>
<block
v-for="item in doctorArr"
:key="item.uid"
>
<doctor-item
:data-item="item"
:item="item"
:is-login="isLogin"
:current-doctor="currentDoctor.confidedId"
:play-status="playStatus"
@tap="toDetail(item)"
@player="playAudio"
/>
</block>
<view class="load-more">{{ !paging.hasMore ? '没有更多了~' : '加载中...' }}</view>
</scroll-view>
<view
v-else
class="no-data"
>
<view v-if="isLoaded">
<image
mode="aspectFill"
class="icon-find"
src="https://static.ydlcdn.com/weixin/image/home/no_data.png"
/>
<view class="c-666">未搜索到对应专家,请查询其他条件试试</view>
</view>
<view v-else>加载中...</view>
</view>
<view
v-if="playStatus"
class="player"
>
<view class="player-content">
<view
class="close-player"
@click="closePlayer"
>
<img
class="player-icon"
src="https://static.ydlcdn.com/mini/mini_confide/confide_icon_close.png"
alt=""
/>
</view>
<view class="player-info">
<image
class="player-cover"
mode="aspectFill"
:src="currentDoctor.confidedIcon"
/>
<view>
<view class="player-title">壹点倾诉,心灵寄语</view>
<view class="player-user">
<text class="player-user-name">{{ currentDoctor.confidedName }}</text>
<text
v-show="playStartTime && playEndTime"
class="player-user-time"
>
{{ playStartTime }} / {{ playEndTime }}
</text>
</view>
</view>
</view>
<view
class="pause-player"
@click="pausePlayer"
>
<img
class="player-icon"
:src="
isPausePlay
? 'https://static.ydlcdn.com/mini/mini_confide/confide_icon_play.png'
: 'https://static.ydlcdn.com/mini/mini_confide/confide_icon_pause.png'
"
alt=""
/>
</view>
</view>
</view> </view>
</view> </view>
</template> </template>
<script> <script>
/* eslint-disable no-undef */
import ScreenBox from '@/components/expert-screen'
import DoctorItem from '@/components/expert-item'
import { setTrackData } from '@/utils/util'
const innerAudioContext = uni.createInnerAudioContext()
export default { export default {
name: 'HomePage', name: 'ExpertPage',
components: {
ScreenBox,
DoctorItem,
},
data() { data() {
return { return {
title: 'Hello', allowHomeScroll: true,
scrollBottomRefresher: false,
fromOpenId: '', // 从分享进入时所携带分享人的openid
isLoaded: false,
isFixed: true,
statistics: null,
doctorArr: [],
userInfo: {}, // 用户信息
paging: {
hasMore: true,
extras: null,
},
preScreen: {}, // 筛选信息
isLogin: false,
urlParams: {},
currentDoctor: {},
playStatus: false,
isPausePlay: false,
playStartTime: '',
playEndTime: '',
} }
}, },
onLoad() {},
methods: {}, onLoad(options) {
// 进入小程序判断是否携带参数
if (options && options.searchWord) {
this.urlParams = options
this.preScreen.keywords = options.searchWord
}
this.init()
// 咨询师列表访问埋点
setTrackData({
events: [
{
event_id: 'page_visit',
event_custom_properties: {
part: 'listener_list_page ',
position: '',
element: '',
},
},
],
})
},
onPullDownRefresh() {
this.onRefresh()
},
methods: {
// 下拉刷新
onRefresh() {
// 开启下拉刷新
this.scrollBottomRefresher = true
this.paging.extras = null
this.init()
setTimeout(() => {
// 停止下拉刷新
uni.stopPullDownRefresh()
this.scrollBottomRefresher = false
}, 1000)
},
handleScrollBottom() {
// 滚动到底部加载更多数据
if (!this.paging.hasMore) return
this.getData()
},
init() {
this.getData(true)
const accessToken = uni.getStorageSync('accessToken')
this.isLogin = !!accessToken
},
onLoginEvent(e) {
if (e.detail.accessToken) {
this.isLogin = true
}
},
onScreenDoctor(e = {}) {
// 筛选组件回调
this.preScreen = e
this.paging = {
hasMore: true,
}
uni.pageScrollTo({
scrollTop: 0,
})
this.getData(true)
},
async getData(isReset) {
let { doctorArr } = this
// dmp接口入参配置
const res = await this.$request
.get('smart-rank/v1/search-adapter/listeners', {
params: {
...this.preScreen,
extras: this.paging ? this.paging.extras || null : null, // 分页参数,将上一页返回的 extras 传到这里,没有上一页则不传
},
})
.finally(() => (this.loading = false))
const { body } = res
if (isReset) {
doctorArr = []
}
this.doctorArr = doctorArr.concat(body)
// 接口返回数据并且长度大于每页条数,可滚动加载
this.paging.hasMore = !!(Array.isArray(body) && body.length > 9)
this.paging.extras = res.extras
this.isLoaded = true
},
// 跳转详情页
toDetail(e) {
if (!e.confidedId) {
return uni.showToast('专家数据错误')
}
uni.navigateTo({
url: `/pages/confide/confide?listenerId=${e.confidedId}`,
})
},
onShareAppMessage() {
const openId = this.$store.state.user.openId
setTrackData({
events: [
{
event_id: 'common_click',
event_custom_properties: {
part: 'listener_list_page',
position: 'top_column',
element: 'share_friends',
},
},
],
})
return {
title: '倾诉师推荐',
path: `/pages/home/home?fromOpenId=${openId}${
this.preScreen.keywords ? '&searchWord=' + this.preScreen.keywords : ''
}`,
}
},
onShareTimeline() {
setTrackData({
events: [
{
event_id: 'common_click',
event_custom_properties: {
part: 'listener_list_page',
position: 'top_column',
element: 'share_moments',
},
},
],
})
return {
title: '倾诉师推荐-壹点灵心理',
query: {
fromOpenId: this.$store.state.user.openId,
searchWord: this.preScreen.keywords,
},
}
},
// 格式化音频时长
formatTime: function (s) {
let t = ''
s = Math.floor(s)
if (s > -1) {
const min = Math.floor(s / 60) % 60
const sec = s % 60
if (min < 10) {
t += '0'
}
t += min + ':'
if (sec < 10) {
t += '0'
}
t += sec
}
return t
},
closePlayer() {
this.playStatus = false
innerAudioContext.stop()
},
pausePlayer() {
if (!this.isPausePlay) {
innerAudioContext.pause()
} else {
innerAudioContext.play()
}
this.isPausePlay = !this.isPausePlay
},
// 播放音频
playAudio(item) {
var audioUrl = item.confideVoice
this.currentDoctor = item
if (item.isPlayer) {
this.playStatus = false
this.isPausePlay = false
innerAudioContext.stop()
return
}
this.playStatus = true
this.isPausePlay = false
innerAudioContext.stop()
innerAudioContext.autoplay = false
innerAudioContext.src = audioUrl
innerAudioContext.play()
innerAudioContext.onPlay(() => {
console.log('开始播放', innerAudioContext.duration)
setTimeout(() => {
// 设置音频总时长
this.playEndTime = this.formatTime(Math.ceil(innerAudioContext.duration))
}, 300)
})
innerAudioContext.onTimeUpdate(() => {
// 音频跟新时若总时长未获取则重新获取
if (!this.playEndTime) {
this.playEndTime = this.formatTime(Math.ceil(innerAudioContext.duration))
}
console.log('更新播放', innerAudioContext.duration)
// 跟新音频播放时长
this.playStartTime = this.formatTime(Math.ceil(innerAudioContext.currentTime))
})
innerAudioContext.onError(res => {
console.log(res.errMsg, '播放出错', res.errCode)
this.playStatus = false
})
innerAudioContext.onPause(() => {
console.log('播放暂停')
})
innerAudioContext.onEnded(() => {
console.log('播放结束')
this.playStatus = false
this.isPausePlay = false
this.playStartTime = '00:00'
})
},
},
} }
</script> </script>
<style lang="less" scoped> <style lang="less" scoped>
.content { .home {
display: flex; position: relative;
flex-direction: column; background: #fff;
align-items: center; padding: 94px 0 0 0;
justify-content: center; height: 100%;
} }
.consult-list {
.logo { width: 100%;
height: 200rpx; height: 100%;
width: 200rpx;
margin: 200rpx auto 50rpx auto;
} }
.icon-find {
.text-area { width: 100%;
display: flex;
justify-content: center;
} }
.no-data,
.load-more {
text-align: center;
padding: 20px;
}
.player {
position: fixed;
width: 100%;
bottom: 60px;
left: 0;
padding: 16px;
&-content {
width: 100%;
color: #fff;
background: rgba(0, 0, 0, 0.8);
border-radius: 8px;
padding: 8px 20px 8px 8px;
display: flex;
align-items: center;
.player-cover {
width: 40px;
height: 40px;
margin-right: 12px;
border-radius: 4px;
}
}
.player-info {
width: 100%;
display: flex;
align-items: center;
}
.player-title {
font-size: 16px;
line-height: 20px;
margin-bottom: 4px;
}
.player-user {
display: flex;
font-size: 12px;
line-height: 16px;
color: rgba(255, 255, 255, 0.6);
&-name {
::after {
content: '';
border-right: 0.5px solid rgba(255, 255, 255, 0.9);
height: 8px;
padding-right: 8px;
margin-right: 8px;
}
}
}
.close-player {
margin-right: 8px;
.player-icon {
width: 32px;
height: 32px;
vertical-align: middle;
}
}
.title { .player-icon {
font-size: 36rpx; width: 16px;
color: #8f8f94; height: 16px;
vertical-align: middle;
}
} }
</style> </style>
<template> <template>
<view> <view class="my-page">
<phone-login></phone-login> <u-navbar
title="我的"
left-icon=" "
:title-style="{ 'font-weight': 'bold', 'font-size': '18px' }"
fixed
placeholder
bg-color="transparent"
></u-navbar>
<view class="user-info">
<image
v-if="userInfo.head"
class="head-image"
:src="userInfo.head"
/>
<image
v-else
class="head-image"
src="https://static.ydlcdn.com/mini/mini_consult/pic_default_avatar.png"
@click="handleLoginClick"
/>
<text
v-if="isLogin"
class="user-name"
>
{{ userInfo.nickName }}
</text>
<view
v-else
@click="handleLoginClick"
>
<text class="user-name">未登录</text>
<text class="login-tips">点此登录</text>
</view>
</view>
<view class="list-box">
<template v-for="menu in menus">
<view
v-if="!menu.needLogin || isLogin"
:key="menu.label"
class="list-item"
@click="handleMenuItemClick(menu)"
>
<image
:src="menu.icon"
class="item-icon"
/>
<text class="item-label">{{ menu.label }}</text>
<image
src="/static/icon_arrow_right.png"
class="arrow-right"
/>
</view>
</template>
</view>
<u-modal
:show="logoutVisible"
confirm-text="退出登录"
:show-cancel-button="true"
width="72vw"
@cancel="logoutVisible = false"
@confirm="handleLogoutConfirm"
>
<view class="slot-content">
<view class="logout-tip-text">是否退出登录?</view>
</view>
</u-modal>
</view> </view>
</template> </template>
<script> <script>
import PhoneLogin from '@/components/phone-login.vue' import { hostPrefix, h2Prefix } from '@/config'
import { setTrackData } from '@/utils/util'
export default { export default {
name: 'MyPage', name: 'MyPage',
components: {
PhoneLogin,
},
data() { data() {
return {} return {
menus: [
{
icon: '/static/icon_order.png',
label: '我的订单',
callback: () => {
this.handleSendMenuTrackData('我的订单')
this.navigateToOrder()
},
},
{
icon: '/static/icon_help_center.png',
label: '帮助中心',
callback: () => {
this.handleSendMenuTrackData('帮助中心')
uni.navigateTo({
url: `/pages/web/web?title=帮助中心&loadUrl=${encodeURIComponent(
`${h2Prefix}/help/list/12`,
)}`,
})
},
},
{
icon: '/static/icon_custom_service.png',
label: '联系客服',
callback: () => {
this.handleSendMenuTrackData('联系客服')
uni.makePhoneCall({
phoneNumber: '4007651010',
})
},
},
{
icon: '/static/icon_introduction.png',
label: '壹点灵介绍',
callback: () => {
this.handleSendMenuTrackData('壹点灵介绍')
uni.navigateTo({
url: `/pages/web/web?title=壹点灵介绍&loadUrl=${encodeURIComponent(
`${hostPrefix}/about`,
)}`,
})
},
},
{
icon: '/static/icon_logout.png',
label: '退出登录',
needLogin: true,
callback: () => {
this.handleSendMenuTrackData('退出登录')
this.logoutVisible = true
},
},
],
logoutVisible: false,
}
},
computed: {
// 用户基本信息
userInfo() {
return this.$store.getters.userInfo
},
// 是否登录
isLogin() {
return this.$store.getters.isLogin
},
},
mounted() {
// 页面访问埋点
setTrackData({
events: [
{
event_id: 'page_visit',
event_custom_properties: {
part: 'ydl_user_my_page',
position: '',
element: '',
},
},
],
})
},
methods: {
// 菜单项的埋点
handleSendMenuTrackData(content) {
setTrackData({
events: [
{
event_id: 'content_click',
event_custom_properties: {
part: 'ydl_user_my_page',
position: 'other_list',
element: 'other_column',
content,
},
},
],
})
},
// 登录点击事件
handleLoginClick() {
setTrackData({
events: [
{
event_id: 'common_click',
event_custom_properties: {
part: 'ydl_user_my_page',
position: 'avatar_column',
element: 'login',
},
},
],
})
this.handleLogin()
},
// 跳转登录
handleLogin() {
uni.navigateTo({
url: '/pages/login/login',
})
},
// 菜单点击
handleMenuItemClick({ callback }) {
callback && callback()
},
// 退出登录
handleLogoutConfirm() {
this.logoutVisible = false
this.$store.commit('user/setUserInfo', {})
this.$store.commit('user/setCode', '')
this.$store.commit('user/setUid', '')
this.$store.commit('user/setAccessToken', '')
},
// 跳转订单
navigateToOrder() {
if (!this.isLogin) {
this.handleLogin()
return
}
uni.navigateTo({
url: '/pages/order/order',
})
},
}, },
methods: {},
} }
</script> </script>
<style></style> <style lang="less" scoped>
.my-page {
height: 100%;
background: linear-gradient(to bottom, #f3faff 0%, #f7f7f7 70%, #f7f7f7 100%);
.user-info {
padding: 20px 20px 29px;
display: flex;
align-items: center;
.head-image {
width: 60px;
height: 60px;
border-radius: 50%;
}
.user-name {
margin-left: 16px;
color: #000000;
font-weight: 500;
font-size: 18px;
margin-bottom: 4px;
}
.login-tips {
margin-left: 16px;
display: block;
font-size: 15px;
color: #6ec8f9;
line-height: 21px;
}
}
.list-box {
padding: 0 16px;
.list-item {
padding: 0 16px;
height: 60px;
display: flex;
align-items: center;
border-radius: 8px;
background-color: #ffffff;
margin-top: 16px;
.item-icon {
width: 24px;
height: 24px;
margin-right: 7px;
}
.item-label {
color: #000000;
font-weight: 400;
font-size: 16px;
flex: 1;
}
.arrow-right {
width: 12px;
height: 13px;
}
}
}
.logout-tip-text {
font-size: 4.8vw;
line-height: 1.4;
}
/* modal 弹窗按钮样式 */
.u-modal__button-group__wrapper__text {
font-size: 4.8vw !important;
}
}
</style>
...@@ -32,10 +32,14 @@ service.interceptors.response.use(async res => { ...@@ -32,10 +32,14 @@ service.interceptors.response.use(async res => {
store.dispatch('user/uniLogin') store.dispatch('user/uniLogin')
} }
if (res.status === 200 && res.data) { if (res.status === 200 && res.data) {
// 有些接口处理逻辑中可能需要根据code进行判断,这里根据raw字段返回全部的数据
if (res.config && res.config.raw) return Promise.resolve(res.data)
const code = +res.data.code const code = +res.data.code
if (code === 200) { if (code === 200) {
// 默认返回的是data字段
return Promise.resolve(res.data.data) return Promise.resolve(res.data.data)
} else if (code === 401) { } else if (code === 401) {
// 未登录,清除用户信息
clearUserInfo() clearUserInfo()
uni.showToast({ uni.showToast({
title: '请先登录', title: '请先登录',
...@@ -43,6 +47,7 @@ service.interceptors.response.use(async res => { ...@@ -43,6 +47,7 @@ service.interceptors.response.use(async res => {
}) })
return Promise.reject(new Error('unlogin')) return Promise.reject(new Error('unlogin'))
} else if ( } else if (
// code重复使用或者过期,需要重新获取code
code === 40029 || code === 40029 ||
code === 40163 || code === 40163 ||
(res.data.errMsg || res.data.msg).includes('40029') || (res.data.errMsg || res.data.msg).includes('40029') ||
...@@ -50,26 +55,28 @@ service.interceptors.response.use(async res => { ...@@ -50,26 +55,28 @@ service.interceptors.response.use(async res => {
) { ) {
clearUserInfo() clearUserInfo()
uni.showToast({ uni.showToast({
title: 'code已过期,请重新登录', title: '登录过期,请重新登录',
icon: 'none', icon: 'none',
}) })
store.dispatch('user/uniLogin') store.dispatch('user/uniLogin')
return Promise.reject(new Error('unlogin')) return Promise.reject(new Error('unlogin'))
} else { } else {
if (res.data.errMsg || res.data.msg) { // 错误提示
if (res.data.msg || res.data.errMsg) {
// 错误统一处理 // 错误统一处理
uni.showToast({ uni.showToast({
title: res.data.errMsg || res.data.msg, title: res.data.msg || res.data.errMsg,
icon: 'none', icon: 'none',
}) })
} }
return Promise.reject(res.data.errMsg || res.data.msg) return Promise.reject(res.data.msg || res.data.errMsg)
} }
} else { } else {
return Promise.reject(res) return Promise.reject(res)
} }
}) })
// 清除用户信息
const clearUserInfo = () => { const clearUserInfo = () => {
store.commit('user/setUserInfo', {}) store.commit('user/setUserInfo', {})
store.commit('user/setCode', '') store.commit('user/setCode', '')
......
/* eslint-disable no-undef */ import request from '@/plugins/request'
// import request from '@/plugins/request'
export default { export default {
namespaced: true, namespaced: true,
...@@ -9,6 +8,7 @@ export default { ...@@ -9,6 +8,7 @@ export default {
code: uni.getStorageSync('code') || '', code: uni.getStorageSync('code') || '',
uid: uni.getStorageSync('uid') || '', uid: uni.getStorageSync('uid') || '',
accessToken: uni.getStorageSync('accessToken') || '', accessToken: uni.getStorageSync('accessToken') || '',
openId: uni.getStorageSync('openId') || '',
} }
}, },
mutations: { mutations: {
...@@ -28,6 +28,10 @@ export default { ...@@ -28,6 +28,10 @@ export default {
uni.setStorageSync('accessToken', data) uni.setStorageSync('accessToken', data)
state.accessToken = data state.accessToken = data
}, },
setOpenId(state, data) {
uni.setStorageSync('openId', data)
state.openId = data
},
}, },
actions: { actions: {
uniLogin({ commit }) { uniLogin({ commit }) {
...@@ -50,8 +54,44 @@ export default { ...@@ -50,8 +54,44 @@ export default {
}, },
login({ commit }, { code, encryptedData, iv }) { login({ commit }, { code, encryptedData, iv }) {
return new Promise(async (resolve, reject) => { return new Promise(async (resolve, reject) => {
// TODO 调用登录接口,设置store数据 const appId = uni.getAccountInfoSync().miniProgram.appId
resolve() try {
const res = await request.post(
`/mini/wx/user/${appId}/getToken`,
{
code,
encryptedData,
iv,
},
{
clearCode: true,
},
)
const { uid, accessToken, openId } = res
commit('setUid', uid)
commit('setAccessToken', accessToken)
commit('setOpenId', openId)
resolve()
} catch (e) {
reject(e)
}
})
},
getOpenId({ commit }) {
uni.login({
async success(res) {
const appId = uni.getAccountInfoSync().miniProgram.appId
try {
const result = await request.get(`/mini/wx/user/${appId}/login?code=${res.code}`)
const { openid } = result
commit('setOpenId', openid)
commit('setCode', '')
} catch (e) {}
},
fail(e) {
console.log(e, '<<<<<<<<获取code失败原因')
commit('setCode', '')
},
}) })
}, },
}, },
......
page {
font-size: 24rpx;
line-height: 1.4;
font-family: 'Helvetica Neue', Helvetica, 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei',
Arial, sans-serif;
background-color: #fff;
color: #000;
-webkit-overflow-scrolling: touch;
-webkit-font-smoothing: subpixel-antialiased;
}
@font-face {
font-style: normal;
font-weight: 400;
font-family: 'DINCondBold';
src: url('https://static.ydlcdn.com/weixin/font/DINCond-Bold/DINCond-Bold.ttf') format('ttf'),
url('https://static.ydlcdn.com/weixin/font/DINCond-Bold/DINCond-Bold.woff') format('woff');
}
.DINCond-Bold {
}
.container {
width: 100%;
box-sizing: border-box;
}
view,
scroll-view,
text,
checkbox-group,
checkbox,
label,
button,
input {
box-sizing: border-box;
}
.box-c {
padding-left: 32rpx;
padding-right: 32rpx;
}
.dix {
display: flex;
}
.alc {
align-items: center;
}
.jcc {
justify-content: center;
}
.flexs0 {
flex-shrink: 0;
}
.flex1 {
flex: 1;
}
.flex2 {
flex: 2;
}
.flex3 {
flex: 3;
}
.dib {
display: inline-block;
}
.vm {
vertical-align: middle;
}
.vt {
vertical-align: top;
}
.vb {
vertical-align: bottom;
}
.ff-db {
font-family: 'DINCondBold';
}
.c-3d {
color: #3d3d3d;
}
.c-24 {
color: #242424;
}
.c-666 {
color: #666;
}
.c-black {
color: #000;
}
.fs30 {
font-size: 30rpx;
}
.fs32 {
font-size: 32rpx;
}
.fs36 {
font-size: 36rpx;
}
.fs38 {
font-size: 38rpx;
}
.fs40 {
font-size: 40rpx;
}
.pl10 {
padding-left: 10rpx;
}
.pl20 {
padding-left: 20rpx;
}
.pr20 {
padding-right: 20rpx;
}
.pt30 {
padding-top: 30rpx;
}
.pt50 {
padding-top: 50rpx;
}
.pb2 {
padding-bottom: 2rpx;
}
.pb4 {
padding-bottom: 4rpx;
}
.pb8 {
padding-bottom: 8rpx;
}
.pb30 {
padding-bottom: 30rpx;
}
.mt6 {
margin-top: 6rpx;
}
.mt8 {
margin-top: 8rpx;
}
.mt9 {
margin-top: 9rpx;
}
.mt10 {
margin-top: 10rpx;
}
.mt12 {
margin-top: 12rpx;
}
.mr20 {
margin-right: 20rpx;
}
.mr8 {
margin-right: 8rpx;
}
.mr10 {
margin-right: 10rpx;
}
.ml2 {
margin-left: 2rpx;
}
.ml4 {
margin-left: 4rpx;
}
.ml6 {
margin-left: 6rpx;
}
.mr2 {
margin-right: 2rpx;
}
.ml20 {
margin-left: 20rpx;
}
.ml30 {
margin-left: 30rpx;
}
.mxw120 {
max-width: 120rpx;
}
.w180 {
width: 180rpx;
}
.tr {
text-align: right;
}
.b {
font-weight: bold;
}
.f500 {
font-weight: 500;
}
.y-btn {
color: #ffffff;
border: none;
}
button::after {
border: none;
}
.y-btn_primary {
background: linear-gradient(to right, #23b2fa, #1da0f2);
}
.y-btn_default {
color: #999;
background: #f7f7f7;
border: 1rpx solid #e0e0e0;
}
.y-icon-star {
width: 22rpx;
height: 22rpx;
}
.y-check {
position: absolute;
left: -9999px;
}
.weui-dialog__btn {
display: block;
flex: 1;
color: #576b95;
border-radius: 0;
line-height: 3;
text-decoration: none;
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
position: relative;
}
.weui-dialog__btn.default {
}
.weui-dialog__btn.primary {
color: #fff;
background: linear-gradient(to right, #4db4f5, #157dd5);
}
.weui-dialog {
position: fixed;
z-index: 5000;
width: 80%;
max-width: 300px;
top: 50%;
left: 50%;
font-size: 32rpx;
-webkit-transform: translate(-50%, -50%);
transform: translate(-50%, -50%);
background-color: #ffffff;
text-align: center;
border-radius: 5px;
overflow: hidden;
}
.weui-dialog__bd {
padding-top: 70rpx;
padding-bottom: 60rpx;
text-align: center;
}
.weui-dialog__ft {
display: flex;
}
.weui-mask {
position: fixed;
z-index: 1000;
top: 0;
right: 0;
left: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.6);
}
.ellipsis {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
word-break: break-word;
}
.ellipsis2 {
overflow: hidden;
text-overflow: ellipsis;
word-break: break-word;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
}
export const tabs = [
{
name: '排序',
id: 1,
},
{
name: '性别年龄',
id: 2,
},
{
name: '擅长方向',
id: 3,
},
]
export const sortLib = {
title: '排序',
data: [
{
name: '综合排序',
id: 1,
},
{
name: '人气从高到低',
id: 2,
},
{
name: '时间从新到旧',
id: 3,
},
],
}
export const sexType = {
title: '性别筛选',
data: [
{ id: 1, name: '只看男生' },
{ id: 2, name: '只看女生' },
],
}
export const ageType = {
title: '年龄筛选',
data: [
{ id: 0, name: '50后' },
{ id: 1, name: '60后' },
{ id: 2, name: '70后' },
{ id: 3, name: '80后' },
{ id: 4, name: '90后' },
{ id: 5, name: '00后' },
],
}
export const goodDirection = {
title: '擅长方向',
data: [
{ id: 1, name: '恋爱情感' },
{ id: 2, name: '婚姻家庭' },
{ id: 4, name: '情绪压力' },
{ id: 5, name: '亲子教育' },
{ id: 7, name: '职场发展' },
{ id: 8, name: '人际社交' },
{ id: 9, name: '个人成长' },
],
}
...@@ -29,8 +29,9 @@ export const setTrackData = ({ events = [], beforeEvent = null }) => { ...@@ -29,8 +29,9 @@ export const setTrackData = ({ events = [], beforeEvent = null }) => {
const result = request.post( const result = request.post(
'/dmp-event/v1/events/bulk', '/dmp-event/v1/events/bulk',
{ {
app_name: '', // 应用名称,根据实际项目定义填写 // todo
os_type: 4, // 操作系统类型,小程序 app_name: 'todo_ydllisten', // 应用名称
os_type: 4, // 操作系统类型
time: Date.now(), time: Date.now(),
os: res.system, os: res.system,
os_version: res.version, os_version: res.version,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment