新增vuex状态管理
parent
6474f606f4
commit
9ec15c0272
2
App.vue
2
App.vue
|
@ -20,7 +20,7 @@
|
|||
// #endif
|
||||
},
|
||||
onShow: function() {
|
||||
if(uni.getStorageSync('phone_active')){
|
||||
if(uni.getStorageSync('token')){
|
||||
// 刷新token
|
||||
this.$toolAll.tools.refreshToken();
|
||||
}
|
||||
|
|
|
@ -0,0 +1,295 @@
|
|||
<template>
|
||||
<view class="datetime-picker">
|
||||
<view class="mask" :class="{ show: open }" @touchmove.stop.prevent catchtouchmove="true"></view>
|
||||
<view class="wrap" :class="{ show: open }">
|
||||
<view class="picker-header" @touchmove.stop.prevent catchtouchmove="true">
|
||||
<view class="btn-picker cancel" @click="open = false">取消</view>
|
||||
<view class="btn-picker submit" @click="_onSubmit">确定</view>
|
||||
</view>
|
||||
<view class="picker-body">
|
||||
<picker-view :value="value" @change="_onChange">
|
||||
<picker-view-column>
|
||||
<view class="column-item" v-for="item in years" :key="item">
|
||||
{{ item + "年" }}
|
||||
</view>
|
||||
</picker-view-column>
|
||||
<picker-view-column>
|
||||
<view class="column-item" v-for="item in months" :key="item">
|
||||
{{ formatNum(item) + "月" }}
|
||||
</view>
|
||||
</picker-view-column>
|
||||
<picker-view-column>
|
||||
<view class="column-item" v-for="item in days" :key="item">
|
||||
{{ formatNum(item) + "日" }}
|
||||
</view>
|
||||
</picker-view-column>
|
||||
<picker-view-column>
|
||||
<view class="column-item" v-for="item in hours" :key="item">
|
||||
{{ formatNum(item) + "时" }}
|
||||
</view>
|
||||
</picker-view-column>
|
||||
<picker-view-column>
|
||||
<view class="column-item" v-for="item in minutes" :key="item">
|
||||
{{ formatNum(item) + "分" }}
|
||||
</view>
|
||||
</picker-view-column>
|
||||
</picker-view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "buuug7-simple-datetime-picker",
|
||||
props: {
|
||||
startYear: {
|
||||
type: Number,
|
||||
default: 2000,
|
||||
},
|
||||
endYear: {
|
||||
type: Number,
|
||||
default: 2030,
|
||||
},
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
open: false,
|
||||
years: [],
|
||||
months: [],
|
||||
days: [],
|
||||
hours: [],
|
||||
minutes: [],
|
||||
currentDate: new Date(),
|
||||
year: "",
|
||||
month: "",
|
||||
day: "",
|
||||
hour: "",
|
||||
minute: "",
|
||||
value: [0, 0, 0, 0, 0],
|
||||
};
|
||||
},
|
||||
|
||||
mounted() {
|
||||
this.init();
|
||||
},
|
||||
|
||||
watch: {
|
||||
month() {
|
||||
this.initDays();
|
||||
},
|
||||
},
|
||||
|
||||
methods: {
|
||||
init() {
|
||||
this.initYears();
|
||||
this.initMonths();
|
||||
this.initDays();
|
||||
this.initHours();
|
||||
this.initMinutes();
|
||||
this.setSelectValue();
|
||||
},
|
||||
|
||||
initYears() {
|
||||
const years = [];
|
||||
for (let year = this.startYear; year <= this.endYear; year++) {
|
||||
years.push(year);
|
||||
if (this.currentDate.getFullYear() === year) {
|
||||
this.$set(this.value, 0, year - this.startYear);
|
||||
}
|
||||
}
|
||||
this.years = years;
|
||||
},
|
||||
|
||||
initMonths() {
|
||||
const months = [];
|
||||
for (let month = 1; month <= 12; month++) {
|
||||
months.push(month);
|
||||
if (this.currentDate.getMonth() + 1 === month) {
|
||||
this.$set(this.value, 1, month - 1);
|
||||
}
|
||||
}
|
||||
this.months = months;
|
||||
},
|
||||
|
||||
initDays() {
|
||||
const value = this.value;
|
||||
const selectedYear = this.years[value[0]];
|
||||
const selectedMonth = this.months[value[1]];
|
||||
const days = [];
|
||||
const totalDays = new Date(selectedYear, selectedMonth, 0).getDate();
|
||||
for (let day = 1; day <= totalDays; day++) {
|
||||
days.push(day);
|
||||
if (this.currentDate.getDate() === day) {
|
||||
this.$set(value, 2, day - 1);
|
||||
}
|
||||
}
|
||||
this.days = days;
|
||||
},
|
||||
|
||||
initHours() {
|
||||
const hours = [];
|
||||
for (let hour = 0; hour <= 23; hour++) {
|
||||
hours.push(hour);
|
||||
if (this.currentDate.getHours() === hour) {
|
||||
this.$set(this.value, 3, hour);
|
||||
}
|
||||
}
|
||||
this.hours = hours;
|
||||
},
|
||||
|
||||
initMinutes() {
|
||||
const minutes = [];
|
||||
for (let minute = 0; minute < 60; minute++) {
|
||||
minutes.push(minute);
|
||||
if (this.currentDate.getMinutes() === minute) {
|
||||
this.$set(this.value, 4, minute);
|
||||
}
|
||||
}
|
||||
this.minutes = minutes;
|
||||
},
|
||||
|
||||
show() {
|
||||
this.open = true;
|
||||
},
|
||||
|
||||
hide() {
|
||||
this.open = false;
|
||||
},
|
||||
|
||||
_onChange(e) {
|
||||
this.value = e.detail.value;
|
||||
this.setSelectValue();
|
||||
},
|
||||
|
||||
setSelectValue() {
|
||||
const v = this.value;
|
||||
|
||||
this.year = this.years[v[0]];
|
||||
this.month = this.months[v[1]];
|
||||
this.day = this.days[v[2]];
|
||||
this.hour = this.hours[v[3]];
|
||||
this.minute = this.minutes[v[4]];
|
||||
},
|
||||
|
||||
_onSubmit() {
|
||||
const {
|
||||
year,
|
||||
month,
|
||||
day,
|
||||
hour,
|
||||
minute,
|
||||
formatNum
|
||||
} = this;
|
||||
const result = {
|
||||
year: formatNum(year),
|
||||
month: formatNum(month),
|
||||
day: formatNum(day),
|
||||
hour: formatNum(hour),
|
||||
minute: formatNum(minute),
|
||||
};
|
||||
this.$emit("submit", result);
|
||||
this.hide();
|
||||
},
|
||||
|
||||
formatNum(num) {
|
||||
return num < 10 ? "0" + num : num + "";
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
$transition: all 0.3s ease;
|
||||
$primary: #488ee9;
|
||||
|
||||
.datetime-picker {
|
||||
position: relative;
|
||||
z-index: 999;
|
||||
|
||||
picker-view {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.mask {
|
||||
position: fixed;
|
||||
z-index: 1000;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
background-color: rgba(0, 0, 0, 0.6);
|
||||
visibility: hidden;
|
||||
opacity: 0;
|
||||
transition: $transition;
|
||||
|
||||
&.show {
|
||||
visibility: visible;
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.wrap {
|
||||
z-index: 1001;
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
transition: $transition;
|
||||
transform: translateY(100%);
|
||||
|
||||
&.show {
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
.picker-header {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 8px 8px;
|
||||
background-color: darken(#fff, 2%);
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.picker-body {
|
||||
width: 100%;
|
||||
height: 420rpx;
|
||||
overflow: hidden;
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.column-item {
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.btn-picker {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
padding-left: 10px;
|
||||
padding-right: 10px;
|
||||
box-sizing: border-box;
|
||||
text-align: center;
|
||||
text-decoration: none;
|
||||
line-height: 2;
|
||||
-webkit-tap-highlight-color: transparent;
|
||||
overflow: hidden;
|
||||
background-color: #eee;
|
||||
font-size: 14px;
|
||||
// border-radius: 2px;
|
||||
color: #000;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.btn-picker.submit {
|
||||
background-color: $primary;
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -1,75 +0,0 @@
|
|||
<template>
|
||||
<view id="main-img">
|
||||
<!-- <view class="mar-x40" v-for="(item,index) in list" :key="index"> -->
|
||||
<!-- 活动商品 start -->
|
||||
<view v-for="(item,index) in activityList" :key="index" class="mar-x50">
|
||||
<h1 class="fon36 bold">{{item.name}}</h1>
|
||||
<view class="colpeili fon26 mar-s20 mar-x40 clips1">{{item.subtitle}}</view>
|
||||
<view class="posir" @tap="goDetail(item.id)">
|
||||
<image class="radius30 animated fadeIn" :src="item.cover" mode="aspectFill" lazy-load style="height: 425rpx;width: 100%;" :style="{height:activityHeight + 'px'}"></image>
|
||||
<view v-if="item.tag!=''" class="posia fon24 colf pad-zy10 pad-s10 pad-x20 activity-img">限时优惠</view>
|
||||
</view>
|
||||
</view>
|
||||
<!-- 活动商品 end -->
|
||||
|
||||
<!-- 子商品 start -->
|
||||
<view class="disjbac fw">
|
||||
<view @tap="goDetail(item.id)" class="width47 mar-x50 posir" v-for="(item,index) in list" :key="index">
|
||||
<image :src="item.cover" mode="aspectFill" lazy-load style="width: 100%;height: 312rpx;border-radius: 30rpx;"></image>
|
||||
<view class="clips2 fon30 col0 linh50" style="height: 100rpx;">{{item.name}}</view>
|
||||
<view class="fon30 colpeili">¥{{item.price}}</view>
|
||||
<view v-if="item.tag!=''" class="posia fon24 colf pad-zy10 pad-s10 pad-x20 activity-img">限时优惠</view>
|
||||
</view>
|
||||
</view>
|
||||
<!-- 子商品 end -->
|
||||
<!-- </view> -->
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name:"list-one",
|
||||
props:{
|
||||
list:{
|
||||
type:Array,
|
||||
default:()=>{
|
||||
return []
|
||||
}
|
||||
},
|
||||
activityList:{
|
||||
type:Array,
|
||||
default:()=>{
|
||||
return []
|
||||
}
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
check:uni.getStorageSync('is_active'),
|
||||
activityHeight:''
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
uni.createSelectorQuery().in(this).select('#main-img').boundingClientRect().exec(rect => {
|
||||
this.activityHeight = rect[0].width;
|
||||
console.log(this.activityHeight,55);
|
||||
});
|
||||
},
|
||||
methods:{
|
||||
goDetail(id){//前往详情页
|
||||
if(this.check){
|
||||
uni.navigateTo({
|
||||
url:`/pagesB/shopDetail/shopDetail?id=${id}`
|
||||
})
|
||||
} else {
|
||||
uni.navigateTo({
|
||||
url:`/pages/login/login`
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
</style>
|
|
@ -1,163 +0,0 @@
|
|||
<template>
|
||||
<scroll-view scroll-y @scrolltolower="scrollBottomEv" :style="{height: scrollHeight +'px'}">
|
||||
<view class="disjbac fw">
|
||||
<view @tap="goDetail(item.id)" class="width48_5 mar-x50 posir" v-for="(item,index) in dataList" :key="index">
|
||||
<image class="animated fadeIn" :src="item.imgSrc" mode="aspectFill" style="width: 100%;height: 312rpx;border-radius: 30rpx;"></image>
|
||||
<view class="clips2 fon30 col0 linh50" style="height: 100rpx;">{{item.title}}</view>
|
||||
<view class="fon30 colpeili">¥{{item.price}}</view>
|
||||
<view v-if="item.isActivity" class="posia fon24 colf pad-zy10 pad-s10 pad-x20 activity-img">限时优惠</view>
|
||||
</view>
|
||||
</view>
|
||||
<!-- 暂无更多数据 -->
|
||||
<pitera v-if="showpitera"></pitera>
|
||||
</scroll-view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
// 暂无更多组件
|
||||
import pitera from '@/components/nothing/pitera.vue';
|
||||
export default {
|
||||
name:"list-two",
|
||||
components:{
|
||||
pitera
|
||||
},
|
||||
props:{
|
||||
// 高度类型
|
||||
scrollCate:{
|
||||
type:Number,
|
||||
default:1
|
||||
},
|
||||
// 页面来源
|
||||
pageSource: {
|
||||
type:Number,
|
||||
default:1
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
scrollHeight:uni.getStorageSync('scrollHeight'),
|
||||
// 数据
|
||||
dataList:[
|
||||
{
|
||||
id:1,
|
||||
imgSrc:'https://s6.jpg.cm/2022/02/14/L4oDhy.jpg',
|
||||
title:'于亿年宝藏中臻选1的宝',
|
||||
price:'2,000',
|
||||
isActivity:true,
|
||||
},
|
||||
{
|
||||
id:1,
|
||||
imgSrc:'https://s6.jpg.cm/2022/02/14/L4oDhy.jpg',
|
||||
title:'于亿年宝藏中臻选1的宝石级钻石每年开采数级钻石每年开采数',
|
||||
price:'2,000',
|
||||
isActivity:false,
|
||||
},
|
||||
{
|
||||
id:1,
|
||||
imgSrc:'https://s6.jpg.cm/2022/02/14/L4oDhy.jpg',
|
||||
title:'于亿年宝藏中臻选',
|
||||
price:'2,000',
|
||||
isActivity:false,
|
||||
},
|
||||
{
|
||||
id:1,
|
||||
imgSrc:'https://s6.jpg.cm/2022/02/14/L4oDhy.jpg',
|
||||
title:'于亿年宝藏中臻选',
|
||||
price:'2,000',
|
||||
isActivity:true,
|
||||
},
|
||||
{
|
||||
id:1,
|
||||
imgSrc:'https://s6.jpg.cm/2022/02/14/L4oDhy.jpg',
|
||||
title:'于亿年宝藏中臻选',
|
||||
price:'2,000',
|
||||
isActivity:false,
|
||||
},
|
||||
{
|
||||
id:1,
|
||||
imgSrc:'https://s6.jpg.cm/2022/02/14/L4oDhy.jpg',
|
||||
title:'于亿年宝藏中臻选1的宝石级钻石每年开采数',
|
||||
price:'2,000',
|
||||
isActivity:false,
|
||||
},
|
||||
{
|
||||
id:1,
|
||||
imgSrc:'https://s6.jpg.cm/2022/02/14/L4oDhy.jpg',
|
||||
title:'于亿年宝藏中臻选1的宝石级钻石每年开采数的宝石级钻石每年开采数',
|
||||
price:'2,000',
|
||||
isActivity:false,
|
||||
},
|
||||
{
|
||||
id:1,
|
||||
imgSrc:'https://s6.jpg.cm/2022/02/14/L4oDhy.jpg',
|
||||
title:'于亿年宝藏中臻选',
|
||||
price:'2,000',
|
||||
isActivity:false,
|
||||
},
|
||||
{
|
||||
id:1,
|
||||
imgSrc:'https://s6.jpg.cm/2022/02/14/L4oDhy.jpg',
|
||||
title:'于亿年宝藏中臻选1的宝石级钻石每年开采数的宝石级钻石每年开采数',
|
||||
price:'2,000',
|
||||
isActivity:false,
|
||||
}
|
||||
],
|
||||
page:1, // 第几页
|
||||
size:10, // 数量
|
||||
total:0, // 总数
|
||||
showpitera:true, // 是否显示暂无数据
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
switch (this.scrollCate){
|
||||
case 1:
|
||||
this.scrollHeight = uni.getStorageSync('scrollHeight-one'); // App.vue缓存的数据
|
||||
break;
|
||||
case 2:
|
||||
this.scrollHeight = uni.getStorageSync('scrollHeight-two'); // App.vue缓存的数据
|
||||
break;
|
||||
case 3:
|
||||
this.scrollHeight = uni.getStorageSync('scrollHeight-three'); // App.vue缓存的数据
|
||||
break;
|
||||
case 4:
|
||||
this.scrollHeight = uni.getStorageSync('scrollHeight-four'); // App.vue缓存的数据
|
||||
break;
|
||||
}
|
||||
switch (this.pageSource){
|
||||
case 1:
|
||||
this.checkList();
|
||||
break;
|
||||
}
|
||||
},
|
||||
methods:{
|
||||
checkList(){
|
||||
console.log('列表事件')
|
||||
},
|
||||
// 视图容器触底事件
|
||||
scrollBottomEv(){
|
||||
console.log('触底了',55)
|
||||
// 判断总数是否等于数组长度,如果相等显示暂无更多,否则继续执行列表事件
|
||||
if(this.total!=this.dataList.length){
|
||||
// 页数每次+1
|
||||
this.page++
|
||||
switch (this.pageSource){
|
||||
case 1:
|
||||
// this.checkList();// 调用列表事件
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
// 显示暂无数据
|
||||
this.pitera = true;
|
||||
}
|
||||
},
|
||||
goDetail(id){//前往详情页
|
||||
uni.navigateTo({
|
||||
url:`/pagesB/shopDetail/shopDetail?id=${id}`
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
</style>
|
|
@ -1,61 +0,0 @@
|
|||
<template>
|
||||
<text :style="{ color: color, 'font-size': size + 'rpx' }" :class="{isTheme:isTheme}" class="lw-icons"
|
||||
@click="_onClick">{{icons[icon]}}</text>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import icons from './icons.js';
|
||||
// #ifdef APP-NVUE
|
||||
var domModule = weex.requireModule('dom');
|
||||
domModule.addRule('fontFace', {
|
||||
'fontFamily': 'iconfont',
|
||||
'src': 'url(\'https://at.alicdn.com/t/font_2294175_vq7ymlkpbtm.ttf\')',
|
||||
});
|
||||
// #endif
|
||||
export default {
|
||||
name: 'UniIcons',
|
||||
props: {
|
||||
icon: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
color: {
|
||||
type: String,
|
||||
default: '#333333'
|
||||
},
|
||||
size: {
|
||||
type: [Number, String],
|
||||
default: 50
|
||||
},
|
||||
isTheme: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
icons: icons
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
_onClick() {
|
||||
this.$emit('click')
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
/* #ifndef APP-NVUE */
|
||||
@font-face {
|
||||
font-family: iconfont;
|
||||
src: url('https://at.alicdn.com/t/font_2294175_vq7ymlkpbtm.ttf')
|
||||
}
|
||||
|
||||
/* #endif */
|
||||
.lw-icons {
|
||||
font-family: iconfont;
|
||||
text-decoration: none;
|
||||
text-align: center;
|
||||
}
|
||||
</style>
|
|
@ -1,6 +0,0 @@
|
|||
export default {
|
||||
'aixin':'\ue8ab',
|
||||
'rules':'\ue909',
|
||||
'sound':'\ue8ea',
|
||||
'arrowright':'\uee02'
|
||||
}
|
|
@ -1,373 +0,0 @@
|
|||
<template>
|
||||
<view>
|
||||
<view class="contentBox" v-if="list.length" @click="toEmit()"
|
||||
:style="'color:' + color + ';background-color:' + backgroundColor + ';height:' + height+'rpx;'">
|
||||
<view v-if="showIcon" class="supBox">
|
||||
<lwIcon :size="32" :color="iconColor" icon="sound"></lwIcon>
|
||||
</view>
|
||||
<view v-if="list.length > 1" class="content">
|
||||
<view v-for="(item, index) in list" :key="index" @tap.stop="dangGao(index)">
|
||||
<view class="loopItemBase" :class="index==0&&firstIn?'fistInClass':''"
|
||||
:animation="realAnimation(index)" v-if="aindexArr.includes(index)"
|
||||
:style="'line-height:'+height+'rpx;'">
|
||||
{{ item }}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view v-if="list.length == 1" class="content">
|
||||
<view :style="'line-height:'+height+'rpx;'" @tap.stop="dangGao(0)" class="loopItemBaseShow">{{ list[0] }}</view>
|
||||
</view>
|
||||
<view v-if="showMore" class="offBox">
|
||||
<lwIcon :size="32" :color="moreColor" icon="arrowright"></lwIcon>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
/*
|
||||
lw-notice公告上下轮询组件(组件内依赖了自有的字体图标组件,可自行替换为uni或自身项目的图标组件)
|
||||
color:字体颜色
|
||||
backgroundColor:背景色
|
||||
list:要循环的列表数据
|
||||
height:组件高度
|
||||
showScale:是否有缩放动画
|
||||
runTime:间隔切换时间
|
||||
showIcon:是否显示头部小喇叭
|
||||
iconColor:小喇叭的颜色
|
||||
showMore:是否显示尾部更多
|
||||
moreColor:显示更多的颜色
|
||||
*/
|
||||
import lwIcon from './iconFont.vue'
|
||||
export default {
|
||||
components: {
|
||||
lwIcon
|
||||
},
|
||||
props: {
|
||||
color: {
|
||||
type: String,
|
||||
default: '#666666'
|
||||
},
|
||||
backgroundColor: {
|
||||
type: String,
|
||||
default: '#f5f5f5'
|
||||
},
|
||||
list: {
|
||||
type: Array,
|
||||
default: function(){
|
||||
return []
|
||||
}
|
||||
},
|
||||
height: {
|
||||
type: Number,
|
||||
default: 40
|
||||
},
|
||||
showScale: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
runTime: {
|
||||
type: Number,
|
||||
default: 4000
|
||||
},
|
||||
showIcon: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
showMore: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
iconColor: {
|
||||
type: String,
|
||||
default: '#aaaaaa'
|
||||
},
|
||||
moreColor: {
|
||||
type: String,
|
||||
default: '#aaaaaa'
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
// 第一次展示
|
||||
firstIn: true,
|
||||
// 当前显示的项
|
||||
aindexArr: [],
|
||||
// 创建动画的实例
|
||||
animation: null,
|
||||
// 动画对象一
|
||||
animationData: null,
|
||||
// 动画对象二
|
||||
animationDataTwo: null,
|
||||
// 显示项和动画之间的映射关系
|
||||
indexLinkAnimationObj: {},
|
||||
setTimerOne: null,
|
||||
setTimerTwo: null,
|
||||
setTimerThree: null,
|
||||
setTimerFour: null,
|
||||
setTimerFive: null
|
||||
};
|
||||
},
|
||||
beforeDestroy() {
|
||||
this.resetPage()
|
||||
},
|
||||
computed: {
|
||||
// 计算展示项应该展示的动画
|
||||
realAnimation() {
|
||||
return function(value) {
|
||||
if (this.indexLinkAnimationObj[value]) {
|
||||
return this[this.indexLinkAnimationObj[value]]
|
||||
} else {
|
||||
return {}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
// 开始 按3000毫秒的运行示例图
|
||||
// 1.a显示 执行动画1 锁定动画1 0ms
|
||||
// 2.b显示 执行动画2 锁定动画2 200ms
|
||||
// 3.a隐藏 停止动画1 释放动画1 300ms
|
||||
// 4.c显示 执行动画1 锁定动画1 400ms
|
||||
// 5.b隐藏 停止动画2 释放动画2 500ms
|
||||
// 6.a显示 执行动画2 锁定动画2 600ms
|
||||
// 7.c隐藏 停止动画1 释放动画1 700ms
|
||||
// 8.b显示 执行动画1 锁定动画1 800ms
|
||||
// 9.a隐藏 停止动画2 释放动画2 900ms
|
||||
// 10.c显示 执行动画2 锁定动画2 1000ms
|
||||
initPage() {
|
||||
this.resetPage();
|
||||
if (this.list && this.list.length) {
|
||||
if (this.list.length > 1) {
|
||||
this.aindexArr.push(0);
|
||||
this.animation = uni.createAnimation({
|
||||
timingFunction: 'linear',
|
||||
})
|
||||
// #ifdef H5
|
||||
this.animationDataH5 = this.animation.translateY(-100).step({
|
||||
duration: 10000
|
||||
}).export()
|
||||
// #endif
|
||||
this.runAnimation(0, true);
|
||||
}
|
||||
}
|
||||
},
|
||||
// 重置页面动画
|
||||
resetPage() {
|
||||
// 移除所有定时器
|
||||
clearTimeout(this.setTimerOne);
|
||||
clearTimeout(this.setTimerTwo);
|
||||
clearTimeout(this.setTimerThree);
|
||||
clearTimeout(this.setTimerFour);
|
||||
clearTimeout(this.setTimerFive);
|
||||
// 重置页面属性
|
||||
this.aindexArr = [];
|
||||
this.animation = null;
|
||||
this.animationData = null;
|
||||
this.animationDataTwo = null;
|
||||
this.indexLinkAnimationObj = {};
|
||||
},
|
||||
// 执行动画方法(此方法内不要清除赋值的定时器)
|
||||
runAnimation(value, firstIn) {
|
||||
let that = this;
|
||||
if (!firstIn) {
|
||||
that.aindexArr.push(value);
|
||||
}
|
||||
// 获取执行动画对象
|
||||
let lockText = that.createAni(firstIn);
|
||||
// 延迟50毫秒执行(等待dom渲染)
|
||||
that.setTimerOne = setTimeout(() => {
|
||||
// 创建执行动画和执行方之间的映射关系
|
||||
that.indexLinkAnimationObj[value] = lockText;
|
||||
// console.log('已经创建完成绑定关系')
|
||||
// console.log(that.indexLinkAnimationObj)
|
||||
// 获取基础执行时间单位
|
||||
let unitRunTime = (that.runTime - 50) / 6;
|
||||
let waitTime = firstIn ? unitRunTime * 4 : unitRunTime * 5;
|
||||
let waitTimeTwo = firstIn ? (that.runTime - unitRunTime) : that.runTime;
|
||||
// #ifdef H5
|
||||
waitTimeTwo = firstIn ? (that.runTime - (1.5 * unitRunTime)) : that.runTime;
|
||||
//H5重新刷新一下动画绑定关系
|
||||
if (firstIn) {
|
||||
that.aindexArr.splice(0, 1);
|
||||
that.aindexArr.push(0);
|
||||
}
|
||||
// #endif
|
||||
|
||||
// 开启下一个动画
|
||||
that.setTimerTwo = setTimeout(() => {
|
||||
let Index = value == that.list.length - 1 ? 0 : value + 1;
|
||||
that.runAnimation(Index)
|
||||
}, waitTime)
|
||||
// 释放上一个执行方
|
||||
that.setTimerThree = setTimeout(() => {
|
||||
let index = that.aindexArr.indexOf(value);
|
||||
that.aindexArr.splice(index, 1)
|
||||
that.firstIn = false;
|
||||
delete that.indexLinkAnimationObj[value]
|
||||
}, waitTimeTwo)
|
||||
}, 50)
|
||||
},
|
||||
// 创建动画方法
|
||||
createAni(firstIn) {
|
||||
let that = this;
|
||||
let unitRunTime = (that.runTime - 50) / 6;
|
||||
|
||||
let delayTime = unitRunTime * 4;
|
||||
let durationTime = unitRunTime;
|
||||
let dispairTime = unitRunTime;
|
||||
// #ifdef H5
|
||||
delayTime = unitRunTime * 3.5;
|
||||
dispairTime = unitRunTime * 1.5;
|
||||
// #endif
|
||||
|
||||
let showTransformHeight = -uni.upx2px(that.height);
|
||||
let hideTransformHeight = showTransformHeight * 2;
|
||||
// 创建动画
|
||||
if (that.showScale) {
|
||||
if (firstIn) {
|
||||
// that.animation.translateY(1).scale(1,1).step({ duration: 5 });
|
||||
that.animation.translateY(showTransformHeight).scale(0.5, 0.5).step({
|
||||
delay: delayTime,
|
||||
duration: dispairTime
|
||||
});
|
||||
} else {
|
||||
that.animation.translateY(showTransformHeight).scale(1, 1).step({
|
||||
duration: durationTime
|
||||
});
|
||||
that.animation.translateY(hideTransformHeight).scale(0.5, 0.5).step({
|
||||
delay: delayTime,
|
||||
duration: dispairTime
|
||||
});
|
||||
}
|
||||
} else {
|
||||
if (firstIn) {
|
||||
// that.animation.translateY(1).step({ duration: 5 });
|
||||
that.animation.translateY(showTransformHeight).step({
|
||||
delay: delayTime,
|
||||
duration: dispairTime
|
||||
});
|
||||
} else {
|
||||
that.animation.translateY(showTransformHeight).step({
|
||||
duration: durationTime
|
||||
});
|
||||
that.animation.translateY(hideTransformHeight).step({
|
||||
delay: delayTime,
|
||||
duration: dispairTime
|
||||
});
|
||||
}
|
||||
}
|
||||
// 判断动画赋值项并赋值
|
||||
if (!that.animationData) {
|
||||
that.animationData = that.animation.export()
|
||||
that.setTimerFour = setTimeout(() => {
|
||||
clearTimeout(that.setTimerFour)
|
||||
that.animationData = false;
|
||||
}, that.runTime)
|
||||
return 'animationData'
|
||||
} else {
|
||||
that.animationDataTwo = that.animation.export()
|
||||
that.setTimerFive = setTimeout(() => {
|
||||
clearTimeout(that.setTimerFive)
|
||||
that.animationDataTwo = false;
|
||||
}, that.runTime)
|
||||
return 'animationDataTwo'
|
||||
}
|
||||
},
|
||||
// 抛出点击事件
|
||||
toEmit() {
|
||||
let that = this
|
||||
if (that.list.length == 1) {
|
||||
that.$emit('itemClick', that.list[0])
|
||||
} else {
|
||||
that.$emit('itemClick', that.list[that.aindexArr[0]])
|
||||
}
|
||||
},
|
||||
dangGao(index){
|
||||
let that = this
|
||||
if (that.list.length != 0) {
|
||||
that.$emit('dangGao', index)
|
||||
}
|
||||
}
|
||||
},
|
||||
created() {
|
||||
|
||||
},
|
||||
mounted() {
|
||||
// 判断list有值后开启动画
|
||||
// setTimeout()
|
||||
this.initPage()
|
||||
},
|
||||
watch: {
|
||||
list(value) {
|
||||
this.initPage()
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.contentBox {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
// padding: 0 20rpx;
|
||||
align-items: center;
|
||||
box-sizing: border-box;
|
||||
font-size: 24rpx;
|
||||
.supBox {
|
||||
width: 50rpx;
|
||||
display: flex;
|
||||
justify-content: flex-start;
|
||||
}
|
||||
|
||||
.offBox {
|
||||
width: 50rpx;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
.content {
|
||||
width: 100%;
|
||||
flex-grow: 1;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
align-items: center;
|
||||
box-sizing: border-box;
|
||||
justify-content: center;
|
||||
|
||||
.loopItemBase {
|
||||
left: 0;
|
||||
top: 100%;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
font-size: 28rpx;
|
||||
text-align: left;
|
||||
position: absolute;
|
||||
white-space: nowrap;
|
||||
align-items: center;
|
||||
text-overflow: ellipsis;
|
||||
|
||||
&.fistInClass {
|
||||
top: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.loopItemBaseShow {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
// height: 100%;
|
||||
overflow: hidden;
|
||||
font-size: 28rpx;
|
||||
text-align: left;
|
||||
white-space: nowrap;
|
||||
align-items: center;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,292 @@
|
|||
<template>
|
||||
<view class="xzw_notice" :style="{color:getColor(theme),backgroundColor:getBgColor(theme)}">
|
||||
<uni-icons v-if="showIcon === true || showIcon === 'true'" class="notice_left" type="sound" :color="getColor(theme)" size="22" />
|
||||
<swiper class="notice_center" vertical v-if="direction=='column'" :autoplay="true" :interval="4000" :duration="500" :circular="true" disable-touch>
|
||||
<swiper-item v-for="(item, index) in list" :key="index" class="swiperIn" @click="goItem(item)">
|
||||
<view>{{item[theKey]}}</view>
|
||||
</swiper-item>
|
||||
</swiper>
|
||||
<view :class="['','notice_center1','notice_center2','notice_center3','notice_center4','notice_center5'][speedTime]" v-else><view class="content">{{list[0][theKey]}}</view></view>
|
||||
<view class="notice_right" v-if="showMore">
|
||||
<view @click="goMore">更多</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name:"notice-one",
|
||||
props:{
|
||||
// 速度
|
||||
speed: {
|
||||
type:Number,
|
||||
default:1
|
||||
},
|
||||
//主题色,default|primary|error|warning|success|info
|
||||
theme: {
|
||||
type: String,
|
||||
default: 'default'
|
||||
},
|
||||
// 是否显示左侧icon
|
||||
showIcon: {
|
||||
type: [Boolean, String],
|
||||
default: false
|
||||
},
|
||||
// 是否显示更多
|
||||
showMore: {
|
||||
type: [Boolean, String],
|
||||
default: false
|
||||
},
|
||||
list: {
|
||||
type: Array,
|
||||
default() {
|
||||
return [{id:1,title:'公告1'},{id:2,title:'公告2'}]
|
||||
}
|
||||
},
|
||||
//公告数组的键名
|
||||
theKey:{
|
||||
type: String,
|
||||
default: 'title'
|
||||
},
|
||||
//方向,column垂直,row水平时取第一条公告
|
||||
direction:{
|
||||
type: String,
|
||||
default: 'column'
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
text:'',
|
||||
speedTime:1
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
// 缓存状态栏+标题栏的高度
|
||||
const query = wx.createSelectorQuery().in(this)
|
||||
query.select('.content').boundingClientRect((rect) => {
|
||||
console.log(rect.width);
|
||||
let newWidth = rect.width;
|
||||
if(newWidth <=420) {
|
||||
this.speedTime = 1;
|
||||
}
|
||||
if(newWidth >= 420 && newWidth < 720) {
|
||||
this.speedTime = 2;
|
||||
}
|
||||
if(newWidth >= 720 && newWidth < 820) {
|
||||
this.speedTime = 3;
|
||||
}
|
||||
if(newWidth >= 820 && newWidth < 920) {
|
||||
this.speedTime = 4;
|
||||
}
|
||||
if(newWidth >= 920) {
|
||||
this.speedTime = 5;
|
||||
}
|
||||
}).exec()
|
||||
},
|
||||
methods:{
|
||||
getColor(theme){
|
||||
if(theme=="primary"){
|
||||
return "#2979FF"
|
||||
}else if(theme=="error"){
|
||||
return "#FA3534"
|
||||
}else if(theme=="warning"){
|
||||
return "#FF9A43"
|
||||
}else if(theme=="success"){
|
||||
return "#1BBF6C"
|
||||
}else if(theme=="info"){
|
||||
return "#909399"
|
||||
}else{
|
||||
return "#303133"
|
||||
}
|
||||
},
|
||||
getBgColor(theme){
|
||||
if(theme=="primary"){
|
||||
return "#ECF5FF"
|
||||
}else if(theme=="error"){
|
||||
return "#FEF0F0"
|
||||
}else if(theme=="warning"){
|
||||
return "#FDF6EC"
|
||||
}else if(theme=="success"){
|
||||
return "#DBF1E1"
|
||||
}else if(theme=="info"){
|
||||
return "#F4F4F5"
|
||||
}else{
|
||||
return "#FFFFFF"
|
||||
}
|
||||
},
|
||||
goItem(item){
|
||||
uni.navigateTo({
|
||||
url:`/pagesB/notice-detail/notice-detail?id=${item.id}`
|
||||
})
|
||||
},
|
||||
goMore(){
|
||||
uni.navigateTo({
|
||||
url:`/pagesB/notice-list/notice-list`
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.xzw_notice {
|
||||
font-size: 26upx;
|
||||
height: 40upx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
width: 100%;
|
||||
.notice_left{
|
||||
margin: 0 20upx 0 0;
|
||||
}
|
||||
.notice_center{
|
||||
flex:1;
|
||||
height:90upx;
|
||||
.swiperIn{
|
||||
height:80upx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
view{
|
||||
overflow: hidden;
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 1;
|
||||
-webkit-box-orient: vertical;
|
||||
}
|
||||
}
|
||||
}
|
||||
.notice_center1{
|
||||
flex:1;
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height:90upx;
|
||||
overflow: hidden;
|
||||
view{
|
||||
position: absolute;
|
||||
white-space: nowrap;
|
||||
padding-left: 100%;
|
||||
animation: notice 5s 0s linear infinite both;
|
||||
}
|
||||
}
|
||||
.notice_right {
|
||||
margin: 0 0 0 20upx;
|
||||
}
|
||||
@keyframes notice {
|
||||
100% {
|
||||
transform: translate3d(-100%, 0, 0);
|
||||
}
|
||||
}
|
||||
.notice_center1{
|
||||
flex:1;
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height:90upx;
|
||||
overflow: hidden;
|
||||
view{
|
||||
position: absolute;
|
||||
white-space: nowrap;
|
||||
padding-left: 100%;
|
||||
animation: notice 5s 0s linear infinite both;
|
||||
}
|
||||
}
|
||||
.notice_right {
|
||||
margin: 0 0 0 20upx;
|
||||
}
|
||||
@keyframes notice {
|
||||
100% {
|
||||
transform: translate3d(-100%, 0, 0);
|
||||
}
|
||||
}
|
||||
.notice_center2{
|
||||
flex:1;
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height:90upx;
|
||||
overflow: hidden;
|
||||
view{
|
||||
position: absolute;
|
||||
white-space: nowrap;
|
||||
padding-left: 100%;
|
||||
animation: notice 10s 0s linear infinite both;
|
||||
}
|
||||
}
|
||||
.notice_right {
|
||||
margin: 0 0 0 20upx;
|
||||
}
|
||||
@keyframes notice {
|
||||
100% {
|
||||
transform: translate3d(-100%, 0, 0);
|
||||
}
|
||||
}
|
||||
.notice_center3{
|
||||
flex:1;
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height:90upx;
|
||||
overflow: hidden;
|
||||
view{
|
||||
position: absolute;
|
||||
white-space: nowrap;
|
||||
padding-left: 100%;
|
||||
animation: notice 15s 0s linear infinite both;
|
||||
}
|
||||
}
|
||||
.notice_right {
|
||||
margin: 0 0 0 20upx;
|
||||
}
|
||||
@keyframes notice {
|
||||
100% {
|
||||
transform: translate3d(-100%, 0, 0);
|
||||
}
|
||||
}
|
||||
.notice_center4{
|
||||
flex:1;
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height:90upx;
|
||||
overflow: hidden;
|
||||
view{
|
||||
position: absolute;
|
||||
white-space: nowrap;
|
||||
padding-left: 100%;
|
||||
animation: notice 20s 0s linear infinite both;
|
||||
}
|
||||
}
|
||||
.notice_right {
|
||||
margin: 0 0 0 20upx;
|
||||
}
|
||||
@keyframes notice {
|
||||
100% {
|
||||
transform: translate3d(-100%, 0, 0);
|
||||
}
|
||||
}
|
||||
.notice_center5{
|
||||
flex:1;
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height:90upx;
|
||||
overflow: hidden;
|
||||
view{
|
||||
position: absolute;
|
||||
white-space: nowrap;
|
||||
padding-left: 100%;
|
||||
animation: notice 25s 0s linear infinite both;
|
||||
}
|
||||
}
|
||||
.notice_right {
|
||||
margin: 0 0 0 20upx;
|
||||
}
|
||||
@keyframes notice {
|
||||
100% {
|
||||
transform: translate3d(-100%, 0, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,75 @@
|
|||
### 安装方式
|
||||
|
||||
本组件符合[easycom](https://uniapp.dcloud.io/collocation/pages?id=easycom)规范,`HBuilderX 2.5.5`起,只需将本组件导入项目,在页面`template`中即可直接使用,无需在页面中`import`和注册`components`。
|
||||
|
||||
### 说明
|
||||
由于官方公告组件uni-notice-bar没有垂直滚动的功能, 所以利用swiper加入了垂直滚动, 加入了常用主题色, 可以自己去添加, 需要用到uni-icons
|
||||
|
||||
```html
|
||||
<template>
|
||||
<view class="container">
|
||||
<!-- 默认垂直滚动 -->
|
||||
<xzw-notice/>
|
||||
<!-- 水平滚动,取数组第一条 -->
|
||||
<xzw-notice theme="info" direction="row"/>
|
||||
<!-- theme主题色,default|primary|error|warning|success|info -->
|
||||
<xzw-notice theme="error" direction="row"/>
|
||||
<!-- 点击公告,点击更多 -->
|
||||
<xzw-notice theme="warning" @goItem="goItem" @goMore="goMore"/>
|
||||
<!-- 绑定公告数组,默认取每一项的title字段,可以通过theKey改变读取的字段 -->
|
||||
<xzw-notice theme="success" :list="list2" theKey="name"/>
|
||||
<!-- 是否显示左侧喇叭,是否显示更多 -->
|
||||
<xzw-notice theme="primary" :list="list2" theKey="name" :showIcon="false" :showMore="false"/>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
```
|
||||
|
||||
```javascript
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
list:[{id:1,title:'公告1'},{id:2,title:'公告2'}]
|
||||
list2:[{id:1,name:'公告3'},{id:2,name:'公告4'}]
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
goItem(item){
|
||||
uni.showToast({
|
||||
title:'你点击的公告id是'+item.id,
|
||||
icon:'none'
|
||||
})
|
||||
},
|
||||
goMore(){
|
||||
uni.showToast({
|
||||
title:'点击更多',
|
||||
icon:'none'
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
## API
|
||||
|
||||
### Tag Props
|
||||
|
||||
|属性名 |类型 |默认值 |说明 |
|
||||
|:-: |:-: |:-: |:-: |
|
||||
|list |Array | |公告数组 |
|
||||
|theme |String |default |主题 |
|
||||
|showIcon |Boolean |true |是否显示左侧icon |
|
||||
|showMore |Boolean |true |是否显示更多 |
|
||||
|theKey |String |title |公告数组的键名 |
|
||||
|direction |String |column |滚动的方向 |
|
||||
|
||||
|
||||
### Tag Events
|
||||
|
||||
|事件称名 |说明 |返回值 |
|
||||
|:-: |:-: |:-: |
|
||||
|@goItem |点击公告 |- |
|
||||
|@goMore |点击更多 |- |
|
||||
|
|
@ -0,0 +1,132 @@
|
|||
export default {
|
||||
"pulldown": "\ue588",
|
||||
"refreshempty": "\ue461",
|
||||
"back": "\ue471",
|
||||
"forward": "\ue470",
|
||||
"more": "\ue507",
|
||||
"more-filled": "\ue537",
|
||||
"scan": "\ue612",
|
||||
"qq": "\ue264",
|
||||
"weibo": "\ue260",
|
||||
"weixin": "\ue261",
|
||||
"pengyouquan": "\ue262",
|
||||
"loop": "\ue565",
|
||||
"refresh": "\ue407",
|
||||
"refresh-filled": "\ue437",
|
||||
"arrowthindown": "\ue585",
|
||||
"arrowthinleft": "\ue586",
|
||||
"arrowthinright": "\ue587",
|
||||
"arrowthinup": "\ue584",
|
||||
"undo-filled": "\ue7d6",
|
||||
"undo": "\ue406",
|
||||
"redo": "\ue405",
|
||||
"redo-filled": "\ue7d9",
|
||||
"bars": "\ue563",
|
||||
"chatboxes": "\ue203",
|
||||
"camera": "\ue301",
|
||||
"chatboxes-filled": "\ue233",
|
||||
"camera-filled": "\ue7ef",
|
||||
"cart-filled": "\ue7f4",
|
||||
"cart": "\ue7f5",
|
||||
"checkbox-filled": "\ue442",
|
||||
"checkbox": "\ue7fa",
|
||||
"arrowleft": "\ue582",
|
||||
"arrowdown": "\ue581",
|
||||
"arrowright": "\ue583",
|
||||
"smallcircle-filled": "\ue801",
|
||||
"arrowup": "\ue580",
|
||||
"circle": "\ue411",
|
||||
"eye-filled": "\ue568",
|
||||
"eye-slash-filled": "\ue822",
|
||||
"eye-slash": "\ue823",
|
||||
"eye": "\ue824",
|
||||
"flag-filled": "\ue825",
|
||||
"flag": "\ue508",
|
||||
"gear-filled": "\ue532",
|
||||
"reload": "\ue462",
|
||||
"gear": "\ue502",
|
||||
"hand-thumbsdown-filled": "\ue83b",
|
||||
"hand-thumbsdown": "\ue83c",
|
||||
"hand-thumbsup-filled": "\ue83d",
|
||||
"heart-filled": "\ue83e",
|
||||
"hand-thumbsup": "\ue83f",
|
||||
"heart": "\ue840",
|
||||
"home": "\ue500",
|
||||
"info": "\ue504",
|
||||
"home-filled": "\ue530",
|
||||
"info-filled": "\ue534",
|
||||
"circle-filled": "\ue441",
|
||||
"chat-filled": "\ue847",
|
||||
"chat": "\ue263",
|
||||
"mail-open-filled": "\ue84d",
|
||||
"email-filled": "\ue231",
|
||||
"mail-open": "\ue84e",
|
||||
"email": "\ue201",
|
||||
"checkmarkempty": "\ue472",
|
||||
"list": "\ue562",
|
||||
"locked-filled": "\ue856",
|
||||
"locked": "\ue506",
|
||||
"map-filled": "\ue85c",
|
||||
"map-pin": "\ue85e",
|
||||
"map-pin-ellipse": "\ue864",
|
||||
"map": "\ue364",
|
||||
"minus-filled": "\ue440",
|
||||
"mic-filled": "\ue332",
|
||||
"minus": "\ue410",
|
||||
"micoff": "\ue360",
|
||||
"mic": "\ue302",
|
||||
"clear": "\ue434",
|
||||
"smallcircle": "\ue868",
|
||||
"close": "\ue404",
|
||||
"closeempty": "\ue460",
|
||||
"paperclip": "\ue567",
|
||||
"paperplane": "\ue503",
|
||||
"paperplane-filled": "\ue86e",
|
||||
"person-filled": "\ue131",
|
||||
"contact-filled": "\ue130",
|
||||
"person": "\ue101",
|
||||
"contact": "\ue100",
|
||||
"images-filled": "\ue87a",
|
||||
"phone": "\ue200",
|
||||
"images": "\ue87b",
|
||||
"image": "\ue363",
|
||||
"image-filled": "\ue877",
|
||||
"location-filled": "\ue333",
|
||||
"location": "\ue303",
|
||||
"plus-filled": "\ue439",
|
||||
"plus": "\ue409",
|
||||
"plusempty": "\ue468",
|
||||
"help-filled": "\ue535",
|
||||
"help": "\ue505",
|
||||
"navigate-filled": "\ue884",
|
||||
"navigate": "\ue501",
|
||||
"mic-slash-filled": "\ue892",
|
||||
"search": "\ue466",
|
||||
"settings": "\ue560",
|
||||
"sound": "\ue590",
|
||||
"sound-filled": "\ue8a1",
|
||||
"spinner-cycle": "\ue465",
|
||||
"download-filled": "\ue8a4",
|
||||
"personadd-filled": "\ue132",
|
||||
"videocam-filled": "\ue8af",
|
||||
"personadd": "\ue102",
|
||||
"upload": "\ue402",
|
||||
"upload-filled": "\ue8b1",
|
||||
"starhalf": "\ue463",
|
||||
"star-filled": "\ue438",
|
||||
"star": "\ue408",
|
||||
"trash": "\ue401",
|
||||
"phone-filled": "\ue230",
|
||||
"compose": "\ue400",
|
||||
"videocam": "\ue300",
|
||||
"trash-filled": "\ue8dc",
|
||||
"download": "\ue403",
|
||||
"chatbubble-filled": "\ue232",
|
||||
"chatbubble": "\ue202",
|
||||
"cloud-download": "\ue8e4",
|
||||
"cloud-upload-filled": "\ue8e5",
|
||||
"cloud-upload": "\ue8e6",
|
||||
"cloud-download-filled": "\ue8e9",
|
||||
"headphones":"\ue8bf",
|
||||
"shop":"\ue609"
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
<template>
|
||||
<text :style="{ color: color, 'font-size': size + 'px' }" class="uni-icons" :class="[customIcons,customIcons?type:'']" @click="_onClick">{{icons[type]}}</text>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import icons from './icons.js';
|
||||
export default {
|
||||
name: 'UniIcons',
|
||||
props: {
|
||||
type: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
color: {
|
||||
type: String,
|
||||
default: '#333333'
|
||||
},
|
||||
size: {
|
||||
type: [Number, String],
|
||||
default: 16
|
||||
},
|
||||
customIcons:{
|
||||
type: String,
|
||||
default: ''
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
icons: icons
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
_onClick() {
|
||||
this.$emit('click')
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
/* #ifndef APP-NVUE */
|
||||
@font-face {
|
||||
font-family: uniicons;
|
||||
src: url('./uni.ttf') format('truetype');
|
||||
}
|
||||
/* #endif */
|
||||
.uni-icons {
|
||||
font-family: uniicons;
|
||||
text-decoration: none;
|
||||
text-align: center;
|
||||
}
|
||||
</style>
|
Binary file not shown.
|
@ -1,42 +0,0 @@
|
|||
<template>
|
||||
<view>
|
||||
<view v-if="showShare" @tap="closeShare" style="position: fixed;top: 0;right: 0;left: 0;bottom: 0;background-color: rgba(0,0,0,.5);z-index: 10;">
|
||||
</view>
|
||||
<view v-if="showShare" style="display: flex;flex-direction: column;justify-content: space-around;
|
||||
position: fixed;bottom: 0;left: 0;right: 0;z-index: 100; background-color: #FFFFFF;padding: 40rpx;">
|
||||
<view class="posir" v-for="(item,index) in cateArr" :key="index" style="display: flex;justify-content: center;align-items: center;flex-direction: column;width: 25%;">
|
||||
<image style="width: 100rpx;height: 100rpx;margin-bottom: 10rpx;" :src="item.src" mode=""></image>
|
||||
<view class="fon28 color33">{{item.title}}</view>
|
||||
<button data-name="shareBtn" open-type="share" plain="true" class="posia" style="top: 0;left: 0;right: 0;bottom: 0;opacity: 0;">分享</button>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name:'shareAll',
|
||||
props:{
|
||||
showShare:{
|
||||
type:Boolean,
|
||||
default:false
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
cateArr:[
|
||||
{src:'/static/img/share/weix.png',title:'微信好友'},
|
||||
]
|
||||
};
|
||||
},
|
||||
methods:{
|
||||
closeShare(){
|
||||
this.$emit('closeShare')
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
|
||||
</style>
|
|
@ -1,188 +0,0 @@
|
|||
<template>
|
||||
<view class="status-box statusHNH">
|
||||
<!-- 网络、电量栏 start -->
|
||||
<view :style="{height: statusBarHeight+'px',background: backgroudColor}"></view>
|
||||
<!-- 网络、电量栏 end -->
|
||||
|
||||
<!-- 头部状态栏 start -->
|
||||
<view class="status-nav"
|
||||
:style="{background: backgroudColor,height: navBarHeight+'px'}">
|
||||
<!-- 返回键 -->
|
||||
<view class="return-box" @tap="backEv" v-if="ifReturn"
|
||||
:style="{height: navBarHeight+'px'}">
|
||||
<slot name="leftContent">
|
||||
<i class="icon icon-return" style="font-size: 32rpx;"
|
||||
:style="{color: returnColor}"></i>
|
||||
</slot>
|
||||
</view>
|
||||
<!-- 标题 -->
|
||||
<view class="tab-title" v-if="ifTitle && ifNet"
|
||||
:style="{
|
||||
color: titleColor,
|
||||
justifyContent: ifCenter ? 'center' : '',
|
||||
padding: ifCenter ? '0px' : `${ifReturn ? '0 38' : '0 15'}px`}">
|
||||
<view class="title-box" :class="['','clips1','clips2'][clipNumber]" :style="{maxWidth: ifCenter ? '360rpx' : '70%'}">{{navBarTitle}}</view>
|
||||
</view>
|
||||
<view class="tab-title" v-if="!ifNet"
|
||||
:style="{
|
||||
color: titleColor,
|
||||
justifyContent: ifCenter ? 'center' : '',
|
||||
padding: ifCenter ? '0px' : `${ifReturn ? '0 38' : '0 15'}px`}">
|
||||
<view class="title-box" :class="['','clips1','clips2'][clipNumber]" :style="{maxWidth: ifCenter ? '360rpx' : '70%'}">{{netText}}<text @tap="refreshEv" style="color: #3875F6;margin-left: 20rpx;">刷新</text></view>
|
||||
</view>
|
||||
</view>
|
||||
<!-- 头部状态栏 end -->
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name:'status-nav',
|
||||
props:{
|
||||
//状态栏、导航栏背景颜色
|
||||
backgroudColor:{
|
||||
type:String,
|
||||
default:'#FFFFFF'
|
||||
},
|
||||
// 默认导航栏高度
|
||||
navBarHeight: {
|
||||
type:Number,
|
||||
default:40
|
||||
},
|
||||
//是否显示返回键
|
||||
ifReturn:{
|
||||
type:Boolean,
|
||||
default:true
|
||||
},
|
||||
// 返回键颜色
|
||||
returnColor: {
|
||||
type:String,
|
||||
default:'#000'
|
||||
},
|
||||
//是否显示标题
|
||||
ifTitle:{
|
||||
type:Boolean,
|
||||
default:true
|
||||
},
|
||||
// 导航栏标题
|
||||
navBarTitle: {
|
||||
type:String,
|
||||
default:''
|
||||
},
|
||||
// 标题最多几行显示
|
||||
clipNumber: {
|
||||
type:Number,
|
||||
default:1
|
||||
},
|
||||
//标题颜色
|
||||
titleColor:{
|
||||
type:String,
|
||||
default:'#333333'
|
||||
},
|
||||
// 标题是否居中
|
||||
ifCenter: {
|
||||
type:Boolean,
|
||||
default: true
|
||||
},
|
||||
// 来自哪里
|
||||
fromWhere: {
|
||||
type:Number,
|
||||
default:0
|
||||
}
|
||||
},
|
||||
data(){
|
||||
return {
|
||||
statusBarHeight: uni.getSystemInfoSync().statusBarHeight,
|
||||
ifNet:true ,// 是否有网络
|
||||
netText:'当前无网络',
|
||||
netTimer:null
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
// 网络监测
|
||||
this.$toolAll.tools.networkStatus();
|
||||
// 缓存状态栏+标题栏的高度
|
||||
// const query = wx.createSelectorQuery().in(this)
|
||||
// query.select('.statusHNH').boundingClientRect((rect) => {
|
||||
// uni.setStorageSync('statusHNH',rect.height)
|
||||
// }).exec();
|
||||
|
||||
// 获取当前页面路径
|
||||
this.$toolAll.tools.obtainUrl();
|
||||
this.$toolAll.tools.obtainUrlParam();
|
||||
setTimeout(()=>{
|
||||
this.ifNet = uni.getStorageSync('isNet');
|
||||
},500)
|
||||
},
|
||||
methods:{
|
||||
// 刷新网络事件
|
||||
refreshEv(){
|
||||
this.netText = '正在刷新...';
|
||||
let outTime = 0;//十秒超时
|
||||
this.netTimer = setInterval(()=>{
|
||||
outTime++;
|
||||
this.$toolAll.tools.networkStatus();
|
||||
if(uni.getStorageSync('isNet')) {
|
||||
clearInterval(this.netTimer);
|
||||
this.ifNet = true;
|
||||
}
|
||||
if(outTime==10) {
|
||||
clearInterval(this.netTimer);
|
||||
this.netText = '刷新失败';
|
||||
outTime = 0;
|
||||
}
|
||||
},1000)
|
||||
},
|
||||
//返回事件
|
||||
backEv(){
|
||||
if(uni.getStorageSync('outside')*1==2){
|
||||
this.fromWhere = uni.getStorageSync('outside')*1;
|
||||
}
|
||||
switch (this.fromWhere){
|
||||
case 1:
|
||||
case 2:
|
||||
uni.navigateTo({
|
||||
url:'/pages/tabbar/pagehome/pagehome'
|
||||
})
|
||||
uni.setStorageSync('outside',0)
|
||||
break;
|
||||
case 0:
|
||||
uni.navigateBack({
|
||||
delta:1
|
||||
})
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.clips1{display: -webkit-box;-webkit-box-orient: vertical;-webkit-line-clamp: 1;overflow: hidden;text-overflow: ellipsis;word-wrap: break-word;word-break:break-all;}
|
||||
.clips2{display: -webkit-box;-webkit-box-orient: vertical;-webkit-line-clamp: 2;overflow: hidden;text-overflow: ellipsis;word-wrap: break-word;word-break:break-all;}
|
||||
|
||||
.status-box{
|
||||
position: fixed;top: 0;left: 0;right: 0;z-index: 10;
|
||||
}
|
||||
.status-nav{
|
||||
width: 100%;
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
.return-box {
|
||||
display: flex;justify-content: center;align-items: center;flex-shrink: 0;
|
||||
position: absolute;
|
||||
padding: 0rpx 10rpx;
|
||||
}
|
||||
.return-box i {font-size: 56rpx;}
|
||||
.tab-title{
|
||||
width: 100%;
|
||||
font-size: 32rpx;
|
||||
display: flex;
|
||||
font-weight: bold;
|
||||
}
|
||||
.tab-title .title-box{margin-top: -4rpx;}
|
||||
</style>
|
254
jsFile/tools.js
254
jsFile/tools.js
|
@ -1,6 +1,6 @@
|
|||
const app = getApp();
|
||||
const tools = {
|
||||
timer:'',
|
||||
timerNot:'',
|
||||
// 埋点倒计时
|
||||
daoTime(){
|
||||
let daoTime = uni.getStorageSync('daoTime')
|
||||
|
@ -9,13 +9,10 @@ const tools = {
|
|||
daoTime = uni.getStorageSync('daoTime')
|
||||
this.timer = setInterval(()=>{
|
||||
uni.setStorageSync('daoTime',daoTime--)//设置倒计时
|
||||
// console.log('埋点倒计时初次:',daoTime);
|
||||
// console.log('埋点长度初次:',uni.getStorageSync('maiList').length);
|
||||
if(uni.getStorageSync('daoTime')<=0 || uni.getStorageSync('maiList').length==5){
|
||||
uni.removeStorageSync('daoTime')//清空倒计时
|
||||
clearInterval(this.timer)//关闭倒计时
|
||||
// console.log('上/报,埋点');
|
||||
// reportBuriedPoint(uni.getStorageSync('maiList'))//上报事件
|
||||
uni.removeStorageSync('maiList')//清空上报参数
|
||||
this.daoTime()//重新倒计时
|
||||
}
|
||||
|
@ -23,13 +20,10 @@ const tools = {
|
|||
} else {//继续当前倒计时倒计
|
||||
this.timer = setInterval(()=>{
|
||||
uni.setStorageSync('daoTime',daoTime--)//设置倒计时
|
||||
// console.log('埋点倒计时:',daoTime);
|
||||
// console.log('埋点长度:',uni.getStorageSync('maiList').length);
|
||||
if(uni.getStorageSync('daoTime')<=0 || uni.getStorageSync('maiList').length==5){
|
||||
uni.removeStorageSync('daoTime')//清空倒计时
|
||||
clearInterval(this.timer)//关闭倒计时
|
||||
// console.log('上报,埋点');
|
||||
// reportBuriedPoint(uni.getStorageSync('maiList'))//上报事件
|
||||
uni.removeStorageSync('maiList')//清空上报参数
|
||||
this.daoTime()//重新倒计时
|
||||
}
|
||||
|
@ -39,15 +33,6 @@ const tools = {
|
|||
closeTimer(){
|
||||
clearInterval(this.timer)//关闭倒计时
|
||||
console.log('倒计时清空了');
|
||||
clearInterval(this.timerNot)//关闭倒计时
|
||||
},
|
||||
maiDian(data){//埋点事件
|
||||
let maiList = uni.getStorageSync('maiList')
|
||||
// console.log(maiList);
|
||||
if(maiList==''){
|
||||
maiList = [data]
|
||||
} else maiList.push(data)
|
||||
uni.setStorageSync('maiList',maiList)
|
||||
},
|
||||
weekDate(){//获取未来七天星期几,几号
|
||||
let date = new Date()
|
||||
|
@ -63,10 +48,6 @@ const tools = {
|
|||
isPhone:function(phone){
|
||||
// 手机号正则表达式
|
||||
let reg_tel = /^(13[0-9]|14[01456879]|15[0-35-9]|16[2567]|17[0-8]|18[0-9]|19[0-35-9])\d{8}$/;
|
||||
// if(!reg_tel.test(phone)){
|
||||
// return true
|
||||
// }
|
||||
// return false
|
||||
return !reg_tel.test(phone);
|
||||
},
|
||||
// 电子邮箱验证
|
||||
|
@ -83,6 +64,21 @@ const tools = {
|
|||
hideMPhone(phone){
|
||||
return `${phone.substr(0, 3)}****${phone.substr(7)}`
|
||||
},
|
||||
// 手机号中间加字符
|
||||
phoneAddChat(phone,startNum=3,endNum=7,character=' '){
|
||||
let phoneStr = phone;
|
||||
phoneStr = phoneStr.replace(/\s*/g, "");
|
||||
var phoneArr = [];
|
||||
for(var i = 0; i < phoneStr.length; i++){
|
||||
if (i==startNum||i==endNum){
|
||||
phoneArr.push(`${character}` + phoneStr.charAt(i));
|
||||
} else {
|
||||
phoneArr.push(phoneStr.charAt(i));
|
||||
}
|
||||
}
|
||||
phone = phoneArr.join("");
|
||||
return phone;
|
||||
},
|
||||
// 昵称从第一个字开始,后面的都用"*"代替
|
||||
hideName(name,num){
|
||||
return `${name.substr(0, 1)}****${name.substr(name.length-1)}`
|
||||
|
@ -113,7 +109,7 @@ const tools = {
|
|||
str = str.toFixed(2);
|
||||
str = str+'';
|
||||
}
|
||||
return str.includes('.') ? str*1 : str = num + '.00';
|
||||
return str.includes('.') ? str : str = num + '.00';
|
||||
},
|
||||
// type:+加、-减、*乘、/除
|
||||
// len:小数后保留几位
|
||||
|
@ -229,6 +225,65 @@ const tools = {
|
|||
// console.log(time2);//1398250549123
|
||||
// console.log(time3);//1398250549000
|
||||
},
|
||||
// 返回当前时间
|
||||
returnCurrentTime(format,type) {
|
||||
let date = new Date();
|
||||
let year = date.getFullYear(); // 年
|
||||
let month = date.getMonth() + 1; // 月
|
||||
let day = date.getDate(); // 日
|
||||
let time = date.getHours(); // 时
|
||||
let minu = date.getSeconds(); // 分
|
||||
let second = date.getMinutes(); // 秒
|
||||
|
||||
let newTime = '';
|
||||
switch (type){
|
||||
case 0:
|
||||
newTime = `${year}${format}${month < 10? '0' + month : month}${format}${day < 10 ? '0' + day : day} ${time < 10 ? '0' + time : time}:${minu < 10 ? '0' + minu : minu}`; // 2022-03-31 16:05
|
||||
break;
|
||||
case 1:
|
||||
newTime = `${year}${format}${month < 10? '0' + month : month}${format}${day < 10 ? '0' + day : day} ${time < 10 ? '0' + time : time}:${minu < 10 ? '0' + minu : minu}:${second < 10 ? '0' + second : second}`; // 2022-03-31 16:10:07
|
||||
break;
|
||||
}
|
||||
return newTime;
|
||||
},
|
||||
// 返回时间xx天xx小时xx分钟
|
||||
returnTimeFormat(startTime,endTime){
|
||||
console.log(startTime,endTime);
|
||||
let newTimeFormat = '';
|
||||
let currentTimestamp = this.timeToTimestamp(endTime) - this.timeToTimestamp(startTime);
|
||||
return this.returnTimestampToTime(currentTimestamp);
|
||||
},
|
||||
// 返回时间戳转时、分对象
|
||||
returnTimestampToTime(timestamp){
|
||||
let timeStr = '';
|
||||
var day = parseInt((timestamp % (1000 * 60 * 60 * 24 * 12)) / (1000 * 60 * 60 * 24));
|
||||
var hours = parseInt((timestamp % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));
|
||||
var seconds = parseInt((timestamp % (1000 * 60 * 60)) / (1000 * 60));
|
||||
day = day < 10 ? ('0' + day) : day;
|
||||
hours = hours < 10 ? ('0' + hours) : hours;
|
||||
seconds = seconds < 10 ? ('0' + seconds) : seconds;
|
||||
if(day*1==0) {
|
||||
if(hours*1==0) {
|
||||
seconds*1==0 ? timeStr = 0 : timeStr = `${seconds}分钟`;
|
||||
} else {
|
||||
timeStr = `${hours}小时${seconds}分钟`;
|
||||
}
|
||||
} else {
|
||||
timeStr = `${day}天${hours}小时${seconds}分钟`;
|
||||
}
|
||||
return timeStr;
|
||||
},
|
||||
// 时间戳转时分秒 00 : 00 : 00
|
||||
formatDuring: function(mss) {
|
||||
// let dangTime = Math.round(new Date()/1000)//获取当前时间戳
|
||||
var hours = parseInt((mss % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));
|
||||
var seconds = parseInt((mss % (1000 * 60 * 60)) / (1000 * 60));
|
||||
var minutes = (mss % (1000 * 60)) / 1000;
|
||||
hours = hours < 10 ? ('0' + hours) : hours;
|
||||
seconds = seconds < 10 ? ('0' + seconds) : seconds;
|
||||
minutes = minutes < 10 ? ('0' + minutes) : minutes;
|
||||
return hours + ' : ' + seconds + ' : ' + minutes;
|
||||
},
|
||||
// 随机数生成
|
||||
randomStr(){
|
||||
var strData = "";
|
||||
|
@ -268,30 +323,18 @@ const tools = {
|
|||
return newObj
|
||||
},
|
||||
// 提示方法
|
||||
showToast: function(msg, icon,time) {
|
||||
// 弹框图标:none默认无图标、loading、success
|
||||
var newIncon = 'none';
|
||||
if (icon) {newIncon = icon;}
|
||||
showToast: function(msg, icon='none',time) {
|
||||
// 弹框显示时间:默认2秒
|
||||
var newTime = 2000
|
||||
if (time) {newTime = time;}
|
||||
return uni.showToast({
|
||||
title: msg,
|
||||
icon: newIncon,
|
||||
icon: icon,
|
||||
duration:newTime
|
||||
})
|
||||
},
|
||||
formatDuring: function(mss) {
|
||||
// let dangTime = Math.round(new Date()/1000)//获取当前时间戳
|
||||
var hours = parseInt((mss % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));
|
||||
var minutes = parseInt((mss % (1000 * 60 * 60)) / (1000 * 60));
|
||||
var seconds = (mss % (1000 * 60)) / 1000;
|
||||
hours = hours < 10 ? ('0' + hours) : hours;
|
||||
minutes = minutes < 10 ? ('0' + minutes) : minutes;
|
||||
seconds = seconds < 10 && seconds >= 1 ? ('0' + seconds) : seconds;
|
||||
return hours + ' : ' + minutes + ' : ' + seconds;
|
||||
},
|
||||
escape2Html(str) {//富文本
|
||||
// 富文本
|
||||
escape2Html(str) {
|
||||
var arrEntities = { 'lt': '<', 'gt': '>', 'nbsp': ' ', 'amp': '&', 'quot': '"' };
|
||||
return str.replace(/&(lt|gt|nbsp|amp|quot|src);/ig, function (all, t) {
|
||||
return arrEntities[t];
|
||||
|
@ -300,39 +343,10 @@ const tools = {
|
|||
.replace(/\<img/g, '<img @tap="pre" style="max-width:100%!important;height:auto" ')
|
||||
.replace(/src=\"/g,'src="https://oss.hmzfyy.cn');
|
||||
},
|
||||
updaX(){//检测小程序版本以及更新小程序
|
||||
// #ifdef MP-WEIXIN
|
||||
// 获取小程序的运行环境、版本号、appId 注意:线上小程序版本号仅支持在正式版小程序中获取,开发版和体验版中无法获取。
|
||||
const accountInfo = wx.getAccountInfoSync();//使用详情:https://developers.weixin.qq.com/miniprogram/dev/api/open-api/account-info/wx.getAccountInfoSync.html
|
||||
var version = accountInfo.miniProgram.version;
|
||||
console.log(version,319);
|
||||
// 检测小程序的更新
|
||||
const updateManager = wx.getUpdateManager()//以下使用详情:https://developers.weixin.qq.com/miniprogram/dev/api/base/update/UpdateManager.html#%E7%A4%BA%E4%BE%8B%E4%BB%A3%E7%A0%81
|
||||
updateManager.onCheckForUpdate(function (res) {
|
||||
// 请求完新版本信息的回调
|
||||
// console.log('检测是否有更新:',res.hasUpdate)
|
||||
})
|
||||
updateManager.onUpdateReady(function (res) {
|
||||
wx.showModal({
|
||||
title: `更新`,
|
||||
content: `新版本${version}已上线,是否重启应用`,
|
||||
success:(res)=> {
|
||||
if (res.confirm) {
|
||||
// 新的版本已经下载好,调用 applyUpdate 应用新版本并重启
|
||||
updateManager.applyUpdate()
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
updateManager.onUpdateFailed(function (res) {
|
||||
// 新版本下载失败
|
||||
// console.log('新版本下载失败:',res);
|
||||
})
|
||||
// #endif
|
||||
},
|
||||
networkStatus(){//检查网络状态
|
||||
// 检查网络状态
|
||||
networkStatus(){
|
||||
uni.getNetworkType({
|
||||
success: function (res) {
|
||||
success: (res)=> {
|
||||
console.log('当前网络状态:',res.networkType);//none:当前无网络连接
|
||||
if(res.networkType=='none'){
|
||||
uni.setStorageSync('isNet',false)
|
||||
|
@ -341,12 +355,84 @@ const tools = {
|
|||
// 微信小程序原生API性能优化
|
||||
// #ifdef MP-WEIXIN
|
||||
// 连网下,检测小程序是否有更新
|
||||
tools.updaX();
|
||||
this.checkUpdate();
|
||||
// #endif
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
// app、小程序的检测版本并更新
|
||||
checkUpdate(){
|
||||
// 检测app
|
||||
// #ifdef APP-PLUS
|
||||
|
||||
// #endif
|
||||
//检测小程序
|
||||
// #ifdef MP-WEIXIN
|
||||
var self = this;
|
||||
// 获取小程序更新机制兼容
|
||||
if (wx.canIUse('getUpdateManager')) {
|
||||
const updateManager = wx.getUpdateManager();//1. 检查小程序是否有新版本发布
|
||||
updateManager.onCheckForUpdate(function(res) {// 请求完新版本信息的回调
|
||||
if (res.hasUpdate) {
|
||||
//检测到新版本,需要更新,给出提示
|
||||
wx.showModal({
|
||||
title: '更新提示',
|
||||
content: '检测到新版本,是否下载新版本并重启小程序?',
|
||||
success: function(res) {
|
||||
if (res.confirm) {
|
||||
//2. 用户确定下载更新小程序,小程序下载及更新静默进行
|
||||
self.downLoadAndUpdate(updateManager)
|
||||
// 清除所有缓存
|
||||
uni.clearStorage();
|
||||
uni.clearStorageSync();
|
||||
} else if (res.cancel) {
|
||||
//用户点击取消按钮的处理,如果需要强制更新,则给出二次弹窗,如果不需要,则这里的代码都可以删掉了
|
||||
wx.showModal({
|
||||
title: '温馨提示~',
|
||||
content: '本次版本更新涉及到新的功能添加,旧版本无法正常访问的哦~',
|
||||
showCancel:false,//隐藏取消按钮
|
||||
confirmText:"确定更新",//只保留确定更新按钮
|
||||
success: function(res) {
|
||||
if (res.confirm) {
|
||||
//下载新版本,并重新应用
|
||||
self.downLoadAndUpdate(updateManager)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
} else { // 如果希望用户在最新版本的客户端上体验您的小程序,可以这样子提示
|
||||
wx.showModal({
|
||||
title: '提示',
|
||||
content: '当前微信版本过低,无法使用该功能,请升级到最新微信版本后重试。'
|
||||
})
|
||||
}
|
||||
// #endif
|
||||
},
|
||||
/**
|
||||
* 下载小程序新版本并重启应用
|
||||
* */
|
||||
downLoadAndUpdate(updateManager){
|
||||
var self = this;
|
||||
wx.showLoading(); //静默下载更新小程序新版本
|
||||
updateManager.onUpdateReady(function () {
|
||||
wx.hideLoading(); //新的版本已经下载好,调用 applyUpdate 应用新版本并重启
|
||||
updateManager.applyUpdate();
|
||||
// 清除缓存
|
||||
uni.clearStorageSync();
|
||||
uni.clearStorage();
|
||||
})
|
||||
updateManager.onUpdateFailed(function () { // 新的版本下载失败
|
||||
wx.showModal({
|
||||
title: '已经有新版本了哟~',
|
||||
content: '新版本已经上线啦~,请您删除当前小程序,重新搜索打开哟~',
|
||||
})
|
||||
})
|
||||
},
|
||||
// 文本复制
|
||||
clickCopy(data){
|
||||
uni.setClipboardData({
|
||||
|
@ -405,7 +491,7 @@ const tools = {
|
|||
if (res.code) {
|
||||
var params = {code:res.code}
|
||||
uni.request({
|
||||
url: `${uni.getStorageSync('hostapi')}/api/user/login`,
|
||||
url: `${app.globalData.hostapi}/api/user/login`,
|
||||
method: 'post',
|
||||
data: params,
|
||||
header: {
|
||||
|
@ -430,16 +516,17 @@ const tools = {
|
|||
}
|
||||
},
|
||||
// 判断是否授权,没授权,前往登录页面授权
|
||||
authTimer:null,
|
||||
judgeAuth(){
|
||||
let auth = true;
|
||||
switch (uni.getStorageSync('phone_active')*1){
|
||||
case 0: // 未注册
|
||||
uni.navigateTo({url:'/pages/login/login'});
|
||||
auth = false
|
||||
break;
|
||||
case 1: // 已注册
|
||||
auth = true
|
||||
break;
|
||||
let auth = false;
|
||||
clearTimeout(this.authTimer);
|
||||
if(!uni.getStorageSync('token')) {
|
||||
this.showToast('请登录');
|
||||
this.authTimer = setTimeout(()=>{
|
||||
uni.navigateTo({url:'/pages/login/login'});
|
||||
},2000)
|
||||
} else {
|
||||
auth = true;
|
||||
}
|
||||
return auth;
|
||||
},
|
||||
|
@ -456,13 +543,10 @@ const tools = {
|
|||
// console.log(hInfo.envVersion);//develop:开发版 trial:体验版 release:正式版
|
||||
// if(hInfo.miniProgram.envVersion == "develop"){
|
||||
if(hInfo.miniProgram.envVersion == "develop" || hInfo.miniProgram.envVersion == "trial"){
|
||||
// (开发版,体验版)-配置全局域名
|
||||
// uni.setStorageSync('hostapi','https://hengmei.scdxtc.cn/api/');
|
||||
|
||||
} else {
|
||||
// 清除所有输出日志
|
||||
console.log = () =>{};
|
||||
// 正式版-配置全局域名
|
||||
// uni.setStorageSync('hostapi','https://hm.hmzfyy.cn/api/');
|
||||
// 开启埋点倒计时
|
||||
this.daoTime();//开启埋点倒计时
|
||||
}
|
||||
|
@ -523,7 +607,7 @@ const tools = {
|
|||
const res = uni.getSystemInfoSync();
|
||||
if(res.platform=='ios'){
|
||||
uni.makePhoneCall({
|
||||
phoneNumber:phone,
|
||||
phoneNumber:phone*1,
|
||||
success: () => {},
|
||||
fail: () => {}
|
||||
})
|
||||
|
|
7
main.js
7
main.js
|
@ -1,5 +1,7 @@
|
|||
import Vue from 'vue';
|
||||
import App from './App';
|
||||
import store from './store'
|
||||
Vue.prototype.$store = store
|
||||
|
||||
import nothingPage from './components/nothing/nothing-page.vue';//引入无内容组件
|
||||
Vue.component('nothing-page',nothingPage);//全局注册无内容组件
|
||||
|
@ -10,10 +12,12 @@ Vue.component('status-nav',statusNav);//全局注册头部状态栏与导航栏
|
|||
import containerSubgroupTwo from './components/containers/container-subgroup-two.vue';//引入头部状态栏与导航栏组件
|
||||
Vue.component('container-subgroup',containerSubgroupTwo);//全局注册头部状态栏与导航栏组件
|
||||
|
||||
// #ifdef MP-WEIXIN
|
||||
import share from './jsFile/share.js';// 全局注册分享事件
|
||||
Vue.mixin(share);
|
||||
// #endif
|
||||
|
||||
// 常用工具
|
||||
// 常用便捷式公共方法
|
||||
import tools from '@/jsFile/tools.js';
|
||||
Vue.prototype.$toolAll = tools;
|
||||
// 响应数据
|
||||
|
@ -23,6 +27,7 @@ Vue.prototype.$requst = requst;
|
|||
App.mpType = 'app';
|
||||
|
||||
const app = new Vue({
|
||||
store,
|
||||
...App
|
||||
})
|
||||
app.$mount()
|
||||
|
|
|
@ -48,7 +48,6 @@
|
|||
<view class="disac pad-s30 pad-x10">
|
||||
<image class="mar-zy20" style="width: 64rpx;height: 27rpx;" src="/static/public/icon-home-notice.png" mode=""></image>
|
||||
<view class="fon24 color6 mar-y20 width100 bleft pad-z20">
|
||||
<lwNotice @dangGao="goNoticeDetail" :list="noticeList" :backgroundColor="'#FFFFFF'"></lwNotice>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
@ -228,14 +227,13 @@
|
|||
// 暂无更多组件
|
||||
import pitera from '@/components/nothing/pitera.vue';
|
||||
// 公告
|
||||
import lwNotice from '@/components/lw-notice/lw-notice.vue';
|
||||
import footTabOne from '@/components/foot-tabs/foot-tab-one.vue';
|
||||
import containerSubgroupTwo from '@/components/containers/container-subgroup-two.vue';
|
||||
import { mapState,mapGetters,mapMutations } from 'vuex'//引入mapState
|
||||
export default {
|
||||
components:{
|
||||
pitera,
|
||||
statusNavSlot,
|
||||
lwNotice,
|
||||
'foot-tab' :footTabOne,
|
||||
containerSubgroupTwo
|
||||
},
|
||||
|
@ -313,6 +311,62 @@
|
|||
faultsList:[],
|
||||
}
|
||||
},
|
||||
// computed:{
|
||||
// tokenEv() {
|
||||
// return this.$store.state.token;
|
||||
// }
|
||||
// },
|
||||
// computed:mapState({
|
||||
// // 从state中拿到数据 箭头函数可使代码更简练
|
||||
// token: state => state.token,
|
||||
// }),
|
||||
// computed:mapState(['token']),
|
||||
// computed: {
|
||||
// ...mapState({
|
||||
// token: function (state) {
|
||||
// return '追加的' + state.token
|
||||
// },
|
||||
// userInfo: state => state.userInfo,
|
||||
// })
|
||||
// },
|
||||
// computed: {
|
||||
// todos() {
|
||||
// return this.$store.getters.doneTodos
|
||||
// }
|
||||
// },
|
||||
// computed: {
|
||||
// doneTodosCount() {
|
||||
// return this.$store.getters.doneTodosCount
|
||||
// }
|
||||
// },
|
||||
// computed: {
|
||||
// getTodoById() {
|
||||
// return this.$store.getters.getTodoById(1)
|
||||
// }
|
||||
// },
|
||||
// computed: {
|
||||
// // 使用对象展开运算符将 getter 混入 computed 对象中
|
||||
// ...mapGetters([
|
||||
// 'doneTodos',
|
||||
// 'doneTodosCount',
|
||||
// 'getTodoById'
|
||||
// // ...
|
||||
// ])
|
||||
// },
|
||||
// computed:{
|
||||
// ...mapState([
|
||||
// 'token',
|
||||
// 'userInfo',
|
||||
// 'count',
|
||||
// 'obj'
|
||||
// ])
|
||||
// },
|
||||
computed: {
|
||||
...mapState({
|
||||
token: state => state.moduleA.token,
|
||||
count: state => state.moduleB.count
|
||||
}),
|
||||
},
|
||||
onLoad(options) {
|
||||
// 获取当前页面url
|
||||
this.$toolAll.tools.obtainUrl();
|
||||
|
@ -322,8 +376,29 @@
|
|||
// this.getIncrementServiceType();
|
||||
// 调用获取常见故障列表事件
|
||||
this.getFaultsList();
|
||||
// this.$store.commit('setToken', 'token已改变');
|
||||
// this.$store.commit('updateUserInfo',{userInfo:'用户信息'})
|
||||
// this.$store.commit({
|
||||
// type: 'updateUserInfo',
|
||||
// userInfo: '新方式更新用户信息'
|
||||
// })
|
||||
// console.log(this.userInfo,374);
|
||||
// this.add();
|
||||
// console.log(this.obj);
|
||||
// this.$store.commit('newProp',{c:'吃火锅'})
|
||||
// console.log(this.obj,382);
|
||||
// this.$store.dispatch('addCountAction')
|
||||
// this.$store.dispatch('addCountAction2',{amount:10})
|
||||
// this.$store.dispatch('addCountAction3',{amount:30})
|
||||
// setTimeout(()=>{
|
||||
// console.log(this.count,388);
|
||||
// },3000)
|
||||
// console.log(this.count,390);
|
||||
console.log(this.token,397);
|
||||
console.log(this.count,398);
|
||||
},
|
||||
methods: {
|
||||
// ...mapMutations(['add']),//对象展开运算符直接拿到add
|
||||
// 工单跳转
|
||||
goWorkOrder(index){
|
||||
if(index==0){
|
||||
|
|
|
@ -1,16 +1,19 @@
|
|||
<template>
|
||||
<view>
|
||||
<notice-one direction="row"></notice-one>
|
||||
<!-- 底部tab -->
|
||||
<foot-tab :current="1"></foot-tab>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import noticeOne from '@/components/notices/notice-one/notice-one.vue';
|
||||
// 底部组件
|
||||
import footTabOne from '@/components/foot-tabs/foot-tab-one.vue';
|
||||
export default {
|
||||
components:{
|
||||
'foot-tab' :footTabOne
|
||||
'foot-tab' :footTabOne,
|
||||
noticeOne
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
|
|
|
@ -24,8 +24,8 @@
|
|||
<view class="bacf fon28 pad-sx30 pad-zy40 mar-s20">
|
||||
<view class="fon30 bold mar-sx30">您的评价</view>
|
||||
<view class="mar-s40 mar-x50" style="color: #545454;">
|
||||
<view class="mar-x40 disac"><text class="mar-y40">技术服务</text><rate :size="42" :gutter="40" :curentClick="0" v-model="rateNum" @change="chooseRate"></rate></view>
|
||||
<view class="disac"><text class="mar-y40">客服态度</text><rate :size="42" :gutter="40" :curentClick="1" v-model="attitudeNum" @change="chooseRate"></rate></view>
|
||||
<view class="mar-x40 disac"><text class="mar-y40">技术服务</text><rate-one :size="42" :gutter="40" :curentClick="0" v-model="rateNum" @change="chooseRate"></rate-one></view>
|
||||
<view class="disac"><text class="mar-y40">客服态度</text><rate-one :size="42" :gutter="40" :curentClick="1" v-model="attitudeNum" @change="chooseRate"></rate-one></view>
|
||||
</view>
|
||||
</view>
|
||||
<!-- 提交保存 -->
|
||||
|
@ -36,10 +36,10 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import rate from '@/components/rate.vue';
|
||||
import rateOne from '@/components/rates/rate-one.vue';
|
||||
export default {
|
||||
components:{
|
||||
rate
|
||||
rateOne
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
// 根级别的 action
|
|
@ -0,0 +1,16 @@
|
|||
// 组装模块并导出 store 的地方
|
||||
import Vue from 'vue'
|
||||
import Vuex from 'vuex'
|
||||
import moduleA from '@/store/modules/moduleA'
|
||||
import moduleB from '@/store/modules/moduleB'
|
||||
|
||||
Vue.use(Vuex);//vue的插件机制
|
||||
|
||||
//Vuex.modules 模块选项
|
||||
const store = new Vuex.Store({
|
||||
modules: {
|
||||
moduleA,
|
||||
moduleB
|
||||
}
|
||||
})
|
||||
export default store
|
|
@ -0,0 +1,88 @@
|
|||
// 购物车模块
|
||||
export default {
|
||||
state:{//存放状态
|
||||
token:'token已生成',
|
||||
userInfo:{},
|
||||
count:0,
|
||||
publicColor:'',
|
||||
todos: [{
|
||||
id: 1,
|
||||
text: '我是内容一',
|
||||
done: true
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
text: '我是内容二',
|
||||
done: false
|
||||
}
|
||||
],
|
||||
obj:{
|
||||
a:'吃鸡腿',
|
||||
b:'吃自助餐'
|
||||
}
|
||||
},
|
||||
// Vuex中store数据改变的唯一方法就是mutations 不适合异步方法
|
||||
mutations: {
|
||||
add(state) {
|
||||
state.count = 7;
|
||||
},
|
||||
add2(state, payload) {
|
||||
state.count = payload.amount;
|
||||
},
|
||||
// 单个属性处理方法
|
||||
setToken(state,str) {
|
||||
state.token = str;
|
||||
},
|
||||
// 对象处理方法
|
||||
updateUserInfo(state, payload) {
|
||||
// 变更状态
|
||||
state.userInfo = payload.userInfo;
|
||||
},
|
||||
// 新增字段方法
|
||||
newProp(state,payload) {
|
||||
state.obj = { ...state.obj, c: payload.c };
|
||||
}
|
||||
},
|
||||
// 可以执行任意的同步和异步操作
|
||||
actions:{
|
||||
addCountAction ({commit}) {
|
||||
commit('add')
|
||||
},
|
||||
addCountAction2 (context , payload) {
|
||||
context.commit('add2', payload)
|
||||
},
|
||||
// 异步方法
|
||||
addCountAction3 (context , payload) {
|
||||
setTimeout(function () {
|
||||
context.commit('add2', payload)
|
||||
}, 2000)
|
||||
},
|
||||
actionA ({ commit }) {
|
||||
return new Promise((resolve, reject) => {
|
||||
setTimeout(() => {
|
||||
commit('someMutation')
|
||||
resolve()
|
||||
}, 1000)
|
||||
})
|
||||
},
|
||||
actionB ({ dispatch, commit }) {
|
||||
return dispatch('actionA').then(() => {
|
||||
commit('someOtherMutation')
|
||||
})
|
||||
}
|
||||
},
|
||||
// Vuex 允许我们在 store 中定义“getter”(可以认为是 store 的计算属性),对 state 的加工,是派生出来的数据。 可以在多组件中共享 getter 函数,这样做还可以提高运行效率。
|
||||
getters: {
|
||||
doneTodos: state => {
|
||||
return state.todos.filter(todo => todo.done)
|
||||
},
|
||||
doneTodosCount: (state, getters) => {
|
||||
//state :可以访问数据
|
||||
//getters:访问其他函数,等同于 store.getters
|
||||
return getters.doneTodos.length
|
||||
},
|
||||
getTodoById: (state) => (id) => {
|
||||
return state.todos.find(todo => todo.id === id)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,87 @@
|
|||
export default {
|
||||
state:{//存放状态
|
||||
token:'token已生成',
|
||||
userInfo:{},
|
||||
count:0,
|
||||
publicColor:'',
|
||||
todos: [{
|
||||
id: 1,
|
||||
text: '我是内容一',
|
||||
done: true
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
text: '我是内容二',
|
||||
done: false
|
||||
}
|
||||
],
|
||||
obj:{
|
||||
a:'吃鸡腿',
|
||||
b:'吃自助餐'
|
||||
}
|
||||
},
|
||||
// Vuex中store数据改变的唯一方法就是mutations 不适合异步方法
|
||||
mutations: {
|
||||
add(state) {
|
||||
state.count = 7;
|
||||
},
|
||||
add2(state, payload) {
|
||||
state.count = payload.amount;
|
||||
},
|
||||
// 单个属性处理方法
|
||||
setToken(state,str) {
|
||||
state.token = str;
|
||||
},
|
||||
// 对象处理方法
|
||||
updateUserInfo(state, payload) {
|
||||
// 变更状态
|
||||
state.userInfo = payload.userInfo;
|
||||
},
|
||||
// 新增字段方法
|
||||
newProp(state,payload) {
|
||||
state.obj = { ...state.obj, c: payload.c };
|
||||
}
|
||||
},
|
||||
// 可以执行任意的同步和异步操作
|
||||
actions:{
|
||||
addCountAction ({commit}) {
|
||||
commit('add')
|
||||
},
|
||||
addCountAction2 (context , payload) {
|
||||
context.commit('add2', payload)
|
||||
},
|
||||
// 异步方法
|
||||
addCountAction3 (context , payload) {
|
||||
setTimeout(function () {
|
||||
context.commit('add2', payload)
|
||||
}, 2000)
|
||||
},
|
||||
actionA ({ commit }) {
|
||||
return new Promise((resolve, reject) => {
|
||||
setTimeout(() => {
|
||||
commit('someMutation')
|
||||
resolve()
|
||||
}, 1000)
|
||||
})
|
||||
},
|
||||
actionB ({ dispatch, commit }) {
|
||||
return dispatch('actionA').then(() => {
|
||||
commit('someOtherMutation')
|
||||
})
|
||||
}
|
||||
},
|
||||
// Vuex 允许我们在 store 中定义“getter”(可以认为是 store 的计算属性),对 state 的加工,是派生出来的数据。 可以在多组件中共享 getter 函数,这样做还可以提高运行效率。
|
||||
getters: {
|
||||
doneTodos: state => {
|
||||
return state.todos.filter(todo => todo.done)
|
||||
},
|
||||
doneTodosCount: (state, getters) => {
|
||||
//state :可以访问数据
|
||||
//getters:访问其他函数,等同于 store.getters
|
||||
return getters.doneTodos.length
|
||||
},
|
||||
getTodoById: (state) => (id) => {
|
||||
return state.todos.find(todo => todo.id === id)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
// 根级别的 mutation
|
Loading…
Reference in New Issue