Browse Source

小程序场景页面及我的渲染

h5_css
yanyan 3 years ago
parent
commit
9a0f240c9b
  1. 106
      components/my-login/my-login.vue
  2. 74
      components/my-search/my-search.vue
  3. 183
      components/my-userinfo/my-userinfo.vue
  4. 5
      main.js
  5. 23
      mixins/tabbar-badge.js
  6. 19
      pages.json
  7. 31
      pages/index/index.vue
  8. 196
      pages/my/my.vue
  9. 17
      pages/scan/scan.vue
  10. 15
      store/store.js
  11. 56
      store/user.js
  12. 126
      subpkg/list/list.vue

106
components/my-login/my-login.vue

@ -0,0 +1,106 @@
<template>
<view class="login-container">
<uni-icons type="contact-filled" size="100" color="#AFAFAF"></uni-icons>
<button type="primary" class="btn-login" open-type="getUserInfo" @getuserinfo="getUserInfo">一键登录</button>
<text class="tips-text">登录后尽享更多权益</text>
</view>
</template>
<script>
import { mapMutations, mapState } from 'vuex'
export default {
data() {
return {
};
},
computed: {
...mapState('m_user', ['redirectInfo'])
},
methods: {
...mapMutations('m_user', ['updateUserInfo', 'updateToken', 'updateRedirectInfo']),
// 用户授权之后,获取用户的基本信息
getUserInfo(e) {
console.log(e)
if (e.detail.errMsg === 'getUserInfo:fail auth deny') return uni.$showMsg('您取消了登录授权!')
console.log(e.detail.userInfo)
this.updateUserInfo(e.detail.userInfo)
this.getToken(e.detail)
},
async getToken(info) {
// 获取 code 对应的值
const [err, res] = await uni.login().catch(err => err)
if (err || res.errMsg !== 'login:ok') return uni.$showMsg('登录失败!')
// 准备参数
const query = {
code: res.code,
encryptedData: info.encryptedData,
iv: info.iv,
rawData: info.rawData,
signature: info.signature
}
const { data: loginResult } = await uni.$http.post('/api/public/v1/users/wxlogin', query)
if (loginResult.meta.status !== 200) return uni.$showMsg('登录失败!')
// 直接把 token 保存到 vuex 中
this.updateToken(loginResult.message.token)
this.navigateBack()
},
navigateBack() {
if (this.redirectInfo && this.redirectInfo.openType === 'switchTab') {
uni.switchTab({
url: this.redirectInfo.from,
complete: () => {
this.updateRedirectInfo(null)
}
})
}
}
}
}
</script>
<style lang="scss">
.login-container {
height: 750rpx;
background-color: #F8F8F8;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
position: relative;
overflow: hidden;
&::after {
content: ' ';
display: block;
width: 100%;
height: 40px;
background-color: white;
position: absolute;
bottom: 0;
left: 0;
border-radius: 100%;
transform: translateY(50%);
}
.btn-login {
width: 90%;
border-radius: 100px;
margin: 15px 0;
background-color: #C00000;
}
.tips-text {
font-size: 12px;
color: gray;
}
}
</style>

74
components/my-search/my-search.vue

@ -0,0 +1,74 @@
<template>
<view class="search">
<view class="search-title">请选择演练场景</view>
<view class="my-search-container" @click="searchBoxHandler">
<view class="my-search-box" :style="{ 'border-radius': radius + 'px' }">
<uni-search-bar @confirm="search" @input="input"></uni-search-bar>
<!-- 使用 uni-ui 提供的图标组件 -->
<uni-icons type="search" size="17" color="" ></uni-icons>
<text class="placeholder">搜索场景</text>
</view>
</view>
</view>
</template>
<script>
export default {
props: {
// 背景颜色
bgcolor: {
type: String,
default: 'white'
},
// 圆角尺寸
radius: {
type: Number,
default: 4 // px
}
},
data() {
return {
}
},
methods: {
searchBoxHandler() {
this.$emit('click')
}
}
}
</script>
<style lang="scss">
.search-title{
font-family: 'Courier New', Courier, monospace;
color: #67676a;
margin-left: 8px;
margin-top: 6px;
}
.my-search-container {
height: 50px;
// background-color: #C00000;
display: flex;
align-items: center;
padding: 0 10px;
.my-search-box {
height: 36px;
border: 0.5px solid #969696;
background-color: #FFFFFF;
// border-radius: 18px;
width: 100%;
display: flex;
justify-content: center;
align-items: center;
.placeholder {
font-size: 12px;
margin-left: 4px;
color: #969696;
}
}
}
</style>

