Commit 8dc1f9dc authored by xinzhedeai's avatar xinzhedeai

init

parents
Pipeline #439 failed with stages
<script>
/**
* vuex管理登陆状态,具体可以参考官方登陆模板示例
*/
import {
mapMutations
} from 'vuex';
export default {
methods: {
...mapMutations(['login'])
},
onLaunch: function() {
let userInfo = uni.getStorageSync('userInfo') || '';
if(userInfo.id){
//更新登陆状态
uni.getStorage({
key: 'userInfo',
success: (res) => {
this.login(res.data);
}
});
}
},
onShow: function() {
console.log('App Show')
},
onHide: function() {
console.log('App Hide')
},
}
</script>
<style lang='scss'>
/* 注意要写在第一行,同时给style标签加入lang="scss"属性 */
@import "@/uni_modules/uview-ui/index.scss";
@import "@/common/css/common.scss";
@import '@/common/css/iconfont.css';
.yellow{
color: #FFD64B;
}
/* input 样式 */
.input-placeholder {
color: #999999;
}
.placeholder {
color: #999999;
}
</style>
This diff is collapsed.
.cateWrapper{ // 分类容器样式
padding-top: 20rpx;
padding-bottom: 20rpx;
background: #f7f7f7;
}
.c-yellow{
color: #FFD64B;
}
.uicon-star, .uicon-star-fill{
color: #FFD64B !important;
}
.tabWrapper{
position: relative;
// background: url('/static/minestar/bottomLine.png');
.line{
position: absolute;
top: 45px;
width: 100%;
border-bottom: 1px solid #af9a9a;
box-shadow: 1px 1px 1px 0px #dacbcb;
}
}
\ No newline at end of file
@font-face {
font-family: "iconfont"; /* Project id 4336045 */
src: url('//at.alicdn.com/t/c/font_4336045_ci591mr68gj.woff2?t=1700285315700') format('woff2'),
url('//at.alicdn.com/t/c/font_4336045_ci591mr68gj.woff?t=1700285315700') format('woff'),
url('//at.alicdn.com/t/c/font_4336045_ci591mr68gj.ttf?t=1700285315700') format('truetype');
}
.iconfont {
font-family: "iconfont" !important;
font-size: 16px;
font-style: normal;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.icon-Setup:before {
content: "\e63d";
}
.icon-star:before {
content: "\e65e";
}
.icon-star1:before {
content: "\e617";
}
import Vue from 'vue'
import { resErrorDeal } from './util.js'
import msgTip from "./msgTip.js"
// const BASEURL = 'http://192.168.3.23:8086' // 研发环境url
const BASEURL = 'http://117.34.103.191:8086' // 生产环境url
export default {
/**
* 封装请求(async await 封装uni.request)
*/
async call(paramObj) {
let resultObj = false, cb = paramObj.cb;
let header = {
'Accept':'application/json, text/plain, */*',
}
if(uni.getStorageSync('userInfo')){
header['Authorization'] = 'Bearer ' + JSON.parse(uni.getStorageSync('userInfo')).token
}
let opt = {
url: BASEURL + paramObj.url, // 域名+接口地址
data: paramObj.data,
method: paramObj.method || 'GET',
loadFlag: paramObj.loadFlag === "N" ? false : true ,// 默认带有加载条
timeout: paramObj.timeout || 1200000, // 默认登录超时时间20min
sslVerify: false,
header
}
if (opt.loadFlag) { // 请求是加载进度条
msgTip.showLoading()
}
console.log('请求信息', JSON.stringify(opt))
let [error, response] = await uni.request(opt);
if(response === undefined){
msgTip.toast('网络错误')
msgTip.showLoading(false)
return
}
if(!response.data){
msgTip.toast('网络错误')
msgTip.showLoading(false)
return
}
const resData = response.data
if(resData.code === 200){
cb && cb(resData) // 自定义处理回调函数
if(paramObj.showSuccessTip){ // 成功调用接口时,默认不显示提醒信息
msgTip.toast(resData.message)
}
}else{
resErrorDeal(response)
}
uni.hideLoading()
console.log('登录响应信息', response)
},
}
\ No newline at end of file
export const customTabar = {
data() {
return {
navHeight: 0,
customTop: 0,
customHeight: 0,
};
},
computed: {},
created() {
/**
* 计算自定义导航栏位置
*/
let custom = uni.getMenuButtonBoundingClientRect(); // 小程序右上角胶囊信息
let system = uni.getSystemInfoSync(); // 获取设备信息
this.navHeight = system.statusBarHeight + 44; // 导航栏的高度
this.customTop = custom.top; // 胶囊按钮与顶部的距离
this.customHeight = custom.height; // 胶囊按钮与右侧的距离
console.log(this.navHeight, this.customTop, this.customHeight)
},
mounted() {
console.log("我是mixin中的mounted生命周期函数");
},
methods: {
clickMe() {
console.log("我是mixin中的点击事件");
},
},
};
\ No newline at end of file
/**
* 确认提示框
*/
const confirmModal = (config) => {
uni.showModal({
title: config.title || '信息提示',
content: config.content || '确认要继续该操作吗',
showCancel: config.showCancel !== 'NO',
confirmText: config.confirmText || '确定',
cancelText: config.cancelText ||'取消',
success: (res) => {
console.log('***confirmmodasl**', res)
if (res.confirm) {
config.cb && config.cb(true)
} else if (res.cancel) {
config.cb && config.cb(false)
}
}
});
}
/**
* 显示提示框
*/
const toast = (title, icon = 'none', duration = 2800) => {
setTimeout(()=>{
uni.showToast({
title,
icon,
duration //显示时间
});
}, 0)
}
const showLoading = (showFlag = true) => {
if(showFlag){
uni.showLoading({
title: '正在加载中...',
mask: true
});
}else{
uni.hideLoading()
}
}
const hideKeyboard = () => {
uni.hideKeyboard()
}
export default {
confirmModal,
toast,
showLoading,
hideKeyboard
}
\ No newline at end of file
import msgTip from "./msgTip.js"
function formatTime(time) {
if (typeof time !== 'number' || time < 0) {
return time
}
var hour = parseInt(time / 3600)
time = time % 3600
var minute = parseInt(time / 60)
time = time % 60
var second = time
return ([hour, minute, second]).map(function(n) {
n = n.toString()
return n[1] ? n : '0' + n
}).join(':')
}
function formatLocation(longitude, latitude) {
if (typeof longitude === 'string' && typeof latitude === 'string') {
longitude = parseFloat(longitude)
latitude = parseFloat(latitude)
}
longitude = longitude.toFixed(2)
latitude = latitude.toFixed(2)
return {
longitude: longitude.toString().split('.'),
latitude: latitude.toString().split('.')
}
}
var dateUtils = {
UNITS: {
'': 31557600000,
'': 2629800000,
'': 86400000,
'小时': 3600000,
'分钟': 60000,
'': 1000
},
humanize: function(milliseconds) {
var humanize = '';
for (var key in this.UNITS) {
if (milliseconds >= this.UNITS[key]) {
humanize = Math.floor(milliseconds / this.UNITS[key]) + key + '';
break;
}
}
return humanize || '刚刚';
},
format: function(dateStr) {
var date = this.parse(dateStr)
var diff = Date.now() - date.getTime();
if (diff < this.UNITS['']) {
return this.humanize(diff);
}
var _format = function(number) {
return (number < 10 ? ('0' + number) : number);
};
return date.getFullYear() + '/' + _format(date.getMonth() + 1) + '/' + _format(date.getDate()) + '-' +
_format(date.getHours()) + ':' + _format(date.getMinutes());
},
parse: function(str) { //将"yyyy-mm-dd HH:MM:ss"格式的字符串,转化为一个Date对象
var a = str.split(/[^0-9]/);
return new Date(a[0], a[1] - 1, a[2], a[3], a[4], a[5]);
}
};
const resErrorDeal = (response) => {
const res = response.data
if(!res){
return
}
if(res.code === 401){
msgTip.confirmModal({
content: '系统登录超时,请重新登录',
showCancel: 'NO',
cb: (res) => {
if (res) {
uni.reLaunch({
url: '/pages/login'
});
}
}
});
}else{
msgTip.confirmModal({
content: res.message,
showCancel: 'NO'
})
}
}
export {
formatTime,
formatLocation,
dateUtils,
resErrorDeal
}
<template>
<view style="width: 94vw; margin: 0 auto;">
<scroll-view class="scroll-view_H" scroll-x="true" :enable-flex="true">
<view class="cate-section">
<view class="cate-item" v-for="(item, index) in dataList" >
<image :src="item.src"></image>
<text class="ellipse" style="font-size:24rpx;">{{item.name}}</text>
</view>
</view>
</scroll-view>
</view>
</template>
<script>
export default {
name:"cate-list",
// props: ['dataList'],
props: {
dataList: {
type: Array,
default: function() {
return [{
src: '/static/minestar/01.png',
name: '地质'
},{
src: '/static/minestar/02.png',
name: '测绘'
},{
src: '/static/minestar/03.png',
name: '通风'
},{
src: '/static/minestar/04.png',
name: '采矿'
},{
src: '/static/minestar/05.png',
name: '爆破'
},]
}
},
},
data() {
return {
};
},
onLoad() {
console.log(this.$parent)
}
}
</script>
<style lang="scss" scoped>
.ellipse{
@include ellipse();
}
/* 分类 */
.cate-section {
display: flex;
justify-content: flex-start;
align-items: center;
// padding: 30upx 22upx;
background: #f7f7f7;
.cate-item {
display: flex;
flex-direction: column;
align-items: center;
margin-right: 68rpx;
font-size: $font-sm + 2upx;
font-weight: bold;
color: $font-color-dark;
text{
font-size: 20rpx;
}
}
/* 原图标颜色太深,不想改图了,所以加了透明度 */
image {
width: 88upx;
height: 88upx;
margin-bottom: 14upx;
border-radius: 50%;
opacity: .7;
box-shadow: 4upx 4upx 20upx rgba(250, 67, 106, 0.3);
}
}
</style>
\ No newline at end of file
This diff is collapsed.
<template>
<view>
<view class="list-item" v-for="(item, index) in dataList" :key="index">
<view class="topper">
<view class="header">
<image v-if="item.flag==='new'" src="../static/minestar/new.png"></image>
<image v-if="item.flag==='hot'" src="../static/minestar/hot.png"></image>
<i class='iconfont icon-star' v-if="item.collect"></i>
<i class='iconfont icon-star1' v-if="!item.collect"></i>
<!-- <u-icon name="star-fill" v-if="item.collect" size="18px"></u-icon>
<u-icon name="star" v-if="!item.collect" size="18px"></u-icon> -->
</view>
<view class="body">
<u-avatar
slot="icon"
shape="square"
size="50"
:src="item.src"
customStyle="margin-right:30px"
></u-avatar>
<view>
<p>{{item.name}}</p>
<u--text type="info" :text="item.desc" size="12"></u--text>
</view>
</view>
<view class="tag">
<template v-for="(label, index1) in item.labels">
<div style="" >{{label.name}}</div>
</template>
</view>
</view>
<view class="footer">
<text class="text">HOT:5151</text>
</view>
</view>
</view>
</template>
<script>
export default {
name:"list-item",
props: {
dataList: {
type: Array,
default: function() {
return [{
src: '/static/minestar/厚度计算.png',
name: '体积计算',
desc: '计算器',
collect: true,
flag: 'hot',
labels: [{
name: '计算器',
bgcolor: 'pink'
}]
},{
src: '/static/minestar/体积计算.png',
name: '体积计算',
desc: '计算器',
collect: false,
flag: 'new',
labels: [{
name: '计算器',
bgcolor: 'pink'
}]
},{
src: '/static/minestar/平均品位计算.png',
name: '体积计算',
desc: '计算器',
collect: true,
labels: [{
name: '计算器',
bgcolor: 'pink'
}]
},{
src: '/static/minestar/岩层厚度.png',
name: '体积计算',
desc: '计算器',
collect: true,
labels: [{
name: '计算器计算器',
bgcolor: 'pink'
},{
name: '断面计算',
bgcolor: 'pink'
}]
},{
src: '/static/minestar/巷道横截面计算.png',
name: '体积计算',
desc: '计算器',
collect: false,
labels: [{
name: '计算器',
bgcolor: 'pink'
}]
},]
}
},
},
data() {
return {
};
}
}
</script>
<style scoped lang="scss">
@mixin rounded-corners{
border-radius: 20rpx;
}
@mixin tag($width:32px, $height:16px, $bgcolor:#fff, $fontsize:12px){
padding: 0px 2px;
margin-right: 2px;
min-width: 64rpx;
height: $height;
line-height: $height;
background-color: $bgcolor;
font-size: $fontsize;
text-align: center;
border-radius: 4px;
}
.list-item{
position: relative;
margin-top: 10upx;
background-color: #fff;
.topper{
padding: 0 40upx;
}
}
.header, .body, .tag, .footer{
display: flex;
}
.header{
justify-content: space-between;
image{
width: 50rpx;
height: 50rpx;
position: absolute;
left: 0;
}
.iconfont{
color: #FFD64B;
position: absolute;
right: 20rpx;
top: 8rpx;
}
}
.body{
justify-content: flex-start;
height: 120upx;
align-items: center;
p{
font-size: 30upx;
font-weight: bold;
}
}
.tag{
justify-content: flex-end;
padding-bottom: 8upx;
div{
//color: #fff;background-color: orangered;width: 42upx;height: 22upx;line-height: 22upx;font-size: 20upx;
@include tag($bgcolor: pink);
}
}
.footer{
justify-content: flex-end;
border-top: 1upx solid lightgray;
padding-right: 20px;
.text{
font-size: 22upx;
color: darkgray;
}
}
</style>
\ No newline at end of file
<template>
<view v-if="show" class="mask" @click="toggleMask" @touchmove.stop.prevent="stopPrevent"
:style="{backgroundColor: backgroundColor}"
>
<view
class="mask-content"
@click.stop.prevent="stopPrevent"
:style="[{
height: config.height,
transform: transform
}]"
>
<scroll-view class="view-content" scroll-y>
<view class="share-header">
分享到
</view>
<view class="share-list">
<view
v-for="(item, index) in shareList" :key="index"
class="share-item"
@click="shareToFriend(item.text)"
>
<image :src="item.icon" mode=""></image>
<text>{{item.text}}</text>
</view>
</view>
</scroll-view>
<view class="bottom b-t" @click="toggleMask">取消</view>
</view>
</view>
</template>
<script>
export default {
data() {
return {
transform: 'translateY(50vh)',
timer: 0,
backgroundColor: 'rgba(0,0,0,0)',
show: false,
config: {},
};
},
props:{
contentHeight:{
type: Number,
default: 0
},
//是否是tabbar页面
hasTabbar:{
type: Boolean,
default: false
},
shareList:{
type: Array,
default: function(){
return [];
}
}
},
created() {
const height = uni.upx2px(this.contentHeight) + 'px';
this.config = {
height: height,
transform: `translateY(${height})`,
backgroundColor: 'rgba(0,0,0,.4)',
}
this.transform = this.config.transform;
},
methods:{
toggleMask(){
//防止高频点击
if(this.timer == 1){
return;
}
this.timer = 1;
setTimeout(()=>{
this.timer = 0;
}, 500)
if(this.show){
this.transform = this.config.transform;
this.backgroundColor = 'rgba(0,0,0,0)';
setTimeout(()=>{
this.show = false;
this.hasTabbar && uni.showTabBar();
}, 200)
return;
}
this.show = true;
//等待mask重绘完成执行
if(this.hasTabbar){
uni.hideTabBar({
success: () => {
setTimeout(()=>{
this.backgroundColor = this.config.backgroundColor;
this.transform = 'translateY(0px)';
}, 10)
}
});
}else{
setTimeout(()=>{
this.backgroundColor = this.config.backgroundColor;
this.transform = 'translateY(0px)';
}, 10)
}
},
//防止冒泡和滚动穿透
stopPrevent(){},
//分享操作
shareToFriend(type){
this.$api.msg(`分享给${type}`);
this.toggleMask();
},
}
}
</script>
<style lang='scss'>
.mask{
position:fixed;
left: 0;
top: 0;
right: 0;
bottom: 0;
display:flex;
justify-content: center;
align-items: flex-end;
z-index: 998;
transition: .3s;
.bottom{
position:absolute;
left: 0;
bottom: 0;
display:flex;
justify-content: center;
align-items: center;
width: 100%;
height: 90upx;
background: #fff;
z-index: 9;
font-size: $font-base + 2upx;
color: $font-color-dark;
}
}
.mask-content{
width: 100%;
height: 580upx;
transition: .3s;
background: #fff;
&.has-bottom{
padding-bottom: 90upx;
}
.view-content{
height: 100%;
}
}
.share-header{
height: 110upx;
font-size: $font-base+2upx;
color: font-color-dark;
display:flex;
align-items:center;
justify-content: center;
padding-top: 10upx;
&:before, &:after{
content: '';
width: 240upx;
heighg: 0;
border-top: 1px solid $border-color-base;
transform: scaleY(.5);
margin-right: 30upx;
}
&:after{
margin-left: 30upx;
margin-right: 0;
}
}
.share-list{
display:flex;
flex-wrap: wrap;
}
.share-item{
min-width: 33.33%;
display:flex;
flex-direction: column;
justify-content: center;
align-items: center;
height: 180upx;
image{
width: 80upx;
height: 80upx;
margin-bottom: 16upx;
}
text{
font-size: $font-base;
color: $font-color-base;
}
}
</style>
<template>
<view class="uni-numbox">
<view class="uni-numbox-minus"
@click="_calcValue('subtract')"
>
<text class="yticon icon--jianhao" :class="minDisabled?'uni-numbox-disabled': ''" ></text>
</view>
<input
class="uni-numbox-value"
type="number"
:disabled="disabled"
:value="inputValue"
@blur="_onBlur"
>
<view
class="uni-numbox-plus"
@click="_calcValue('add')"
>
<text class="yticon icon-jia2" :class="maxDisabled?'uni-numbox-disabled': ''" ></text>
</view>
</view>
</template>
<script>
export default {
name: 'uni-number-box',
props: {
isMax: {
type: Boolean,
default: false
},
isMin: {
type: Boolean,
default: false
},
index: {
type: Number,
default: 0
},
value: {
type: Number,
default: 0
},
min: {
type: Number,
default: -Infinity
},
max: {
type: Number,
default: Infinity
},
step: {
type: Number,
default: 1
},
disabled: {
type: Boolean,
default: false
}
},
data() {
return {
inputValue: this.value,
minDisabled: false,
maxDisabled: false
}
},
created(){
this.maxDisabled = this.isMax;
this.minDisabled = this.isMin;
},
computed: {
},
watch: {
inputValue(number) {
const data = {
number: number,
index: this.index
}
this.$emit('eventChange', data);
}
},
methods: {
_calcValue(type) {
const scale = this._getDecimalScale();
let value = this.inputValue * scale;
let newValue = 0;
let step = this.step * scale;
if(type === 'subtract'){
newValue = value - step;
if (newValue <= this.min){
this.minDisabled = true;
}
if(newValue < this.min){
newValue = this.min
}
if(newValue < this.max && this.maxDisabled === true){
this.maxDisabled = false;
}
}else if(type === 'add'){
newValue = value + step;
if (newValue >= this.max){
this.maxDisabled = true;
}
if(newValue > this.max){
newValue = this.max
}
if(newValue > this.min && this.minDisabled === true){
this.minDisabled = false;
}
}
if(newValue === value){
return;
}
this.inputValue = newValue / scale;
},
_getDecimalScale() {
let scale = 1;
// 浮点型
if (~~this.step !== this.step) {
scale = Math.pow(10, (this.step + '').split('.')[1].length);
}
return scale;
},
_onBlur(event) {
let value = event.detail.value;
if (!value) {
this.inputValue = 0;
return
}
value = +value;
if (value > this.max) {
value = this.max;
} else if (value < this.min) {
value = this.min
}
this.inputValue = value
}
}
}
</script>
<style>
.uni-numbox {
position:absolute;
left: 30upx;
bottom: 0;
display: flex;
justify-content: flex-start;
align-items: center;
width:230upx;
height: 70upx;
background:#f5f5f5;
}
.uni-numbox-minus,
.uni-numbox-plus {
margin: 0;
background-color: #f5f5f5;
width: 70upx;
height: 100%;
line-height: 70upx;
text-align: center;
position: relative;
}
.uni-numbox-minus .yticon,
.uni-numbox-plus .yticon{
font-size: 36upx;
color: #555;
}
.uni-numbox-minus {
border-right: none;
border-top-left-radius: 6upx;
border-bottom-left-radius: 6upx;
}
.uni-numbox-plus {
border-left: none;
border-top-right-radius: 6upx;
border-bottom-right-radius: 6upx;
}
.uni-numbox-value {
position: relative;
background-color: #f5f5f5;
width: 90upx;
height: 50upx;
text-align: center;
padding: 0;
font-size: 30upx;
}
.uni-numbox-disabled.yticon {
color: #d6d6d6;
}
</style>
<template>
<view class="upload-content">
<block v-for="(item, index) in imageList" :key="index">
<view class="upload-item">
<image class="upload-img" :src="item.filePath" mode="aspectFill" @click="previewImage(index)"></image>
<image class="upload-del-btn"
@click="delImage(index)"
src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACYAAAAmCAYAAACoPemuAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyJpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMy1jMDExIDY2LjE0NTY2MSwgMjAxMi8wMi8wNi0xNDo1NjoyNyAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNiAoV2luZG93cykiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6RjNBODgzQjUwNDM5MTFFOUJDMjlGN0UwRTJGMjVCNjQiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6RjNBODgzQjYwNDM5MTFFOUJDMjlGN0UwRTJGMjVCNjQiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDpGM0E4ODNCMzA0MzkxMUU5QkMyOUY3RTBFMkYyNUI2NCIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDpGM0E4ODNCNDA0MzkxMUU5QkMyOUY3RTBFMkYyNUI2NCIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PuYQTIAAAAHNSURBVHjazJgxasMwFIbjnsD4BDmCLxDQDZrNQ5bcILlBvXvpDRLIWmiHFkyH2t0LyVbwEkPpbE/eYlUCGYQax096UuIffkIgij7ryU/vyZuYy2e+Z56K70R8lsJcOfPn5AriMCvmZ2YKdMW8EQ/hRA9iEorwXlpZtObMRySQ6kysvrFWloHUEIcmUBuHUDLccmxQskErt7wyVLdy00tQ4Q2g5De2V9kNwWjffiNDA33f/42i6E13Qj5uNptlwJD+SyODuaqqqi/KVBTFOxSKA7VtW/NxSZI8AcbE2nuraZpvKgSBk6G4drsdBOwogz1CwAghH/JEl+BUKJ1VltPHHjoIAoeE4l53YFqb+RKcBSgqyqXhtxEKZwkKB3YOThYCqjPuCDoHZwGK3mGLtdPp5LmqTI1Dqe4p26EkNqA4iE6eg2z+iQ0okyQMATvYgLIIt9Y6knTyFBIudHqIq3BpmkL60VJ9O0sXZY8MBwSLtdNGEAQ/i8XiVXcz83EcEPDbuq/fzMdYWt+6GTmMsX2rh9q3TtsxNrzXhKt1rwg6rR1Dhdjqo7QMlWOvoWTF4imxQMRF7eaL8L5ohmwrLgDB8pCQc8DlcG7y538CDABJNGPqfaJgfgAAAABJRU5ErkJggg=="
mode="scaleToFill">
</image>
<view class="upload-progress" v-if="item.progress < 100">{{item.progress}}%</view>
</view>
</block>
<view class="upload-add-btn" v-if="rduLength > 0" @click="chooseImage"></view>
</view>
</template>
<script>
export default {
data() {
return {
imageList: []
};
},
props: {
url: {
type: String,
value: '' //上传接口地址
},
count: {
type: Number,
value: 4 //单次可选择的图片数量
},
length: {
type: Number,
value: 50 //可上传总数量
}
},
computed: {
rduLength(){
return this.length - this.imageList.length;
}
},
methods: {
//选择图片
chooseImage: function(){
uni.chooseImage({
count: this.rduLength < this.count ? this.rduLength : this.count, //最多可以选择的图片张数,默认9
sizeType: ['original', 'compressed'], //original 原图,compressed 压缩图,默认二者都有
sourceType: ['album'], //album 从相册选图,camera 使用相机,默认二者都有
success: (res)=> {
const images = res.tempFilePaths;
this.uploadFiles(images);
}
});
},
//上传图片
async uploadFiles(images){
this.imageList.push({
filePath: images[0],
progress: 0
});
uni.showLoading({
title: '请稍后..',
mask: true,
})
try{
const uploadUrl = await this.uploadImage(images[0]);
}catch(err){
console.log(err);
return;
}
if(uploadUrl !== false){
images.splice(0, 1);
this.imageList[this.imageList.length - 1].src = uploadUrl;
//判断是否需要继续上传
if(images.length > 0 && this.rduLength > 0){
this.uploadFiles(images);
}else{
uni.hideLoading();
}
}else{
//上传失败处理
this.imageList.pop();
uni.hideLoading();
uni.showToast({
title: '上传中出现问题,已终止上传',
icon: 'none',
mask: true,
duration: 2000
});
}
},
uploadImage: function(file){
return new Promise((resolve, reject)=> {
//发送给后端的附加参数
const formData = {
thumb_mode: 1,
};
this.uploadTask = uni.uploadFile({
url: this.url,
filePath: file,
name: 'file',
formData: formData,
success(uploadFileResult){
const uploadFileRes = JSON.parse(uploadFileResult.data) || {};
if(uploadFileRes.status === 1 && uploadFileRes.data){
resolve(uploadFileRes.data);
}else{
reject('接口返回错误');
}
},
fail(){
reject('网络链接错误');
}
});
//上传进度
this.uploadTask.onProgressUpdate((progressRes)=> {
this.imageList[this.imageList.length - 1].progress = progressRes.progress;
});
});
},
//删除图片
delImage: function(index){
uni.showModal({
content: '确定要放弃这张图片么?',
success: (confirmRes)=> {
if (confirmRes.confirm) {
this.imageList.splice(index, 1);
}
}
});
},
//预览图片
previewImage: function(index){
const urls = [];
this.imageList.forEach((item)=> {
urls.push(item.filePath);
})
uni.previewImage({
current: urls[index],
urls: urls,
indicator: "number"
})
}
}
}
</script>
<style lang="scss">
.upload-content{
padding:24upx 0 0 28upx;
background-color: #fff;
overflow:hidden;
}
.upload-item{
position: relative;
float:left;
width:150upx;
height:150upx;
margin-right:30upx;
margin-bottom:30upx;
&:nth-child(4n){
margin-right:0;
}
.upload-img{
width:100%;
height:100%;
border-radius:8upx;
}
.upload-del-btn{
position: absolute;
right:-16upx;
top:-14upx;
width:36upx;
height:36upx;
border: 4upx solid #fff;
border-radius: 100px;
}
.upload-progress{
position: absolute;
left:0;
top:0;
display:flex;
align-items:center;
justify-content: center;
width:100%;
height:100%;
background-color: rgba(0,0,0,.4);
color:#fff;
font-size:24upx;
border-radius:8upx;
}
}
.upload-add-btn {
position: relative;
float:left;
width: 150upx;
height: 150upx;
z-index: 99;
border-radius:8upx;
background:#f9f9f9;
&:before,
&:after {
content: " ";
position: absolute;
top: 50%;
left: 50%;
-webkit-transform: translate(-50%, -50%);
transform: translate(-50%, -50%);
width: 4upx;
height: 60upx;
background-color: #d6d6d6;
}
&:after {
width: 60upx;
height: 4upx;
}
&:active {
background-color: #f7f7f7;
}
}
</style>
import Vue from 'vue'
import store from './store'
import App from './App'
import Json from './Json' //测试用数据
import uView from '@/uni_modules/uview-ui'
Vue.use(uView)
import util from '@/common/js/util.js'
import API from '@/common/js/api.js'
import msgTip from "@/common/js/msgTip.js"
Vue.prototype.$UTIL = util
Vue.prototype.$API = API
Vue.prototype.$TIP = msgTip
/**
* 因工具函数属于公司资产, 所以直接在Vue实例挂载几个常用的函数
* 所有测试用数据均存放于根目录json.js
*
* css部分使用了App.vue下的全局样式和iconfont图标,有需要图标库的可以留言。
* 示例使用了uni.scss下的变量, 除变量外已尽量移除特有语法,可直接替换为其他预处理器使用
*/
const msg = (title, duration=1500, mask=false, icon='none')=>{
//统一提示方便全局修改
if(Boolean(title) === false){
return;
}
uni.showToast({
title,
duration,
mask,
icon
});
}
const json = type=>{
//模拟异步请求数据
return new Promise(resolve=>{
setTimeout(()=>{
resolve(Json[type]);
}, 500)
})
}
const prePage = ()=>{
let pages = getCurrentPages();
let prePage = pages[pages.length - 2];
// #ifdef H5
return prePage;
// #endif
return prePage.$vm;
}
Vue.config.productionTip = false
Vue.prototype.$fire = new Vue();
Vue.prototype.$store = store;
Vue.prototype.$api = {msg, json, prePage};
App.mpType = 'app'
const app = new Vue({
...App
})
app.$mount()
\ No newline at end of file
{
"name" : "矿山之星",
"appid" : "__UNI__1FC7F1C",
"description" : "",
"versionName" : "1.0.0",
"versionCode" : "100",
"transformPx" : false,
"app-plus" : {
/* 5+App特有相关 */
"usingComponents" : true,
"splashscreen" : {
"alwaysShowBeforeRender" : true,
"waiting" : true,
"autoclose" : true,
"delay" : 0
},
"modules" : {},
/* 模块配置 */
"distribute" : {
/* 应用发布信息 */
"android" : {
/* android打包配置 */
"permissions" : [
"<uses-permission android:name=\"android.permission.CHANGE_NETWORK_STATE\"/>",
"<uses-permission android:name=\"android.permission.MOUNT_UNMOUNT_FILESYSTEMS\"/>",
"<uses-permission android:name=\"android.permission.READ_CONTACTS\"/>",
"<uses-permission android:name=\"android.permission.VIBRATE\"/>",
"<uses-permission android:name=\"android.permission.READ_LOGS\"/>",
"<uses-permission android:name=\"android.permission.ACCESS_WIFI_STATE\"/>",
"<uses-feature android:name=\"android.hardware.camera.autofocus\"/>",
"<uses-permission android:name=\"android.permission.WRITE_CONTACTS\"/>",
"<uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\"/>",
"<uses-permission android:name=\"android.permission.CAMERA\"/>",
"<uses-permission android:name=\"android.permission.RECORD_AUDIO\"/>",
"<uses-permission android:name=\"android.permission.GET_ACCOUNTS\"/>",
"<uses-permission android:name=\"android.permission.MODIFY_AUDIO_SETTINGS\"/>",
"<uses-permission android:name=\"android.permission.READ_PHONE_STATE\"/>",
"<uses-permission android:name=\"android.permission.CHANGE_WIFI_STATE\"/>",
"<uses-permission android:name=\"android.permission.WAKE_LOCK\"/>",
"<uses-permission android:name=\"android.permission.CALL_PHONE\"/>",
"<uses-permission android:name=\"android.permission.FLASHLIGHT\"/>",
"<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\"/>",
"<uses-permission android:name=\"android.permission.WRITE_SETTINGS\"/>"
]
},
"ios" : {},
/* ios打包配置 */
"sdkConfigs" : {}
}
},
/* SDK配置 */
"quickapp" : {},
/* 快应用特有相关 */
"mp-weixin" : {
/* 小程序特有相关 */
"usingComponents" : true,
"appid" : "wx89c878770aba9171",
"setting" : {
"urlCheck" : true,
"es6" : true,
"minified" : true
},
"plugins" : {
"chatGroupPlugin" : {
"version" : "1.1.2",
"provider" : "wxaae6519cee98d824"
},
"materialPlugin" : {
"version" : "1.0.5",
"provider" : "wx4d2deeab3aed6e5a"
}
}
},
"vueVersion" : "2"
}
{
"pages": [
{
"path": "pages/index/index",
"style": {
"navigationBarTitleText": "矿山之星",
"navigationBarBackgroundColor": "#0f0",
// #ifdef MP
"navigationStyle": "custom",
// #endif
"app-plus": {
"titleNView": {
"type": "transparent",
"searchInput": {
"backgroundColor": "rgba(231, 231, 231,.7)",
"borderRadius": "16px",
"placeholder": "请输入地址 如:大钟寺",
"disabled": true,
"placeholderColor": "#606266"
}
}
}
}
},
{
"path": "pages/set/set",
"style": {
"navigationBarTitleText": "设置"
}
},
{
"path": "pages/userinfo/userinfo",
"style": {
"navigationBarTitleText": "修改资料"
}
}, {
"path": "pages/cart/cart",
"style": {
"navigationBarTitleText": "教程",
// #ifdef MP
"navigationStyle": "custom"
// #endif
}
}, {
"path": "pages/public/login",
"style": {
"navigationBarTitleText": "",
"navigationStyle": "custom",
"app-plus": {
"titleNView": false,
"animationType": "slide-in-bottom"
}
}
}, {
"path": "pages/user/user",
"style": {
"navigationBarTitleText": "我的",
// #ifdef MP
"navigationStyle": "custom",
// #endif
"app-plus": {
"bounce": "none",
"titleNView": {
"type": "transparent",
"buttons": [{
"fontSrc": "/static/yticon.ttf",
"text": "\ue60f",
"fontSize": "24",
"color": "#303133",
"width": "46px",
"background": "rgba(0,0,0,0)"
},
{
"fontSrc": "/static/yticon.ttf",
"text": "\ue744",
"fontSize": "28",
"color": "#303133",
"background": "rgba(0,0,0,0)",
"redDot": true
}
]
}
}
}
}
,{
"path" : "pages/tool/index",
"style" : {
"navigationBarTitleText": "工具",
// #ifdef MP
"navigationStyle": "custom",
// #endif
"app-plus": {
"bounce": "none"
},
// "usingComponents": {
// "cell": "plugin://chatGroupPlugin/cell"
// },
"usingComponents": {
// "cell": "plugin://chatGroupPlugin/cell",
"cell": "plugin://materialPlugin/cell"
}
}
},
{
"path" : "pages/tool/detail",
"style" :
{
"navigationBarTitleText" : "",
"enablePullDownRefresh" : false
}
},
{
"path" : "pages/public/wxLoginAuth",
"style" :
{
"navigationBarTitleText" : "",
"enablePullDownRefresh" : false
}
}
],
"globalStyle": {
"navigationBarTextStyle": "black",
"navigationBarTitleText": "uni-app",
"navigationBarBackgroundColor": "#FFFFFF",
"backgroundColor": "#f8f8f8"
},
"tabBar": {
"color": "#C0C4CC",
"selectedColor": "#44AED2",
"borderStyle": "black",
"backgroundColor": "#ffffff",
"list": [{
"pagePath": "pages/index/index",
"iconPath": "static/minestar/home.png",
"selectedIconPath": "static/minestar/home-active.png",
"text": "首页"
},
{
"pagePath": "pages/tool/index",
"iconPath": "static/minestar/tool.png",
"selectedIconPath": "static/minestar/tool-active.png",
"text": "工具"
},
{
"pagePath": "pages/cart/cart",
"iconPath": "static/minestar/book.png",
"selectedIconPath": "static/minestar/book-active.png",
"text": "教程"
},
{
"pagePath": "pages/user/user",
"iconPath": "static/minestar/my.png",
"selectedIconPath": "static/minestar/my-active.png",
"text": "我的"
}
]
}
}
\ No newline at end of file
<template>
<view class="page-wrapper">
<view class="topBar" ref="top" :style="{ height: navHeight + 'px' }"></view>
<view class="mp-search-box" :style="{
top: (customTop+2) + 'px',
height: customHeight + 'px',}"
>
<view class="wrapper" :style="{
height: (customHeight-4) + 'px',}"
>
<u-icon style="float: left;width:20px;" name="search" color="#A1A1A1" size="20"></u-icon>
<input class="ser-input" type="text" placeholder="搜索工具ID、关键字" :style="{
height: (customHeight-6) + 'px',}"
/>
</view>
</view>
<view class="cateWrapper">
<cate-list></cate-list>
</view>
<view class="tabWrapper">
<u-tabs :list="list1" @click="click"></u-tabs>
<view class="line" style="top:84rpx;"></view>
</view>
<list-item></list-item>
</view>
</template>
<script>
import cateList from '@/components/cate-list.vue';
import listItem from '@/components/list-item.vue';
import { customTabar } from "@/common/js/mixins.js";
export default {
mixins: [customTabar],
components: {
listItem,
cateList
},
data() {
return {
currentId: 1,
list1: [{
name: '全部',
}, {
name: '最新',
}],
}
},
onLoad(){
this.loadData();
},
methods: {
async loadData(){
let list = await this.$api.json('cateList');
list.forEach(item=>{
if(!item.pid){
this.flist.push(item); //pid为父级id, 没有pid或者pid=0是一级分类
}else if(!item.picture){
this.slist.push(item); //没有图的是2级分类
}else{
this.tlist.push(item); //3级分类
}
})
},
//一级分类点击
tabtap(item){
if(!this.sizeCalcState){
this.calcSize();
}
this.currentId = item.id;
let index = this.slist.findIndex(sitem=>sitem.pid === item.id);
this.tabScrollTop = this.slist[index].top;
},
//右侧栏滚动
asideScroll(e){
if(!this.sizeCalcState){
this.calcSize();
}
let scrollTop = e.detail.scrollTop;
let tabs = this.slist.filter(item=>item.top <= scrollTop).reverse();
if(tabs.length > 0){
this.currentId = tabs[0].pid;
}
},
//计算右侧栏每个tab的高度等信息
calcSize(){
let h = 0;
this.slist.forEach(item=>{
let view = uni.createSelectorQuery().select("#main-" + item.id);
view.fields({
size: true
}, data => {
item.top = h;
h += data.height;
item.bottom = h;
}).exec();
})
this.sizeCalcState = true;
},
navToList(sid, tid){
uni.navigateTo({
url: `/pages/product/list?fid=${this.currentId}&sid=${sid}&tid=${tid}`
})
}
}
}
</script>
<style lang='scss' scoped>
.page-wrapper{
height: 100%;
padding-top: 150upx;
background-color: #f8f8f8;
}
.topBar{
@include topBar($height:160rpx);
}
.mp-search-box{
width: 100%;
/* padding: 20rpx 20rpx; */
height: 120rpx;
position: fixed;
top: 62upx;
left: 8rpx;
z-index: 501;
.wrapper{
display: flex;
width: 64vw;
height: 60rpx;
padding-left: 12rpx;
background-color: #fff;
border: 4rpx solid #1f1f1f;
border-radius: 40rpx;
.ser-input{
flex:1;
height: 56rpx;
line-height: 56rpx;
text-align: left;
font-size: 28rpx;
color:$font-color-base;
border-radius: 20px;
background: rgba(255,255,255,.6);
}
}
}
::v-deep .u-tabs__wrapper__nav{
background-color: #fff;
}
</style>
<template>
<view class="page-wrapper" :style="{
paddingTop: (customTop+customHeight+45) + 'px',}"
>
<view class="topBar" ref="top"></view>
<view class="mp-search-box" :style="{
top: (customTop+customHeight) + 'px',}"
>
<view class="wrapper">
<view class="">
<picker style="width: 108upx;float: left;" @change="bindPickerChange" :value="index" :range="array">
<view class="uni-input">{{array[index]}}</view>
</picker>
<u-icon style="float: left;width:20px;" name="arrow-down-fill" color="#A1A1A1" size="20"></u-icon>
</view>
<text style="font-size: 14px; color: #ded7d7;">|</text>
<u-icon style="float: left;width:20px;" name="search" color="#A1A1A1" size="20"></u-icon>
<input class="ser-input" type="text" placeholder="搜索工具ID、关键字" />
</view>
</view>
<view class="u-demo-block">
<u-swiper
:list="list6"
@change="e => current = e.current"
:autoplay="false"
imgMode="widthFix"
>
<view
slot="indicator"
class="indicator"
>
<view
class="indicator__dot"
v-for="(item, index) in list6"
:key="index"
:class="[index === current && 'indicator__dot--active']"
>
</view>
</view>
</u-swiper>
</view>
<view class="cateWrapper">
<cate-list :dataList="cateData"></cate-list>
</view>
<cell class="qiyeQun" bind:startmessage='startmessage' bind:completemessage="completemessage" url='https://work.weixin.qq.com/gm/f9d0268e8d47a10e8925a8bd589e2eb3' />
<view class="hotTool">
<view class="left">
<image src="../../static/minestar/hotool-01.png"></image>
<!-- <p>应用推荐</p>
<h3>便捷工具</h3>
<div style="color: #fff;background-color: orangered;width: 42upx;height: 22upx;line-height: 22upx;font-size: 20upx;">new</div> -->
</view>
<view class="right">
<view class="item1">
<!-- <p>热门教程</p>
<h3>教学矿山应用</h3> -->
<image src="../../static/minestar/hotool-02.png"></image>
</view>
<view class="item2">
<!-- <p>热门微信</p>
<h3>微信共享资源</h3> -->
<image src="../../static/minestar/hotool-03.png"></image>
</view>
</view>
</view>
<view class="tabWrapper">
<u-tabs :list="list1" @click="click"></u-tabs>
<view class="line"></view>
</view>
<view class="list">
<list-item></list-item>
</view>
</view>
</template>
<script>
import cateList from '@/components/cate-list.vue';
import listItem from '@/components/list-item.vue';
import { customTabar } from "@/common/js/mixins.js";
export default {
mixins: [customTabar],
components: {
listItem,
cateList,
cell: "plugin://chatGroupPlugin/cell"
},
data() {
return {
current:0,
list6: [
// 'https://cdn.uviewui.com/uview/swiper/swiper2.png',
'/static/minestar/banner.png',
],
list1: [{
name: '全部11',
}, {
name: '最新',
}],
array: ['中国', '美国', '巴西', '日本'],
index: 0,
toolList: [],
cateData: [{
src: '/static/minestar/01.png',
name: '地质'
},{
src: '/static/minestar/02.png',
name: '测绘'
},{
src: '/static/minestar/03.png',
name: '通风'
},{
src: '/static/minestar/04.png',
name: '采矿'
},{
src: '/static/minestar/05.png',
name: '爆破'
},]
};
},
onLoad() {
// this.loadData();
for (var i = 0; i < 10; i++) {
this.toolList.push({
index: i,
name: '体积计算'
})
}
},
methods: {
gotoQun(){
uni.navigateTo({
url: 'https://work.weixin.qq.com/gm/f9d0268e8d47a10e8925a8bd589e2eb3'
})
},
startmessage(){
console.log('监听按钮点击事件执行开始时的回调');
},
completemessage(){
console.log('监听按钮点击事件执行完毕后的回调');
},
useErrCallback(){
},
bindPickerChange: function(e) {
console.log('picker发送选择改变,携带值为', e.detail.value)
this.index = e.detail.value
},
},
}
</script>
<style lang="scss" scoped>
::v-deep .qiyeQun {
image{
border-radius: 50% !important;
}
}
::v-deep .u-tabs__wrapper__nav{
height: 48px !important;
}
::v-deep .u-tabs__wrapper__nav__item{
height: 50px !important;
}
.page-wrapper{
padding-top: 248rpx;
background-color: #fff;
}
$hotMargin: 16upx;
$pagePadding: 20upx; // 用于模块元素整体的边距
@mixin rounded-corners{
border-radius: 20rpx;
}
.list{
background-color: #f7f7f7;
}
.topBar{
// background-image: url('~@/pages/bg.png');
// background-image: url('~@/static/minestar/tabarBg1.jpg');
@include topBar();
}
.mp-search-box{
width: 100%;
padding: 20upx 20upx;
height: 120upx;
position: fixed;
top: 136upx;
z-index: 501;
.wrapper{
width: 94vw;
display: flex;
border: 4upx solid #1f1f1f;
border-radius: 40upx;
height: 60upx;
background-color: #fff;
.ser-input{
flex:1;
height: 56upx;
line-height: 56upx;
text-align: left;
font-size: 28upx;
color:$font-color-base;
border-radius: 20px;
background: rgba(255,255,255,.6);
}
}
}
::v-deep .uni-input{
font-size: 24upx;
line-height: 50upx;
text-align: center;
}
::v-deep .u-icon__icon.uicon-arrow-down-fill{
font-size: 16upx !important;
position: absolute !important;
left: 108upx;
top: 32upx !important;
}
.hotTool{
display: flex;
height: 300rpx;
padding: $pagePadding;
background-color: #fff;
image{
width: 100%;
height: 100%;
}
.left{
margin-right: $hotMargin;
padding-left: 20upx;
padding-top: 20upx;
flex: 1;
background-color: #FCDFE0;
p{
font-weight: bold;
font-size: 40upx;
}
h3{
font-size: 24upx;
color: darkgray;
}
@include rounded-corners;
}
.right{
flex: 1.2;
.item1, .item2{
display: flex;
align-items: flex-start;
flex-direction: column;
justify-content: center;
height: 142rpx;
padding-left: $hotMargin;
background-color: #FCF9D1;
@include rounded-corners;
p{
font-size: 32upx;
font-weight: bold;
}
h3{
font-size: 20upx;
color: darkgray;
}
}
.item2{
margin-top: $hotMargin;
}
}
}
// 轮播图
.u-demo-block{
padding: $pagePadding;
.indicator {
@include flex(row);
justify-content: center;
&__dot {
height: 10upx;
width: 10upx;
border-radius: 200upx;
background-color: rgba(255, 255, 255, 0.35);
margin: 0 5px;
transition: background-color 0.3s;
&--active {
background-color: #ffffff;
}
}
}
}
// .tabWrapper{
// position: relative;
// // background: url('/static/minestar/bottomLine.png');
// .line{
// position: absolute;
// top: 45px;
// width: 100%;
// border-bottom: 1px solid #af9a9a;
// box-shadow: 1px 1px 1px 0px #dacbcb;
// }
// }
</style>
<template>
<view class="container">
<view class="left-bottom-sign"></view>
<view class="back-btn yticon icon-zuojiantou-up" @click="navBack"></view>
<view class="right-top-sign"></view>
<!-- 设置白色背景防止软键盘把下部绝对定位元素顶上来盖住输入框等 -->
<view class="wrapper">
<view class="left-top-sign">LOGIN</view>
<view class="welcome">
欢迎回来!
</view>
<view class="input-content">
<view class="input-item">
<text class="tit">手机号码</text>
<input
type="number"
:value="mobile"
placeholder="请输入手机号码"
maxlength="11"
data-key="mobile"
@input="inputChange"
/>
</view>
<view class="input-item">
<text class="tit">密码</text>
<input
type="mobile"
value=""
placeholder="8-18位不含特殊字符的数字、字母组合"
placeholder-class="input-empty"
maxlength="20"
password
data-key="password"
@input="inputChange"
@confirm="toLogin"
/>
</view>
</view>
<button class="confirm-btn" @click="toLogin" :disabled="logining">登录</button>
<view class="forget-section">
忘记密码?
</view>
</view>
<view class="register-section">
还没有账号?
<text @click="toRegist">马上注册</text>
</view>
</view>
</template>
<script>
import {
mapMutations
} from 'vuex';
export default{
data(){
return {
mobile: '',
password: '',
logining: false
}
},
onLoad(){
},
methods: {
...mapMutations(['login']),
inputChange(e){
const key = e.currentTarget.dataset.key;
this[key] = e.detail.value;
},
navBack(){
uni.navigateBack();
},
toRegist(){
this.$api.msg('去注册');
},
async toLogin(){
this.logining = true;
const {mobile, password} = this;
/* 数据验证模块
if(!this.$api.match({
mobile,
password
})){
this.logining = false;
return;
}
*/
const sendData = {
mobile,
password
};
const result = await this.$api.json('userInfo');
if(result.status === 1){
this.login(result.data);
uni.navigateBack();
}else{
this.$api.msg(result.msg);
this.logining = false;
}
}
},
}
</script>
<style lang='scss'>
page{
background: #fff;
}
.container{
padding-top: 115px;
position:relative;
width: 100vw;
height: 100vh;
overflow: hidden;
background: #fff;
}
.wrapper{
position:relative;
z-index: 90;
background: #fff;
padding-bottom: 40upx;
}
.back-btn{
position:absolute;
left: 40upx;
z-index: 9999;
padding-top: var(--status-bar-height);
top: 40upx;
font-size: 40upx;
color: $font-color-dark;
}
.left-top-sign{
font-size: 120upx;
color: $page-color-base;
position:relative;
left: -16upx;
}
.right-top-sign{
position:absolute;
top: 80upx;
right: -30upx;
z-index: 95;
&:before, &:after{
display:block;
content:"";
width: 400upx;
height: 80upx;
background: #b4f3e2;
}
&:before{
transform: rotate(50deg);
border-radius: 0 50px 0 0;
}
&:after{
position: absolute;
right: -198upx;
top: 0;
transform: rotate(-50deg);
border-radius: 50px 0 0 0;
/* background: pink; */
}
}
.left-bottom-sign{
position:absolute;
left: -270upx;
bottom: -320upx;
border: 100upx solid #d0d1fd;
border-radius: 50%;
padding: 180upx;
}
.welcome{
position:relative;
left: 50upx;
top: -90upx;
font-size: 46upx;
color: #555;
text-shadow: 1px 0px 1px rgba(0,0,0,.3);
}
.input-content{
padding: 0 60upx;
}
.input-item{
display:flex;
flex-direction: column;
align-items:flex-start;
justify-content: center;
padding: 0 30upx;
background:$page-color-light;
height: 120upx;
border-radius: 4px;
margin-bottom: 50upx;
&:last-child{
margin-bottom: 0;
}
.tit{
height: 50upx;
line-height: 56upx;
font-size: $font-sm+2upx;
color: $font-color-base;
}
input{
height: 60upx;
font-size: $font-base + 2upx;
color: $font-color-dark;
width: 100%;
}
}
.confirm-btn{
width: 630upx;
height: 76upx;
line-height: 76upx;
border-radius: 50px;
margin-top: 70upx;
background: $uni-color-primary;
color: #fff;
font-size: $font-lg;
&:after{
border-radius: 100px;
}
}
.forget-section{
font-size: $font-sm+2upx;
color: $font-color-spec;
text-align: center;
margin-top: 40upx;
}
.register-section{
position:absolute;
left: 0;
bottom: 50upx;
width: 100%;
font-size: $font-sm+2upx;
color: $font-color-base;
text-align: center;
text{
color: $font-color-spec;
margin-left: 10upx;
}
}
</style>
<template>
<view class="container">
<view class="authModal">
<view class='header'>
<image src='https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1582442269885&di=244f11fe921a75d4be2b7f41bded8a48&imgtype=0&src=http%3A%2F%2Fimg.qqzhi.com%2Fuploads%2F2018-12-06%2F062323200.jpg'></image>
</view>
<view class='content'>
<view>申请获取以下权限</view>
<text>获得你的公开信息(昵称,头像、地区等)</text>
</view>
<button class='bottom' type='primary' open-type="getUserInfo" withCredentials="true" lang="zh_CN" @getuserinfo="wxLogin">
授权登录
</button>
<button class='bottom' type='danger' @click="notAuth4Login()">
取消授权
</button>
</view>
</view>
</template>
<script>
import { mapState } from 'vuex';
export default {
data() {
return {
// hasAuthed: uni.getStorageSync('accessToken'),
}
},
// computed: {
// ...mapState(['hasLogined', 'userInfo'])
// },
methods: {
wxLogin(e) { // 第一次微信授权登录
const VUE = this;
VUE.logining = true;
uni.login({ // 请求微信后台接口,获取code
provider: "weixin",
success: (login_res => {
let code = login_res.code;
uni.getUserInfo({ // 已授权的用户获取用户详情
async success(info_res) {
let userInfo = JSON.parse(info_res.rawData);
// 向服务器发起登录请求
let res = await VUE.$http.call('/api/login/weChatLogin', {
jsCode: code,
...userInfo,
bindAuthor: uni.getStorageSync('bindAuthor')
})
if(res){ // 登录成功
await uni.setStorageSync("userInfo", res.result);
await uni.setStorageSync('accessToken', res.accessToken)
console.log('用户的openId', res.result.wxOpenid)
VUE.$util.toast('授权登录成功')
VUE.$store.commit('login', res.result) // 设置登录信息
uni.reLaunch({ // 授权登录成功后,跳转到我的页面
url: '/pages/user/user'
})
// util.refreshPage()
// uni.navigateBack() // 返回上一个需要授权操作的页面
}
// 登录成功后,更新登录状态store 刷新上一页的load
// VUE.$util.getToken() && && VUE.$util.refreshPrePage();
}
})
})
})
},
notAuth4Login(){
// uni.navigateBack() // 返回上一页
uni.reLaunch({
url: '/pages/index/index'
})
}
}
}
</script>
<style lang='scss' scoped>
.container {
position: relative;
// 微信授权弹窗
.authModal {
position: absolute;
top: 0;
background-color: #fff;
z-index: 100;
margin-top: 30rpx;
margin-left: 50%;
border: 1px solid #eee;
transform: translateX(-50%);
border-radius: 10px;
.header {
margin: 90rpx 0 90rpx 50rpx;
border-bottom: 1px solid #ccc;
text-align: center;
width: 650rpx;
height: 300rpx;
line-height: 450rpx;
image {
width: 200rpx;
height: 160rpx;
}
}
.content {
margin-left: 50rpx;
margin-bottom: 90rpx;
text {
display: block;
color: #9d9d9d;
margin-top: 40rpx;
}
}
.bottom {
/* border-radius: 80rpx; */
margin: 70rpx 50rpx;
font-size: 35rpx;
}
}
}
</style>
\ No newline at end of file
<template>
<view class="container">
<view class="list-cell b-b m-t" @click="navTo('个人资料')" hover-class="cell-hover" :hover-stay-time="50">
<text class="cell-tit">个人资料</text>
<text class="cell-more yticon icon-you"></text>
</view>
<view class="list-cell b-b" @click="navTo('收货地址')" hover-class="cell-hover" :hover-stay-time="50">
<text class="cell-tit">收货地址</text>
<text class="cell-more yticon icon-you"></text>
</view>
<view class="list-cell" @click="navTo('实名认证')" hover-class="cell-hover" :hover-stay-time="50">
<text class="cell-tit">实名认证</text>
<text class="cell-more yticon icon-you"></text>
</view>
<view class="list-cell m-t">
<text class="cell-tit">消息推送</text>
<switch checked color="#fa436a" @change="switchChange" />
</view>
<view class="list-cell m-t b-b" @click="navTo('清除缓存')" hover-class="cell-hover" :hover-stay-time="50">
<text class="cell-tit">清除缓存</text>
<text class="cell-more yticon icon-you"></text>
</view>
<view class="list-cell b-b" @click="navTo('关于Dcloud')" hover-class="cell-hover" :hover-stay-time="50">
<text class="cell-tit">关于Dcloud</text>
<text class="cell-more yticon icon-you"></text>
</view>
<view class="list-cell">
<text class="cell-tit">检查更新</text>
<text class="cell-tip">当前版本 1.0.3</text>
<text class="cell-more yticon icon-you"></text>
</view>
<view class="list-cell log-out-btn" @click="toLogout">
<text class="cell-tit">退出登录</text>
</view>
</view>
</template>
<script>
import {
mapMutations
} from 'vuex';
export default {
data() {
return {
};
},
methods:{
...mapMutations(['logout']),
navTo(url){
this.$api.msg(`跳转到${url}`);
},
//退出登录
toLogout(){
uni.showModal({
content: '确定要退出登录么',
success: (e)=>{
if(e.confirm){
this.logout();
setTimeout(()=>{
uni.navigateBack();
}, 200)
}
}
});
},
//switch
switchChange(e){
let statusTip = e.detail.value ? '打开': '关闭';
this.$api.msg(`${statusTip}消息推送`);
},
}
}
</script>
<style lang='scss'>
page{
background: $page-color-base;
}
.list-cell{
display:flex;
align-items:baseline;
padding: 20upx $page-row-spacing;
line-height:60upx;
position:relative;
background: #fff;
justify-content: center;
&.log-out-btn{
margin-top: 40upx;
.cell-tit{
color: $uni-color-primary;
text-align: center;
margin-right: 0;
}
}
&.cell-hover{
background:#fafafa;
}
&.b-b:after{
left: 30upx;
}
&.m-t{
margin-top: 16upx;
}
.cell-more{
align-self: baseline;
font-size:$font-lg;
color:$font-color-light;
margin-left:10upx;
}
.cell-tit{
flex: 1;
font-size: $font-base + 2upx;
color: $font-color-dark;
margin-right:10upx;
}
.cell-tip{
font-size: $font-base;
color: $font-color-light;
}
switch{
transform: translateX(16upx) scale(.84);
}
}
</style>
<template>
<view>
</view>
</template>
<script>
export default {
data() {
return {
};
}
}
</script>
<style lang="scss">
</style>
<template>
<view class="page-wrapper">
<view class="topBar" ref="top" :style="{ height: navHeight + 'px' }"></view>
<view class="mp-search-box" :style="{
top: (customTop+2) + 'px',
height: customHeight + 'px',}"
>
<view class="wrapper" :style="{
height: (customHeight-4) + 'px',}"
>
<u-icon style="float: left;width:20px;" name="search" color="#A1A1A1" size="20"></u-icon>
<input class="ser-input" type="text" placeholder="搜索工具ID、关键字" :style="{
height: (customHeight-6) + 'px',}"
/>
</view>
</view>
<view class="cateWrapper">
<cate-list></cate-list>
</view>
<view class="tabWrapper">
<u-tabs :list="list1" @click="click"></u-tabs>
<view class="line" style="top:84rpx;"></view>
</view>
<list-item></list-item>
</view>
</template>
<script>
import cateList from '@/components/cate-list.vue';
import listItem from '@/components/list-item.vue';
import { customTabar } from "@/common/js/mixins.js";
export default {
mixins: [customTabar],
components: {
listItem,
cateList
},
data() {
return {
currentId: 1,
list1: [{
name: '全部',
}, {
name: '最新',
}],
}
},
onLoad(){
this.loadData();
},
methods: {
async loadData(){
let list = await this.$api.json('cateList');
list.forEach(item=>{
if(!item.pid){
this.flist.push(item); //pid为父级id, 没有pid或者pid=0是一级分类
}else if(!item.picture){
this.slist.push(item); //没有图的是2级分类
}else{
this.tlist.push(item); //3级分类
}
})
},
//一级分类点击
tabtap(item){
if(!this.sizeCalcState){
this.calcSize();
}
this.currentId = item.id;
let index = this.slist.findIndex(sitem=>sitem.pid === item.id);
this.tabScrollTop = this.slist[index].top;
},
//右侧栏滚动
asideScroll(e){
if(!this.sizeCalcState){
this.calcSize();
}
let scrollTop = e.detail.scrollTop;
let tabs = this.slist.filter(item=>item.top <= scrollTop).reverse();
if(tabs.length > 0){
this.currentId = tabs[0].pid;
}
},
//计算右侧栏每个tab的高度等信息
calcSize(){
let h = 0;
this.slist.forEach(item=>{
let view = uni.createSelectorQuery().select("#main-" + item.id);
view.fields({
size: true
}, data => {
item.top = h;
h += data.height;
item.bottom = h;
}).exec();
})
this.sizeCalcState = true;
},
navToList(sid, tid){
uni.navigateTo({
url: `/pages/product/list?fid=${this.currentId}&sid=${sid}&tid=${tid}`
})
}
}
}
</script>
<style lang='scss' scoped>
.page-wrapper{
height: 100%;
padding-top: 150upx;
background-color: #f8f8f8;
}
.topBar{
@include topBar($height:160rpx);
}
.mp-search-box{
width: 100%;
/* padding: 20rpx 20rpx; */
height: 120rpx;
position: fixed;
top: 62upx;
left: 8rpx;
z-index: 501;
.wrapper{
display: flex;
width: 64vw;
height: 60rpx;
padding-left: 12rpx;
background-color: #fff;
border: 4rpx solid #1f1f1f;
border-radius: 40rpx;
.ser-input{
flex:1;
height: 56rpx;
line-height: 56rpx;
text-align: left;
font-size: 28rpx;
color:$font-color-base;
border-radius: 20px;
background: rgba(255,255,255,.6);
}
}
}
::v-deep .u-tabs__wrapper__nav{
background-color: #fff;
}
</style>
<template>
<view class="page-wrapper">
<view class="topBar" ref="top" :style="{ height: navHeight + 'px' }"></view>
<!-- 个人中心 -->
<view class="personInfo">
<view class="header">个人中心</view>
<view class="body">
<view class="userInfo">
<image src="https://cdn.uviewui.com/uview/album/1.jpg" mode=""></image>
<view>
<p>AA(^-^)V</p>
<text>ID:80098</text>
</view>
</view>
<view>
<p>262</p>
<text>kk会员</text>
</view>
<view>
<p>20</p>
<text>积分</text>
</view>
<i class='iconfont icon-Setup' style="margin-top: -40rpx;"></i>
</view>
</view>
<!-- 最近浏览 -->
<view class="recentBrowser">
<view class="header">最近浏览</view>
<view class="tab">
<u-tabs :list="list1" @click="click"></u-tabs>
</view>
<view class="cateWrapper">
<cate-list></cate-list>
</view>
</view>
<view class="myCollect">
<view class="header">我的收藏</view>
<view class="tab">
<u-tabs :list="list1" @click="click"></u-tabs>
</view>
<view class="cateWrapper">
<cate-list></cate-list>
</view>
</view>
<view class="questionCenter">
<view class="header">问题中心</view>
</view>
<view class="aboutMe">
<view class="header">关于我们</view>
</view>
<view class="service">
<view class="header">客服服务</view>
</view>
<view class="feedback">
<view class="header">意见反馈</view>
</view>
</view>
</template>
<script>
import cateList from '@/components/cate-list.vue';
import { customTabar } from "@/common/js/mixins.js";
import {
mapState
} from 'vuex';
let startY = 0, moveY = 0, pageAtTop = true;
export default {
mixins: [customTabar],
components: {
cateList
},
data(){
return {
coverTransform: 'translateY(0px)',
coverTransition: '0s',
moving: false,
list1: [{
name: '全部',
}, {
name: '测绘',
}, {
name: '通风'
}, {
name: '采矿'
}, {
name: '爆破'
}]
}
},
onLoad(){
},
// #ifndef MP
onNavigationBarButtonTap(e) {
const index = e.index;
if (index === 0) {
this.navTo('/pages/set/set');
}else if(index === 1){
// #ifdef APP-PLUS
const pages = getCurrentPages();
const page = pages[pages.length - 1];
const currentWebview = page.$getAppWebview();
currentWebview.hideTitleNViewButtonRedDot({
index
});
// #endif
uni.navigateTo({
url: '/pages/notice/notice'
})
}
},
// #endif
computed: {
...mapState(['hasLogin','userInfo'])
},
methods: {
click(){
}
}
}
</script>
<style lang='scss'>
.page-wrapper{
padding-top: 44rpx;
background-color: #f8f8f8;
}
.topBar{
@include topBar();
}
.cateWrapper{
background-color: #fff;
}
.personInfo, .recentBrowser, .myCollect, .questionCenter, .aboutMe,.service,.feedback{
margin-top: 30rpx;
.header{
padding: 0 20rpx;
font-weight: bold;
}
}
.recentBrowser{
margin-top: 20rpx;
}
::v-deep .cate-section{
background-color: #fff !important;
}
::v-deep .u-tabs__wrapper__nav__item__text.data-v-48634e29 {
color: #928f8f !important;
}
.personInfo{
height: 200rpx;
background-color: #fff;
.body{
display: flex;
margin-top: 50rpx;
padding: 0px 20rpx;
justify-content: space-between;
align-items: center;
font-size: 24rpx;
p{
font-weight: bold;
}
text{
color: darkgray;
}
.userInfo{
display: flex;
flex: 0.66;
align-items: center;
justify-content: flex-start;
font-size: 32rpx;
image{
width: 100rpx;
height: 100rpx;
margin-right: 24rpx;
border-radius: 50%;
}
}
}
}
</style>
\ No newline at end of file
<template>
<view>
<view class="user-section">
<image class="bg" src="/static/user-bg.jpg"></image>
<text class="bg-upload-btn yticon icon-paizhao"></text>
<view class="portrait-box">
<image class="portrait" :src="userInfo.portrait || '/static/missing-face.png'"></image>
<text class="pt-upload-btn yticon icon-paizhao"></text>
</view>
</view>
</view>
</template>
<script>
import {
mapState,
mapMutations
} from 'vuex';
export default {
data() {
return {
};
},
computed:{
...mapState(['userInfo']),
}
}
</script>
<style lang="scss">
page{
background: $page-color-base;
}
.user-section{
display:flex;
align-items:center;
justify-content: center;
height: 460upx;
padding: 40upx 30upx 0;
position:relative;
.bg{
position:absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
filter: blur(1px);
opacity: .7;
}
.portrait-box{
width: 200upx;
height: 200upx;
border:6upx solid #fff;
border-radius: 50%;
position:relative;
z-index: 2;
}
.portrait{
position: relative;
width: 100%;
height: 100%;
border-radius: 50%;
}
.yticon{
position:absolute;
line-height: 1;
z-index: 5;
font-size: 48upx;
color: #fff;
padding: 4upx 6upx;
border-radius: 6upx;
background: rgba(0,0,0,.4);
}
.pt-upload-btn{
right: 0;
bottom: 10upx;
}
.bg-upload-btn{
right: 20upx;
bottom: 16upx;
}
}
</style>
This diff is collapsed.
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
const store = new Vuex.Store({
state: {
hasLogin: false,
userInfo: {},
},
mutations: {
login(state, provider) {
state.hasLogin = true;
state.userInfo = provider;
uni.setStorage({//缓存用户登陆状态
key: 'userInfo',
data: provider
})
console.log(state.userInfo);
},
logout(state) {
state.hasLogin = false;
state.userInfo = {};
uni.removeStorage({
key: 'userInfo'
})
}
},
actions: {
}
})
export default store
/* uni.scss */
@import '@/uni_modules/uview-ui/theme.scss';
/* 页面左右间距 */
$page-row-spacing: 30upx;
$page-color-base: #f8f8f8;
$page-color-light: #f8f6fc;
$base-color: #fa436a;
/* 文字尺寸 */
$font-sm: 24upx;
$font-base: 28upx;
$font-lg: 32upx;
/*文字颜色*/
$font-color-dark: #303133;
$font-color-base: #606266;
$font-color-light: #909399;
$font-color-disabled: #C0C4CC;
$font-color-spec: #4399fc;
/* 边框颜色 */
$border-color-dark: #DCDFE6;
$border-color-base: #E4E7ED;
$border-color-light: #EBEEF5;
/* 图片加载中颜色 */
$image-bg-color: #eee;
/* 行为相关颜色 */
$uni-color-primary:#fa436a;
$uni-color-success: #4cd964;
$uni-color-warning: #f0ad4e;
$uni-color-error: #dd524d;
@mixin topBar($height:190rpx){ // 顶部栏混入
position: fixed;
top: 0px;
width: 100%;
height: $height;
// background: linear-gradient(90deg, #dfe2e4 -1%, #a6c4d4 102%);
// background: radial-gradient(circle, rgba(166,196,212,1) 0%, rgba(223,226,228,1) 100%);
background-image: url('~@/static/minestar/tabarBg.jpg');
background-repeat:no-repeat;
background-position:center;
background-origin:content-box;
background-size: cover;
z-index: 500;
}
@mixin ellipse($weight: 80rpx){
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
max-width: $weight;
}
\ No newline at end of file
MIT License
Copyright (c) 2023 www.uviewui.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
<p align="center">
<img alt="logo" src="https://uviewui.com/common/logo.png" width="120" height="120" style="margin-bottom: 10px;">
</p>
<h3 align="center" style="margin: 30px 0 30px;font-weight: bold;font-size:40px;">uView 2.0</h3>
<h3 align="center">多平台快速开发的UI框架</h3>
[![stars](https://img.shields.io/github/stars/umicro/uView2.0?style=flat-square&logo=GitHub)](https://github.com/umicro/uView2.0)
[![forks](https://img.shields.io/github/forks/umicro/uView2.0?style=flat-square&logo=GitHub)](https://github.com/umicro/uView2.0)
[![issues](https://img.shields.io/github/issues/umicro/uView2.0?style=flat-square&logo=GitHub)](https://github.com/umicro/uView2.0/issues)
[![Website](https://img.shields.io/badge/uView-up-blue?style=flat-square)](https://uviewui.com)
[![release](https://img.shields.io/github/v/release/umicro/uView2.0?style=flat-square)](https://gitee.com/umicro/uView2.0/releases)
[![license](https://img.shields.io/github/license/umicro/uView2.0?style=flat-square)](https://en.wikipedia.org/wiki/MIT_License)
## 说明
uView UI,是[uni-app](https://uniapp.dcloud.io/)全面兼容nvue的uni-app生态框架,全面的组件和便捷的工具会让您信手拈来,如鱼得水
## [官方文档:https://uviewui.com](https://uviewui.com)
## 预览
您可以通过**微信**扫码,查看最佳的演示效果。
<br>
<br>
<img src="https://uviewui.com/common/weixin_mini_qrcode.png" width="220" height="220" >
## 链接
- [官方文档](https://www.uviewui.com/)
- [更新日志](https://www.uviewui.com/components/changelog.html)
- [升级指南](https://www.uviewui.com/components/changeGuide.html)
- [关于我们](https://www.uviewui.com/cooperation/about.html)
## 交流反馈
欢迎加入我们的QQ群交流反馈:[点此跳转](https://www.uviewui.com/components/addQQGroup.html)
## 关于PR
> 我们非常乐意接受各位的优质PR,但在此之前我希望您了解uView2.0是一个需要兼容多个平台的(小程序、h5、ios app、android app)包括nvue页面、vue页面。
> 所以希望在您修复bug并提交之前尽可能的去这些平台测试一下兼容性。最好能携带测试截图以方便审核。非常感谢!
## 安装
#### **uni-app插件市场链接** —— [https://ext.dcloud.net.cn/plugin?id=1593](https://ext.dcloud.net.cn/plugin?id=1593)
请通过[官网安装文档](https://www.uviewui.com/components/install.html)了解更详细的内容
## 快速上手
请通过[快速上手](https://uviewui.com/components/quickstart.html)了解更详细的内容
## 使用方法
配置easycom规则后,自动按需引入,无需`import`组件,直接引用即可。
```html
<template>
<u-button text="按钮"></u-button>
</template>
```
## 版权信息
uView遵循[MIT](https://en.wikipedia.org/wiki/MIT_License)开源协议,意味着您无需支付任何费用,也无需授权,即可将uView应用到您的产品中。
This diff is collapsed.
<template>
<uvForm
ref="uForm"
:model="model"
:rules="rules"
:errorType="errorType"
:borderBottom="borderBottom"
:labelPosition="labelPosition"
:labelWidth="labelWidth"
:labelAlign="labelAlign"
:labelStyle="labelStyle"
:customStyle="customStyle"
>
<slot />
</uvForm>
</template>
<script>
/**
* 此组件存在的理由是,在nvue下,u-form被uni-app官方占用了,u-form在nvue中相当于form组件
* 所以在nvue下,取名为u--form,内部其实还是u-form.vue,只不过做一层中转
*/
import uvForm from '../u-form/u-form.vue';
import props from '../u-form/props.js'
export default {
// #ifdef MP-WEIXIN
name: 'u-form',
// #endif
// #ifndef MP-WEIXIN
name: 'u--form',
// #endif
mixins: [uni.$u.mpMixin, props, uni.$u.mixin],
components: {
uvForm
},
created() {
this.children = []
},
methods: {
// 手动设置校验的规则,如果规则中有函数的话,微信小程序中会过滤掉,所以只能手动调用设置规则
setRules(rules) {
this.$refs.uForm.setRules(rules)
},
validate() {
/**
* 在微信小程序中,通过this.$parent拿到的父组件是u--form,而不是其内嵌的u-form
* 导致在u-form组件中,拿不到对应的children数组,从而校验无效,所以这里每次调用u-form组件中的
* 对应方法的时候,在小程序中都先将u--form的children赋值给u-form中的children
*/
// #ifdef MP-WEIXIN
this.setMpData()
// #endif
return this.$refs.uForm.validate()
},
validateField(value, callback) {
// #ifdef MP-WEIXIN
this.setMpData()
// #endif
return this.$refs.uForm.validateField(value, callback)
},
resetFields() {
// #ifdef MP-WEIXIN
this.setMpData()
// #endif
return this.$refs.uForm.resetFields()
},
clearValidate(props) {
// #ifdef MP-WEIXIN
this.setMpData()
// #endif
return this.$refs.uForm.clearValidate(props)
},
setMpData() {
this.$refs.uForm.children = this.children
}
},
}
</script>
<template>
<uvImage
:src="src"
:mode="mode"
:width="width"
:height="height"
:shape="shape"
:radius="radius"
:lazyLoad="lazyLoad"
:showMenuByLongpress="showMenuByLongpress"
:loadingIcon="loadingIcon"
:errorIcon="errorIcon"
:showLoading="showLoading"
:showError="showError"
:fade="fade"
:webp="webp"
:duration="duration"
:bgColor="bgColor"
:customStyle="customStyle"
@click="$emit('click')"
@error="$emit('error')"
@load="$emit('load')"
>
<template v-slot:loading>
<slot name="loading"></slot>
</template>
<template v-slot:error>
<slot name="error"></slot>
</template>
</uvImage>
</template>
<script>
/**
* 此组件存在的理由是,在nvue下,u-image被uni-app官方占用了,u-image在nvue中相当于image组件
* 所以在nvue下,取名为u--image,内部其实还是u-iamge.vue,只不过做一层中转
*/
import uvImage from '../u-image/u-image.vue';
import props from '../u-image/props.js';
export default {
name: 'u--image',
mixins: [uni.$u.mpMixin, props, uni.$u.mixin],
components: {
uvImage
},
}
</script>
\ No newline at end of file
<template>
<uvInput
:value="value"
:type="type"
:fixed="fixed"
:disabled="disabled"
:disabledColor="disabledColor"
:clearable="clearable"
:password="password"
:maxlength="maxlength"
:placeholder="placeholder"
:placeholderClass="placeholderClass"
:placeholderStyle="placeholderStyle"
:showWordLimit="showWordLimit"
:confirmType="confirmType"
:confirmHold="confirmHold"
:holdKeyboard="holdKeyboard"
:focus="focus"
:autoBlur="autoBlur"
:disableDefaultPadding="disableDefaultPadding"
:cursor="cursor"
:cursorSpacing="cursorSpacing"
:selectionStart="selectionStart"
:selectionEnd="selectionEnd"
:adjustPosition="adjustPosition"
:inputAlign="inputAlign"
:fontSize="fontSize"
:color="color"
:prefixIcon="prefixIcon"
:suffixIcon="suffixIcon"
:suffixIconStyle="suffixIconStyle"
:prefixIconStyle="prefixIconStyle"
:border="border"
:readonly="readonly"
:shape="shape"
:customStyle="customStyle"
:formatter="formatter"
:ignoreCompositionEvent="ignoreCompositionEvent"
@focus="$emit('focus')"
@blur="e => $emit('blur', e)"
@keyboardheightchange="$emit('keyboardheightchange')"
@change="e => $emit('change', e)"
@input="e => $emit('input', e)"
@confirm="e => $emit('confirm', e)"
@clear="$emit('clear')"
@click="$emit('click')"
>
<!-- #ifdef MP -->
<slot name="prefix"></slot>
<slot name="suffix"></slot>
<!-- #endif -->
<!-- #ifndef MP -->
<slot name="prefix" slot="prefix"></slot>
<slot name="suffix" slot="suffix"></slot>
<!-- #endif -->
</uvInput>
</template>
<script>
/**
* 此组件存在的理由是,在nvue下,u-input被uni-app官方占用了,u-input在nvue中相当于input组件
* 所以在nvue下,取名为u--input,内部其实还是u-input.vue,只不过做一层中转
*/
import uvInput from '../u-input/u-input.vue';
import props from '../u-input/props.js'
export default {
name: 'u--input',
mixins: [uni.$u.mpMixin, props, uni.$u.mixin],
components: {
uvInput
},
}
</script>
\ No newline at end of file
<template>
<uvText
:type="type"
:show="show"
:text="text"
:prefixIcon="prefixIcon"
:suffixIcon="suffixIcon"
:mode="mode"
:href="href"
:format="format"
:call="call"
:openType="openType"
:bold="bold"
:block="block"
:lines="lines"
:color="color"
:decoration="decoration"
:size="size"
:iconStyle="iconStyle"
:margin="margin"
:lineHeight="lineHeight"
:align="align"
:wordWrap="wordWrap"
:customStyle="customStyle"
@click="$emit('click')"
></uvText>
</template>
<script>
/**
* 此组件存在的理由是,在nvue下,u-text被uni-app官方占用了,u-text在nvue中相当于input组件
* 所以在nvue下,取名为u--input,内部其实还是u-text.vue,只不过做一层中转
* 不使用v-bind="$attrs",而是分开独立写传参,是因为微信小程序不支持此写法
*/
import uvText from "../u-text/u-text.vue";
import props from "../u-text/props.js";
export default {
name: "u--text",
mixins: [uni.$u.mpMixin, props, uni.$u.mixin],
components: {
uvText,
},
};
</script>
<template>
<uvTextarea
:value="value"
:placeholder="placeholder"
:height="height"
:confirmType="confirmType"
:disabled="disabled"
:count="count"
:focus="focus"
:autoHeight="autoHeight"
:fixed="fixed"
:cursorSpacing="cursorSpacing"
:cursor="cursor"
:showConfirmBar="showConfirmBar"
:selectionStart="selectionStart"
:selectionEnd="selectionEnd"
:adjustPosition="adjustPosition"
:disableDefaultPadding="disableDefaultPadding"
:holdKeyboard="holdKeyboard"
:maxlength="maxlength"
:border="border"
:customStyle="customStyle"
:formatter="formatter"
:ignoreCompositionEvent="ignoreCompositionEvent"
@focus="e => $emit('focus')"
@blur="e => $emit('blur')"
@linechange="e => $emit('linechange', e)"
@confirm="e => $emit('confirm')"
@input="e => $emit('input', e)"
@keyboardheightchange="e => $emit('keyboardheightchange')"
></uvTextarea>
</template>
<script>
/**
* 此组件存在的理由是,在nvue下,u--textarea被uni-app官方占用了,u-textarea在nvue中相当于textarea组件
* 所以在nvue下,取名为u--textarea,内部其实还是u-textarea.vue,只不过做一层中转
*/
import uvTextarea from '../u-textarea/u-textarea.vue';
import props from '../u-textarea/props.js'
export default {
name: 'u--textarea',
mixins: [uni.$u.mpMixin, props, uni.$u.mixin],
components: {
uvTextarea
},
}
</script>
export default {
props: {
// 操作菜单是否展示 (默认false)
show: {
type: Boolean,
default: uni.$u.props.actionSheet.show
},
// 标题
title: {
type: String,
default: uni.$u.props.actionSheet.title
},
// 选项上方的描述信息
description: {
type: String,
default: uni.$u.props.actionSheet.description
},
// 数据
actions: {
type: Array,
default: uni.$u.props.actionSheet.actions
},
// 取消按钮的文字,不为空时显示按钮
cancelText: {
type: String,
default: uni.$u.props.actionSheet.cancelText
},
// 点击某个菜单项时是否关闭弹窗
closeOnClickAction: {
type: Boolean,
default: uni.$u.props.actionSheet.closeOnClickAction
},
// 处理底部安全区(默认true)
safeAreaInsetBottom: {
type: Boolean,
default: uni.$u.props.actionSheet.safeAreaInsetBottom
},
// 小程序的打开方式
openType: {
type: String,
default: uni.$u.props.actionSheet.openType
},
// 点击遮罩是否允许关闭 (默认true)
closeOnClickOverlay: {
type: Boolean,
default: uni.$u.props.actionSheet.closeOnClickOverlay
},
// 圆角值
round: {
type: [Boolean, String, Number],
default: uni.$u.props.actionSheet.round
}
}
}
<template>
<u-popup
:show="show"
mode="bottom"
@close="closeHandler"
:safeAreaInsetBottom="safeAreaInsetBottom"
:round="round"
>
<view class="u-action-sheet">
<view
class="u-action-sheet__header"
v-if="title"
>
<text class="u-action-sheet__header__title u-line-1">{{title}}</text>
<view
class="u-action-sheet__header__icon-wrap"
@tap.stop="cancel"
>
<u-icon
name="close"
size="17"
color="#c8c9cc"
bold
></u-icon>
</view>
</view>
<text
class="u-action-sheet__description"
:style="[{
marginTop: `${title && description ? 0 : '18px'}`
}]"
v-if="description"
>{{description}}</text>
<slot>
<u-line v-if="description"></u-line>
<view class="u-action-sheet__item-wrap">
<template v-for="(item, index) in actions">
<!-- #ifdef MP -->
<button
:key="index"
class="u-reset-button"
:openType="item.openType"
@getuserinfo="onGetUserInfo"
@contact="onContact"
@getphonenumber="onGetPhoneNumber"
@error="onError"
@launchapp="onLaunchApp"
@opensetting="onOpenSetting"
:lang="lang"
:session-from="sessionFrom"
:send-message-title="sendMessageTitle"
:send-message-path="sendMessagePath"
:send-message-img="sendMessageImg"
:show-message-card="showMessageCard"
:app-parameter="appParameter"
@tap="selectHandler(index)"
:hover-class="!item.disabled && !item.loading ? 'u-action-sheet--hover' : ''"
>
<!-- #endif -->
<view
class="u-action-sheet__item-wrap__item"
@tap.stop="selectHandler(index)"
:hover-class="!item.disabled && !item.loading ? 'u-action-sheet--hover' : ''"
:hover-stay-time="150"
>
<template v-if="!item.loading">
<text
class="u-action-sheet__item-wrap__item__name"
:style="[itemStyle(index)]"
>{{ item.name }}</text>
<text
v-if="item.subname"
class="u-action-sheet__item-wrap__item__subname"
>{{ item.subname }}</text>
</template>
<u-loading-icon
v-else
custom-class="van-action-sheet__loading"
size="18"
mode="circle"
/>
</view>
<!-- #ifdef MP -->
</button>
<!-- #endif -->
<u-line v-if="index !== actions.length - 1"></u-line>
</template>
</view>
</slot>
<u-gap
bgColor="#eaeaec"
height="6"
v-if="cancelText"
></u-gap>
<view hover-class="u-action-sheet--hover">
<text
@touchmove.stop.prevent
:hover-stay-time="150"
v-if="cancelText"
class="u-action-sheet__cancel-text"
@tap="cancel"
>{{cancelText}}</text>
</view>
</view>
</u-popup>
</template>
<script>
import openType from '../../libs/mixin/openType'
import button from '../../libs/mixin/button'
import props from './props.js';
/**
* ActionSheet 操作菜单
* @description 本组件用于从底部弹出一个操作菜单,供用户选择并返回结果。本组件功能类似于uni的uni.showActionSheetAPI,配置更加灵活,所有平台都表现一致。
* @tutorial https://www.uviewui.com/components/actionSheet.html
*
* @property {Boolean} show 操作菜单是否展示 (默认 false )
* @property {String} title 操作菜单标题
* @property {String} description 选项上方的描述信息
* @property {Array<Object>} actions 按钮的文字数组,见官方文档示例
* @property {String} cancelText 取消按钮的提示文字,不为空时显示按钮
* @property {Boolean} closeOnClickAction 点击某个菜单项时是否关闭弹窗 (默认 true )
* @property {Boolean} safeAreaInsetBottom 处理底部安全区 (默认 true )
* @property {String} openType 小程序的打开方式 (contact | launchApp | getUserInfo | openSetting |getPhoneNumber |error )
* @property {Boolean} closeOnClickOverlay 点击遮罩是否允许关闭 (默认 true )
* @property {Number|String} round 圆角值,默认无圆角 (默认 0 )
* @property {String} lang 指定返回用户信息的语言,zh_CN 简体中文,zh_TW 繁体中文,en 英文
* @property {String} sessionFrom 会话来源,openType="contact"时有效
* @property {String} sendMessageTitle 会话内消息卡片标题,openType="contact"时有效
* @property {String} sendMessagePath 会话内消息卡片点击跳转小程序路径,openType="contact"时有效
* @property {String} sendMessageImg 会话内消息卡片图片,openType="contact"时有效
* @property {Boolean} showMessageCard 是否显示会话内消息卡片,设置此参数为 true,用户进入客服会话会在右下角显示"可能要发送的小程序"提示,用户点击后可以快速发送小程序消息,openType="contact"时有效 (默认 false )
* @property {String} appParameter 打开 APP 时,向 APP 传递的参数,openType=launchApp 时有效
*
* @event {Function} select 点击ActionSheet列表项时触发
* @event {Function} close 点击取消按钮时触发
* @event {Function} getuserinfo 用户点击该按钮时,会返回获取到的用户信息,回调的 detail 数据与 wx.getUserInfo 返回的一致,openType="getUserInfo"时有效
* @event {Function} contact 客服消息回调,openType="contact"时有效
* @event {Function} getphonenumber 获取用户手机号回调,openType="getPhoneNumber"时有效
* @event {Function} error 当使用开放能力时,发生错误的回调,openType="error"时有效
* @event {Function} launchapp 打开 APP 成功的回调,openType="launchApp"时有效
* @event {Function} opensetting 在打开授权设置页后回调,openType="openSetting"时有效
* @example <u-action-sheet :actions="list" :title="title" :show="show"></u-action-sheet>
*/
export default {
name: "u-action-sheet",
// 一些props参数和methods方法,通过mixin混入,因为其他文件也会用到
mixins: [openType, button, uni.$u.mixin, props],
data() {
return {
}
},
computed: {
// 操作项目的样式
itemStyle() {
return (index) => {
let style = {};
if (this.actions[index].color) style.color = this.actions[index].color
if (this.actions[index].fontSize) style.fontSize = uni.$u.addUnit(this.actions[index].fontSize)
// 选项被禁用的样式
if (this.actions[index].disabled) style.color = '#c0c4cc'
return style;
}
},
},
methods: {
closeHandler() {
// 允许点击遮罩关闭时,才发出close事件
if(this.closeOnClickOverlay) {
this.$emit('close')
}
},
// 点击取消按钮
cancel() {
this.$emit('close')
},
selectHandler(index) {
const item = this.actions[index]
if (item && !item.disabled && !item.loading) {
this.$emit('select', item)
if (this.closeOnClickAction) {
this.$emit('close')
}
}
},
}
}
</script>
<style lang="scss" scoped>
@import "../../libs/css/components.scss";
$u-action-sheet-reset-button-width:100% !default;
$u-action-sheet-title-font-size: 16px !default;
$u-action-sheet-title-padding: 12px 30px !default;
$u-action-sheet-title-color: $u-main-color !default;
$u-action-sheet-header-icon-wrap-right:15px !default;
$u-action-sheet-header-icon-wrap-top:15px !default;
$u-action-sheet-description-font-size:13px !default;
$u-action-sheet-description-color:14px !default;
$u-action-sheet-description-margin: 18px 15px !default;
$u-action-sheet-item-wrap-item-padding:15px !default;
$u-action-sheet-item-wrap-name-font-size:16px !default;
$u-action-sheet-item-wrap-subname-font-size:13px !default;
$u-action-sheet-item-wrap-subname-color: #c0c4cc !default;
$u-action-sheet-item-wrap-subname-margin-top:10px !default;
$u-action-sheet-cancel-text-font-size:16px !default;
$u-action-sheet-cancel-text-color:$u-content-color !default;
$u-action-sheet-cancel-text-font-size:15px !default;
$u-action-sheet-cancel-text-hover-background-color:rgb(242, 243, 245) !default;
.u-reset-button {
width: $u-action-sheet-reset-button-width;
}
.u-action-sheet {
text-align: center;
&__header {
position: relative;
padding: $u-action-sheet-title-padding;
&__title {
font-size: $u-action-sheet-title-font-size;
color: $u-action-sheet-title-color;
font-weight: bold;
text-align: center;
}
&__icon-wrap {
position: absolute;
right: $u-action-sheet-header-icon-wrap-right;
top: $u-action-sheet-header-icon-wrap-top;
}
}
&__description {
font-size: $u-action-sheet-description-font-size;
color: $u-tips-color;
margin: $u-action-sheet-description-margin;
text-align: center;
}
&__item-wrap {
&__item {
padding: $u-action-sheet-item-wrap-item-padding;
@include flex;
align-items: center;
justify-content: center;
flex-direction: column;
&__name {
font-size: $u-action-sheet-item-wrap-name-font-size;
color: $u-main-color;
text-align: center;
}
&__subname {
font-size: $u-action-sheet-item-wrap-subname-font-size;
color: $u-action-sheet-item-wrap-subname-color;
margin-top: $u-action-sheet-item-wrap-subname-margin-top;
text-align: center;
}
}
}
&__cancel-text {
font-size: $u-action-sheet-cancel-text-font-size;
color: $u-action-sheet-cancel-text-color;
text-align: center;
padding: $u-action-sheet-cancel-text-font-size;
}
&--hover {
background-color: $u-action-sheet-cancel-text-hover-background-color;
}
}
</style>
export default {
props: {
// 图片地址,Array<String>|Array<Object>形式
urls: {
type: Array,
default: uni.$u.props.album.urls
},
// 指定从数组的对象元素中读取哪个属性作为图片地址
keyName: {
type: String,
default: uni.$u.props.album.keyName
},
// 单图时,图片长边的长度
singleSize: {
type: [String, Number],
default: uni.$u.props.album.singleSize
},
// 多图时,图片边长
multipleSize: {
type: [String, Number],
default: uni.$u.props.album.multipleSize
},
// 多图时,图片水平和垂直之间的间隔
space: {
type: [String, Number],
default: uni.$u.props.album.space
},
// 单图时,图片缩放裁剪的模式
singleMode: {
type: String,
default: uni.$u.props.album.singleMode
},
// 多图时,图片缩放裁剪的模式
multipleMode: {
type: String,
default: uni.$u.props.album.multipleMode
},
// 最多展示的图片数量,超出时最后一个位置将会显示剩余图片数量
maxCount: {
type: [String, Number],
default: uni.$u.props.album.maxCount
},
// 是否可以预览图片
previewFullImage: {
type: Boolean,
default: uni.$u.props.album.previewFullImage
},
// 每行展示图片数量,如设置,singleSize和multipleSize将会无效
rowCount: {
type: [String, Number],
default: uni.$u.props.album.rowCount
},
// 超出maxCount时是否显示查看更多的提示
showMore: {
type: Boolean,
default: uni.$u.props.album.showMore
}
}
}
This diff is collapsed.
export default {
props: {
// 显示文字
title: {
type: String,
default: uni.$u.props.alert.title
},
// 主题,success/warning/info/error
type: {
type: String,
default: uni.$u.props.alert.type
},
// 辅助性文字
description: {
type: String,
default: uni.$u.props.alert.description
},
// 是否可关闭
closable: {
type: Boolean,
default: uni.$u.props.alert.closable
},
// 是否显示图标
showIcon: {
type: Boolean,
default: uni.$u.props.alert.showIcon
},
// 浅或深色调,light-浅色,dark-深色
effect: {
type: String,
default: uni.$u.props.alert.effect
},
// 文字是否居中
center: {
type: Boolean,
default: uni.$u.props.alert.center
},
// 字体大小
fontSize: {
type: [String, Number],
default: uni.$u.props.alert.fontSize
}
}
}
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
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