183
components/my-userinfo/my-userinfo.vue

@ -0,0 +1,183 @@
<template>
<view class="my-userinfo-container">
<!-- 头像和昵称区域 -->
<view class="top-box">
<image :src="userinfo.avatarUrl" class="avatar"></image>
<view class="nickname">{{userinfo.nickName}}</view>
</view>
<!-- 面板区域 -->
<view class="panel-list">
<!-- 第1个面板 -->
<view class="panel">
<view class="panel-body">
<view class="panel-item">
<text>8</text>
<text>收藏的店铺</text>
</view>
<view class="panel-item">
<text>14</text>
<text>收藏的商品</text>
</view>
<view class="panel-item">
<text>18</text>
<text>关注的商品</text>
</view>
<view class="panel-item">
<text>84</text>
<text>足迹</text>
</view>
</view>
</view>
<!-- 第2个面板 -->
<view class="panel">
<view class="panel-title">
我的订单
</view>
<view class="panel-body">
<view class="panel-item">
<image src="/static/my-icons/icon1.png" class="icon"></image>
<text>待付款</text>
</view>
<view class="panel-item">
<image src="/static/my-icons/icon2.png" class="icon"></image>
<text>待收货</text>
</view>
<view class="panel-item">
<image src="/static/my-icons/icon3.png" class="icon"></image>
<text>退款/退货</text>
</view>
<view class="panel-item">
<image src="/static/my-icons/icon4.png" class="icon"></image>
<text>全部订单</text>
</view>
</view>
</view>
<!-- 第3个面板 -->
<view class="panel">
<view class="panel-list-item">
<text>收货地址</text>
<uni-icons type="arrowright" size="15"></uni-icons>
</view>
<view class="panel-list-item">
<text>联系客服</text>
<uni-icons type="arrowright" size="15"></uni-icons>
</view>
<view class="panel-list-item" @click="logout">
<text>退出登录</text>
<uni-icons type="arrowright" size="15"></uni-icons>
</view>
</view>
</view>
</view>
</template>
<script>
import { mapState, mapMutations } from 'vuex'
export default {
data() {
return {
};
},
computed: {
...mapState('m_user', ['userinfo'])
},
methods: {
...mapMutations('m_user', ['updateAddress', 'updateUserInfo', 'updateToken']),
async logout() {
const [err, succ] = await uni.showModal({
title: '提示',
content: '确认退出登录吗?'
}).catch(err => err)
if (succ && succ.confirm) {
this.updateAddress({})
this.updateUserInfo({})
this.updateToken('')
}
}
}
}
</script>
<style lang="scss">
.my-userinfo-container {
height: 100%;
background-color: #F4F4F4;
.top-box {
height: 400rpx;
background-color: #C00000;
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
.avatar {
width: 90px;
height: 90px;
border-radius: 45px;
border: 2px solid #FFF;
box-shadow: 0 1px 5px black;
}
.nickname {
font-size: 16px;
color: #FFF;
font-weight: bold;
margin-top: 10px;
}
}
}
.panel-list {
padding: 0 10px;
position: relative;
top: -10px;
.panel {
background-color: white;
border-radius: 3px;
margin-bottom: 8px;
.panel-title {
line-height: 45px;
padding-left: 10px;
font-size: 15px;
border-bottom: 1px solid #F4F4F4;
}
.panel-body {
display: flex;
justify-content: space-around;
.panel-item {
display: flex;
flex-direction: column;
align-items: center;
justify-content: space-around;
padding: 10px 0;
font-size: 13px;
.icon {
width: 35px;
height: 35px;
}
}
}
}
}
.panel-list-item {
display: flex;
justify-content: space-between;
align-items: center;
font-size: 15px;
padding: 0 10px;
line-height: 45px;
}
</style>

5
main.js

@ -2,6 +2,7 @@
// #ifndef VUE3
import Vue from 'vue'
import App from './App'
import store from '@/store/store.js'
//导入网络请求的包
import {$http} from '@escook/request-miniprogram'
@ -16,6 +17,7 @@ $http.beforeRequest = function(options) {
})
}
$http.afterRequest = function(options) {
uni.hideLoading()
}
@ -33,7 +35,8 @@ Vue.config.productionTip = false
App.mpType = 'app'
const app = new Vue({
...App
...App,
store
})
app.$mount()
// #endif

23
mixins/tabbar-badge.js

@ -0,0 +1,23 @@
import { mapGetters } from 'vuex'
export default {
computed: {
...mapGetters('m_cart', ['total'])
},
watch: {
total() {
this.setBadge()
}
},
onShow() {
this.setBadge()
},
methods: {
setBadge() {
uni.setTabBarBadge({
index: 2,
text: this.total + ''
})
}
}
}

19
pages.json

@ -20,7 +20,8 @@
"style" :
{
"navigationBarTitleText" : "全民演练",
"enablePullDownRefresh" : false
"enablePullDownRefresh" : false,
"navigationStyle": "custom"
}
},
{
@ -31,6 +32,22 @@
"enablePullDownRefresh" : false
}
}],
"subPackages": [
{
"root": "subpkg",
"pages": [
{
"path": "list/list",
"style" :
{
"navigationBarTitleText" : "场景演练",
"navigationBarTextStyle": "black",
"enablePullDownRefresh" : false
}
}
]
}
],
"globalStyle": {
"navigationBarTextStyle": "white",
"navigationBarTitleText": "全民演练",

31
pages/index/index.vue

@ -6,16 +6,13 @@
<!-- 轮播图 -->
<swiper :indicator-dots="true" :autoplay="true" :interval="3000" :duration="1000" :circular="true">
<swiper-item v-for="(item, i) in swiperList" :key="i">
<!-- <view class="swiper-item">
<image :src="item.image_src"></image>
</view> -->
<navigator class="swiper-item">
<image :src="item"></image>
</navigator>
</swiper-item>
</swiper>
<view class="scene-list">
<view class="scene-item" v-for="(item,i) in sceneList" :key="i">
<view class="scene-item" v-for="(item,i) in sceneList" :key="i" @click="navClickHandler(item)">
<image :src="item" class="scene-img"></image>
</view>
</view>
@ -28,6 +25,8 @@
return {
//顶部图片
topImg: "",
leftImg: "",
rightImg: "",
//轮播图数据列表
swiperList: [],
//场景入口
@ -43,22 +42,30 @@
const {
data: res
} = await uni.$http.post('/small/customImage/listAll')
} = await uni.$http.post('/small/customImage/listAll',{page:'home'})
if (!res.success) return uni.$showMsg()
res.data.forEach(item=>{
item.uploadPath = 'http://localhost:85' +item.uploadPath
item.uploadPath = uni.$http.baseUrl +item.uploadPath
if (item.position === "top"){
this.topImg = item.uploadPath
} else if(item.position === "middle"){
} else if(item.position.indexOf("banner") !=-1){
this.swiperList.push(item.uploadPath)
} else if(item.position === "bottom"){
this.sceneList.push(item.uploadPath)
} else if(item.position.indexOf("bottom-left") !=-1){
this.leftImg = item.uploadPath
} else if(item.position.indexOf("bottom-right") !=-1){
this.rightImg = item.uploadPath
}
})
this.sceneList.push(this.leftImg)
this.sceneList.push(this.rightImg)
uni.$showMsg('数据请求成功!')
},
navClickHandler(item) {
uni.navigateTo({
url: '/subpkg/list/list'
})
},
}
}
</script>
@ -66,13 +73,13 @@
<style lang="scss">
.index-background{
image{
height: 270rpx;
height: 220rpx;
width: 100%;
}
}
swiper {
height: 630rpx;
height: 570rpx;
.swiper-item,
image {

196
pages/my/my.vue

@ -1,19 +1,209 @@
<template>
<view>
我的
<view class="my-userinfo-container">
<!-- 头像和昵称区域 -->
<view class="top-box">
<image :src="avatarUrl" class="avatar"></image>
<view class="nickname">盛大鹏</view>
</view>
<!-- 面板区域 -->
<view class="panel-list">
<!-- 第1个面板 -->
<view class="panel">
<view class="panel-body">
<view class="panel-item">
<text>0</text>
<text>勋章</text>
</view>
<view class="panel-item">
<text>0</text>
<text>挑战历史</text>
</view>
</view>
</view>
<!-- 第2个面板 -->
<view class="panel">
<!-- 轮播图 -->
<swiper :indicator-dots="true" :autoplay="true" :interval="3000" :duration="1000" :circular="true">
<swiper-item v-for="(item, i) in swiperList" :key="i">
<navigator class="swiper-item">
<image :src="item"></image>
</navigator>
</swiper-item>
</swiper>
</view>
<!-- 第3个面板 -->
<view class="panel">
<view class="function-list">
<view class="panel-list-item" v-for="(item,i) in functionList" :key="i">
<image class="function-img" :src="item.uploadPath"></image>
<text style="margin-right: 240px;">{{item.name}}</text>
<uni-icons type="arrowright" size="15"></uni-icons>
</view>
</view>
</view>
</view>
</view>
</template>
<script>
import { mapState, mapMutations } from 'vuex'
export default {
data() {
return {
avatarUrl :"http://localhost:85/profile//2024/01/18/6147d64a3b94d7b3d3cc35aaf8cbfe06.png",
//轮播图数据列表
swiperList: [],
//主页功能列表
functionList:[]
};
},
onLoad() {
this.getSwiperList()
this.getFunctionList()
},
computed: {
...mapState('m_user', ['userinfo'])
},
methods: {
...mapMutations('m_user', ['updateAddress', 'updateUserInfo', 'updateToken']),
async logout() {
const [err, succ] = await uni.showModal({
title: '提示',
content: '确认退出登录吗?'
}).catch(err => err)
if (succ && succ.confirm) {
this.updateAddress({})
this.updateUserInfo({})
this.updateToken('')
}
},
async getSwiperList() {
const {
data: res
} = await uni.$http.post('/small/customImage/listAll')
if (!res.success) return uni.$showMsg()
res.data.forEach(item=>{
//item.uploadPath = uni.$http.baseUrl +item.uploadPath
//this.swiperList.push(item.uploadPath)
})
uni.$showMsg('数据请求成功!')
},
async getFunctionList() {
const {
data: res
} = await uni.$http.post('/small/project/home/listAll')
if (!res.success) return uni.$showMsg()
res.data.forEach(item=>{
item.uploadPath = uni.$http.baseUrl +item.uploadPath
})
this.functionList = res.data;
this.swiperList.push("http://localhost:85/profile//2024/01/18/d8796bd0b80cfbba38585c3462405022.jpeg")
uni.$showMsg('数据请求成功!')
}
},
navClickHandler(item) {
},
}
</script>
<style lang="scss">
.my-userinfo-container {
height: 100%;
background-color: #F4F4F4;
.top-box {
height: 400rpx;
background-color: #aba9d0;
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
.avatar {
width: 90px;
height: 90px;
border-radius: 45px;
border: 2px solid #FFF;
box-shadow: 0 1px 5px black;
}
.nickname {
font-size: 16px;
color: black;
font-family: Georgia, 'Times New Roman', Times, serif;
margin-top: 10px;
}
}
}
.panel-list {
padding: 0 10px;
position: relative;
top: -10px;
.panel {
background-color: white;
border-radius: 3px;
margin-bottom: 8px;
.panel-title {
line-height: 45px;
padding-left: 10px;
font-size: 15px;
border-bottom: 1px solid #F4F4F4;
}
.panel-body {
display: flex;
justify-content: space-around;
.panel-item {
display: flex;
flex-direction: column;
align-items: center;
justify-content: space-around;
padding: 10px 0;
font-size: 13px;
.icon {
width: 35px;
height: 35px;
}
}
}
}
}
.function-img{
width: 30px;
height: 30px;
}
.panel-list-item {
display: flex;
justify-content: space-between;
align-items: center;
font-size: 15px;
padding: 0 10px;
line-height: 45px;
}
swiper {
height: 230rpx;
.swiper-item,
image {
width: 100%;
height: 100%;
border-radius: 4px;
}
}
</style>

17
pages/scan/scan.vue

@ -6,10 +6,27 @@
<script>
export default {
data() {
return {
};
},
onReady(){
this.QR();
},
methods:{
QR() {
uni.scanCode({
onlyFromCamera: true,
success: (res) => {
console.log('扫描二维码成功,结果:' + res.result);
},
error: (res) => {
console.log('扫描二维码出现错误')
}
})
},
}
}
</script>

15
store/store.js

@ -0,0 +1,15 @@
import Vue from 'vue'
import Vuex from 'vuex'
import moduleUser from '@/store/user.js'
Vue.use(Vuex)
const store = new Vuex.Store({
modules: {
// 挂载用户的 vuex 模块,模块内成员的访问路径被调整为 m_user,例如:
// 用户模块中 user 数组的访问路径是 m_user/user
'm_user': moduleUser
}
})
export default store

56
store/user.js

@ -0,0 +1,56 @@
export default {
// 开启命名空间
namespaced: true,
// 数据
state: () => ({
address: JSON.parse(uni.getStorageSync('address') || '{}'),
token: uni.getStorageSync('token') || '',
// 用户的信息对象
userinfo: JSON.parse(uni.getStorageSync('userinfo') || '{}'),
// 重定向的 Object 对象
redirectInfo: null
}),
// 方法
mutations: {
// 更新收货地址
updateAddress(state, address) {
state.address = address
this.commit('m_user/saveAddressToStorage')
},
// 持久化存储 address
saveAddressToStorage(state) {
uni.setStorageSync('address', JSON.stringify(state.address))
},
updateUserInfo(state, userinfo) {
state.userinfo = userinfo
this.commit('m_user/saveUserInfoToStorage')
},
saveUserInfoToStorage(state) {
uni.setStorageSync('userinfo', JSON.stringify(state.userinfo))
},
updateToken(state, token) {
state.token = token
this.commit('m_user/saveTokenToStorage')
},
saveTokenToStorage(state) {
uni.setStorageSync('token', state.token)
},
updateRedirectInfo(state, info) {
state.redirectInfo = info
console.log(state.redirectInfo)
}
},
getters: {
// 收货地址
addstr(state) {
if (!state.address.provinceName) return ''
return state.address.provinceName + state.address.cityName + state.address.countyName + state.address.detailInfo
}
}
}

126
subpkg/list/list.vue

@ -0,0 +1,126 @@
<template>
<view>
<!-- 轮播图 -->
<swiper :indicator-dots="false" :autoplay="true" :interval="3000" :duration="1000" :circular="true">
<swiper-item v-for="(item, i) in swiperList" :key="i">
<!-- <view class="swiper-item">
<image :src="item.image_src"></image>
</view> -->
<navigator class="swiper-item">
<image :src="item"></image>
</navigator>
</swiper-item>
</swiper>
<!-- 搜索 -->
<!-- <my-search></my-search> -->
<view class="search">
<view class="search-title">请选择演练场景</view>
<view class="my-search-container">
<uni-search-bar class="my-search-box" @confirm="search" @input="input" cancel-button="none"></uni-search-bar>
</view>
</view>
<!-- 场景区域 -->
<view class="nav-list">
<view class="nav-item" v-for="(item, i) in sceneList" :key="i" @click="navClickHandler(item)">
<image :src="item" class="nav-img"></image>
</view>
</view>
</view>
</template>
<script>
export default {
data() {
return {
name:"",
//轮播图数据列表
swiperList: [],
//轮播图数据列表
sceneList: []
};
},
onLoad() {
this.getSwiperList();
this.getSceneList()
},
methods: {
async getSwiperList() {
const {
data: res
} = await uni.$http.post('/small/customImage/listAll',{page:'site'})
if (!res.success) return uni.$showMsg()
res.data.forEach(item=>{
item.uploadPath = uni.$http.baseUrl +item.uploadPath
this.swiperList.push(item.uploadPath)
})
uni.$showMsg('数据请求成功!')
},
async getSceneList() {
const {
data: res
} = await uni.$http.post('/small/scene/manage/listAll',{name:this.name})
if (!res.success) return uni.$showMsg()
this.sceneList = []
res.data.forEach(item=>{
item.uploadPath = uni.$http.baseUrl +item.uploadPath
this.sceneList.push(item.uploadPath)
})
uni.$showMsg('数据请求成功!')
},
objToParams(obj){
let arr = [];
for (let key in obj) {
arr.push(`${key}=${obj[key]}`);
}
return arr.join('&')
},
input(e){
clearTimeout(this.timer)
this.timer = setTimeout(() => {
this.name = e
this.getSceneList()
}, 500)
}
}
}
</script>
<style lang="scss">
swiper {
height: 330rpx;
.swiper-item,
image {
width: 99.8%;
margin-left: 0.1%;
height: 100%;
align-items: center;
border-radius: 10px;
}
}
.nav-list {
display: flex;
justify-content: space-around;
margin: 15px 0;
.nav-img {
width: 328rpx;
height: 140rpx;
}
}
.search-title{
font-family: 'Courier New', Courier, monospace;
color: #67676a;
margin-left: 8px;
margin-top: 6px;
}
</style>
Loading…
Cancel
Save