applet
commit
edf7d20e6b
@ -0,0 +1,12 @@ |
||||
# 页面标题 |
||||
VITE_APP_TITLE = 寻驾-无人机 |
||||
|
||||
# 开发环境配置 |
||||
VITE_APP_ENV = 'development' |
||||
|
||||
# 寻驾-无人机/开发环境 |
||||
VITE_APP_BASE_API = 'https://cloud.ahfkbg.com/' |
||||
# VITE_APP_BASE_API = 'https://xj.ahduima.com/' |
||||
|
||||
# 资源地址 |
||||
VITE_UPLOAD_URL = 'https://cloud.ahfkbg.com/' |
@ -0,0 +1,14 @@ |
||||
# 页面标题 |
||||
VITE_APP_TITLE = 寻驾-无人机 |
||||
|
||||
# 开发环境配置 |
||||
VITE_APP_ENV = 'production' |
||||
|
||||
#开发环境 |
||||
VITE_APP_BASE_API = 'https://xj.ahduima.com/' |
||||
|
||||
# |
||||
VITE_WEB_BASE_URL = 'https://xj.ahduima.com' |
||||
|
||||
# 资源地址 |
||||
VITE_UPLOAD_URL = 'http://huodong.ahduima.com' |
@ -0,0 +1,23 @@ |
||||
.DS_Store |
||||
node_modules/ |
||||
dist/ |
||||
npm-debug.log* |
||||
yarn-debug.log* |
||||
yarn-error.log* |
||||
**/*.log |
||||
|
||||
tests/**/coverage/ |
||||
tests/e2e/reports |
||||
selenium-debug.log |
||||
|
||||
# Editor directories and files |
||||
.idea |
||||
.vscode |
||||
*.suo |
||||
*.ntvs* |
||||
*.njsproj |
||||
*.sln |
||||
*.local |
||||
|
||||
package-lock.json |
||||
yarn.lock |
@ -0,0 +1,20 @@ |
||||
<!DOCTYPE html> |
||||
<html lang="en"> |
||||
<head> |
||||
<meta charset="UTF-8" /> |
||||
<script> |
||||
var coverSupport = 'CSS' in window && typeof CSS.supports === 'function' && (CSS.supports('top: env(a)') || |
||||
CSS.supports('top: constant(a)')) |
||||
document.write( |
||||
'<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0' + |
||||
(coverSupport ? ', viewport-fit=cover' : '') + '" />') |
||||
</script> |
||||
<title></title> |
||||
<!--preload-links--> |
||||
<!--app-context--> |
||||
</head> |
||||
<body> |
||||
<div id="app"><!--app-html--></div> |
||||
<script type="module" src="/src/main.js"></script> |
||||
</body> |
||||
</html> |
@ -0,0 +1,9 @@ |
||||
{ |
||||
"compilerOptions": { |
||||
"types": [ |
||||
"@dcloudio/types", |
||||
"miniprogram-api-typings", |
||||
"mini-types" |
||||
] |
||||
} |
||||
} |
@ -0,0 +1,37 @@ |
||||
{ |
||||
"name": "xunjia", |
||||
"version": "1.0.0", |
||||
"scripts": { |
||||
"dev:h5": "uni", |
||||
"dev": "uni -p mp-weixin", |
||||
"dev:dy": "uni -p mp-toutiao", |
||||
"build:h5": "uni build", |
||||
"build": "node updateVersion.js && uni build -p mp-weixin", |
||||
"build:dy": "uni build -p mp-toutiao", |
||||
"build-test:mp-weixin": "uni --mode test -p mp-weixin" |
||||
}, |
||||
"dependencies": { |
||||
"@dcloudio/uni-app": "3.0.0-alpha-3060420220922001", |
||||
"@dcloudio/uni-app-plus": "3.0.0-alpha-3060420220922001", |
||||
"@dcloudio/uni-components": "3.0.0-alpha-3060420220922001", |
||||
"@dcloudio/uni-h5": "3.0.0-alpha-3060420220922001", |
||||
"@dcloudio/uni-mp-toutiao": "3.0.0-alpha-3060420220922001", |
||||
"@dcloudio/uni-mp-weixin": "3.0.0-alpha-3060420220922001", |
||||
"dayjs": "^1.11.13", |
||||
"jsencrypt-plus": "^0.1.0", |
||||
"pinia": "2.0.36", |
||||
"pinia-plugin-persist-uni": "^1.2.0", |
||||
"vue": "^3.2.37", |
||||
"vue-i18n": "^9.1.9" |
||||
}, |
||||
"devDependencies": { |
||||
"@dcloudio/types": "^3.0.13", |
||||
"@dcloudio/uni-automator": "3.0.0-alpha-3060420220922001", |
||||
"@dcloudio/uni-cli-shared": "3.0.0-alpha-3060420220922001", |
||||
"@dcloudio/uni-stacktracey": "3.0.0-alpha-3060420220922001", |
||||
"@dcloudio/vite-plugin-uni": "3.0.0-alpha-3060420220922001", |
||||
"sass": "^1.63.6", |
||||
"sass-loader": "^13.3.2", |
||||
"vite": "^2.9.14" |
||||
} |
||||
} |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,28 @@ |
||||
{ |
||||
"appid": "wx0668c6fabb1a9c44", |
||||
"compileType": "miniprogram", |
||||
"libVersion": "3.3.3", |
||||
"packOptions": { |
||||
"ignore": [], |
||||
"include": [] |
||||
}, |
||||
"setting": { |
||||
"coverView": true, |
||||
"es6": true, |
||||
"postcss": true, |
||||
"minified": true, |
||||
"enhance": true, |
||||
"showShadowRootInWxmlPanel": true, |
||||
"packNpmRelationList": [], |
||||
"babelSetting": { |
||||
"ignore": [], |
||||
"disablePlugins": [], |
||||
"outputPath": "" |
||||
} |
||||
}, |
||||
"condition": {}, |
||||
"editorSetting": { |
||||
"tabIndent": "insertSpaces", |
||||
"tabSize": 2 |
||||
} |
||||
} |
@ -0,0 +1,7 @@ |
||||
{ |
||||
"description": "项目私有配置文件。此文件中的内容将覆盖 project.config.json 中的相同字段。项目的改动优先同步到此文件中。详见文档:https://developers.weixin.qq.com/miniprogram/dev/devtools/projectconfig.html", |
||||
"projectname": "xunjia-applet", |
||||
"setting": { |
||||
"compileHotReLoad": true |
||||
} |
||||
} |
@ -0,0 +1,54 @@ |
||||
<script> |
||||
import useUserStore from '@/jtools/store/user' |
||||
import { getSysConfig } from '@/jtools/api/index'; |
||||
|
||||
export default { |
||||
onLaunch: function (options) { |
||||
if (useUserStore().isLogin) { |
||||
useUserStore().getUserInfo() |
||||
} |
||||
getSysConfig({ configKey: 'AppletShowAll', driverTypeId: -1 }).then(res => { |
||||
let arr = [] |
||||
if(res?.data?.configValue == 1) { |
||||
arr = [ |
||||
{ text: '首页', icon: 'home', name: '/pages/index/index' }, |
||||
{ text: '题库', icon: 'grid', name: '/pages/questionBank/index' }, |
||||
{ text: '我', icon: 'account', name: '/pages/me/index' } |
||||
|
||||
] |
||||
} else { |
||||
arr = [ |
||||
{ text: '题库', icon: 'grid', name: '/pages/questionBank/index' }, |
||||
{ text: '我', icon: 'account', name: '/pages/me/index' } |
||||
] |
||||
} |
||||
useUserStore().setTabbarList(arr) |
||||
}); |
||||
}, |
||||
onShow: function (options) { |
||||
// 如果是二维码扫描过来的,需要保存公司id |
||||
if (options.query?.scene) { |
||||
uni.showToast({ |
||||
title: '请重新登陆绑定分销人', |
||||
icon:'none', |
||||
success() { |
||||
setTimeout(() => { |
||||
useUserStore().setSellManId(options.query.scene) |
||||
}, 1500); |
||||
} |
||||
}) |
||||
} |
||||
console.log('App Show') |
||||
}, |
||||
onHide: function () { |
||||
console.log('App Hide') |
||||
}, |
||||
} |
||||
</script> |
||||
|
||||
<style lang="scss"> |
||||
@import "static/font/iconfont.css"; |
||||
@import "uni_modules/uview-plus/index.scss"; |
||||
@import "static/style/index.scss"; |
||||
|
||||
</style> |
@ -0,0 +1,596 @@ |
||||
<template> |
||||
<view class="chose-city"> |
||||
<!-- 城市搜索 --> |
||||
<view class="city-search-wrap"> |
||||
<view class="search"> |
||||
<view class="l-search"> |
||||
<view class="icon-search"> |
||||
<view class="cuIcon-search"></view> |
||||
</view> |
||||
<input class="input-search" type="text" :value="inputValue" placeholder="请输入城市" |
||||
placeholder-style="color:#8E8F97" :focus="searchFocus" @input="searchChange" /> |
||||
<text class="clear-input iconfont icon-icon-test" v-if="isClearBtn" @click="inputValue = ''"></text> |
||||
</view> |
||||
<view class="r-cancel" @click="closeModal">取消</view> |
||||
</view> |
||||
<!-- 搜索列表 --> |
||||
<view class="reach-content" v-show="inputValue"> |
||||
<block v-show="searchData.length"> |
||||
<view class="li" v-for="item in searchData" :key="item.citycode" @click="selectCity(item)"> |
||||
{{item.name}} |
||||
</view> |
||||
</block> |
||||
<view class="has-no-data" v-show="hasNoData">没有找到匹配数据~</view> |
||||
</view> |
||||
</view> |
||||
<!-- 城市列表 --> |
||||
<scroll-view class="scroll-view" scroll-y scroll-with-animation="true" enable-back-to-top="true" |
||||
:scroll-into-view="toIndex" @scroll="scrollHandle" v-if="!inputValue"> |
||||
<view class="block"> |
||||
<!-- 您所在的地区 --> |
||||
<view class="area list-item" id="area"> |
||||
<view class="title-wrapp"> |
||||
<view class="c-title"> |
||||
<text class="l">您所在的地区</text> |
||||
</view> |
||||
</view> |
||||
<view class="ul"> |
||||
<view class="li now font-clamp" @click="selectCity(myCityObj,'refresh')"> |
||||
<text class="text">{{ hasLocation ? myCityObj.name:'定位失败' }}</text> |
||||
</view> |
||||
</view> |
||||
</view> |
||||
<!-- 历史记录 --> |
||||
<view class="area list-item" id="record" v-if="recordList.length"> |
||||
<view class="title-wrapp"> |
||||
<view class="c-title"> |
||||
<text class="l">历史记录</text> |
||||
</view> |
||||
</view> |
||||
<view class="ul"> |
||||
<view class="li font-clamp" v-for="item in recordList" :key="item.citycode" @click="selectCity(item)"> |
||||
{{ item.name }} |
||||
</view> |
||||
</view> |
||||
</view> |
||||
</view> |
||||
<!-- 城市列表 --> |
||||
<view class="city-list"> |
||||
<view class="list list-item" v-for="(item, key) of cityList" :key="key" :id="item.nameType"> |
||||
<view class="c-title">{{ item.nameType }}</view> |
||||
<view class="item" v-for="innerItem in item.list" :key="innerItem.citycode" @click="selectCity(innerItem)"> |
||||
{{ innerItem.name }} |
||||
</view> |
||||
</view> |
||||
</view> |
||||
</scroll-view> |
||||
|
||||
<!-- 字母列表 --> |
||||
<view class="alphabet" @touchstart="touchStart" @touchend="touchEnd" @touchmove.stop="touchMove"> |
||||
<view v-for="(item, index) in alphabet" :key="index" @touchstart="getLetter" @touchend="setLetter" :id="item"> |
||||
<view class="item" :class="{ active: currentLetter == item }"> |
||||
{{ item == 'area' ? '当前' : item == 'record' ? '历史' : item }} |
||||
</view> |
||||
</view> |
||||
</view> |
||||
</view> |
||||
</template> |
||||
|
||||
<script> |
||||
import cityJson from '@/static/dataJson/city.json' |
||||
export default { |
||||
data() { |
||||
return { |
||||
isIPX: null, |
||||
regionId: null, // 区域ID |
||||
isToggle: true, |
||||
isReach: false, |
||||
inputValue: '', |
||||
searchData: [], // 搜索的数据 |
||||
isClearBtn: false, |
||||
toIndex: '', // 跳转的索引的字母 |
||||
tipsLetter: '', // 滑动显示字母 |
||||
timer: null, |
||||
hasNoData: false, |
||||
searchFocus: false, |
||||
letterDetails: [], |
||||
currentLetter: 'area', //默认选择 |
||||
cityArr: [], |
||||
recordList: [], |
||||
cityList: [], |
||||
hasLocation: false, |
||||
myCityObj: {}, |
||||
alphabet: [], |
||||
qqmap: null |
||||
}; |
||||
}, |
||||
mounted() { |
||||
this.cityArr = cityJson.data.list |
||||
if (this.cityArr && this.cityArr[0]) { |
||||
this.cityArr.map(v => { |
||||
v.nameType = v.pinyin.substr(0, 1) |
||||
}) |
||||
this.cityList = this.groupArr(this.cityArr, 'nameType') |
||||
} |
||||
this.recordList = cityJson.data.recordList |
||||
this.alphabet = cityJson.data.alphabet |
||||
this.getLocation() |
||||
}, |
||||
watch: { |
||||
// 城市搜索输入框 |
||||
inputValue(newVal) { |
||||
this.isClearBtn = newVal ? true : false; |
||||
|
||||
if (this.timer) { |
||||
clearTimeout(this.timer); |
||||
} |
||||
|
||||
if (!this.inputValue) { |
||||
this.searchData = []; |
||||
return; |
||||
} |
||||
this.timer = setTimeout(() => { |
||||
const result = []; |
||||
this.cityList.map(v => { |
||||
v.list.forEach((item) => { |
||||
if (/^[a-zA-Z]+$/.test(item.pinyin) && item.pinyin.toLowerCase().includes(this.inputValue |
||||
.toLowerCase()) || |
||||
item.name.includes(this.inputValue)) { |
||||
result.push(item); |
||||
} |
||||
}); |
||||
}) |
||||
this.searchData = result; |
||||
if (this.searchData.length === 0) { |
||||
this.hasNoData = true; |
||||
} else { |
||||
this.hasNoData = false; |
||||
} |
||||
}, 500); |
||||
}, |
||||
isReach(val) { |
||||
this.searchFocus = val; |
||||
}, |
||||
}, |
||||
methods: { |
||||
getLocation() { |
||||
const that = this |
||||
uni.getLocation({ |
||||
// #ifdef MP-ALIPAY |
||||
type: 2, |
||||
// #endif |
||||
success(res) { |
||||
const latitude = res.latitude; |
||||
const longitude = res.longitude; |
||||
uni.request({ |
||||
url: `https://apis.map.qq.com/ws/geocoder/v1/?location=${latitude},${longitude}&key=3ZYBZ-K3SK2-TGXUJ-CSTFH-7FQQ5-REFVK`, |
||||
success: function(res) { |
||||
const city = res.data.result.address_component.city; |
||||
that.myCityObj = { |
||||
name: city |
||||
}; |
||||
that.hasLocation = true |
||||
} |
||||
}); |
||||
}, |
||||
fail(err) { |
||||
that.hasLocation = false |
||||
uni.showToast({ |
||||
icon: 'none', |
||||
title: '获取用户定位失败,请手动选择当前城市' |
||||
}) |
||||
}, |
||||
}) |
||||
}, |
||||
groupArr(list, field) { |
||||
var fieldList = [], |
||||
att = []; |
||||
list.map((e) => { |
||||
fieldList.push(e[field]) |
||||
}) |
||||
//数组去重 |
||||
fieldList = fieldList.filter((e, i, self) => { |
||||
return self.indexOf(e) == i |
||||
}) |
||||
for (var j = 0; j < fieldList.length; j++) { |
||||
//过滤出匹配到的数据 |
||||
var arr = list.filter((e) => { |
||||
return e[field] == fieldList[j]; |
||||
}) |
||||
att.push({ |
||||
nameType: arr[0].nameType, |
||||
list: arr |
||||
}) |
||||
} |
||||
return att; |
||||
}, |
||||
selectCity(item, type) { |
||||
if (type === 'refresh' && !this.hasLocation) { |
||||
// 获取定位 |
||||
return this.getLocation() |
||||
} |
||||
// console.log('选择的城市:', item); |
||||
this.$emit('selectCity', item) |
||||
// 当前项目是需要选择到区域,所以选择城市后回到区县的地方 |
||||
this.toIndex = 'area'; |
||||
setTimeout(() => { |
||||
this.toIndex = ''; |
||||
}, 1000); |
||||
}, |
||||
closeModal() { |
||||
this.$emit('closeModal') |
||||
}, |
||||
//列表滚动,和右边字母表对应 |
||||
scrollHandle(e) { |
||||
let view = uni.createSelectorQuery().in(this).selectAll('.list-item'); |
||||
view |
||||
.boundingClientRect((d) => { |
||||
let top = d[0].top; |
||||
d.forEach((item) => { |
||||
item.top = item.top - top; |
||||
item.bottom = item.bottom - top; |
||||
this.letterDetails.push({ |
||||
id: item.id, |
||||
top: item.top, |
||||
bottom: item.bottom, |
||||
}); |
||||
}); |
||||
}) |
||||
.exec(); |
||||
|
||||
const scrollTop = e.detail.scrollTop; |
||||
this.letterDetails.some((item) => { |
||||
if (scrollTop >= item.top && scrollTop <= item.bottom - 20) { |
||||
this.currentLetter = item.id; |
||||
//当前固定用的是粘性定位,如果不用粘性定位,在这里设置 |
||||
return true; |
||||
} |
||||
}); |
||||
}, |
||||
|
||||
//搜索 |
||||
searchChange(e) { |
||||
let { |
||||
value |
||||
} = e.detail; |
||||
this.inputValue = value; |
||||
}, |
||||
// 触发开始 |
||||
touchStart(e) { |
||||
// console.log(e); |
||||
}, |
||||
//移动时 |
||||
touchMove(e) { |
||||
uni.vibrateShort(); |
||||
let y = e.touches[0].clientY; |
||||
let offsettop = e.currentTarget.offsetTop; |
||||
|
||||
//判断选择区域,只在选择区才会生效 |
||||
if (y > offsettop) { |
||||
let num = parseInt((y - offsettop) / 15); //右边每个字母元素的高度 |
||||
let letter = this.alphabet[num]; |
||||
this.tipsLetter = letter; |
||||
|
||||
let curentLetter = this.letterTransform(letter); |
||||
uni.showToast({ |
||||
title: curentLetter, |
||||
icon: 'none', |
||||
}); |
||||
} |
||||
}, |
||||
//触发结束 |
||||
touchEnd() { |
||||
this.toIndex = this.tipsLetter; |
||||
}, |
||||
//移动开始获取字母,并放大提示 |
||||
getLetter(e) { |
||||
uni.vibrateShort(); |
||||
let { |
||||
id |
||||
} = e.currentTarget; |
||||
this.tipsLetter = id; |
||||
|
||||
let curentLetter = this.letterTransform(id); |
||||
uni.showToast({ |
||||
title: curentLetter, |
||||
icon: 'none', |
||||
}); |
||||
}, |
||||
//移动结束设置字母,赋值到toIndex |
||||
setLetter() { |
||||
this.toIndex = this.tipsLetter; |
||||
}, |
||||
|
||||
//提示字母转换 |
||||
letterTransform(letter) { |
||||
let str = ''; |
||||
if (letter == 'area') { |
||||
str = '当前'; |
||||
} else if (letter == 'record') { |
||||
str = '历史'; |
||||
} else { |
||||
str = letter; |
||||
} |
||||
return str; |
||||
}, |
||||
}, |
||||
} |
||||
</script> |
||||
|
||||
<style lang="scss" scoped> |
||||
.chose-city { |
||||
position: fixed; |
||||
top: 0; |
||||
left: 0; |
||||
right: 0; |
||||
bottom: 0; |
||||
z-index: 99; |
||||
background: #fff; |
||||
} |
||||
|
||||
.city-search-wrap { |
||||
width: 100%; |
||||
box-sizing: border-box; |
||||
|
||||
.search { |
||||
width: 750rpx; |
||||
height: 110rpx; |
||||
display: flex; |
||||
align-items: center; |
||||
font-size: 28rpx; |
||||
color: #222; |
||||
padding: 14rpx 36rpx; |
||||
box-sizing: border-box; |
||||
background: #fff; |
||||
|
||||
.l-search { |
||||
width: 597rpx; |
||||
position: relative; |
||||
height: 72rpx; |
||||
line-height: 72rpx; |
||||
|
||||
.icon-search { |
||||
font-size: 28rpx; |
||||
position: absolute; |
||||
left: 30rpx; |
||||
top: 0; |
||||
color: #8e8f97; |
||||
font-weight: 700; |
||||
height: 72rpx; |
||||
line-height: 72rpx; |
||||
} |
||||
|
||||
.input-search { |
||||
width: 597rpx; |
||||
height: 72rpx; |
||||
box-sizing: border-box; |
||||
padding: 0 84rpx 0 84rpx; |
||||
text-align: left; |
||||
background: #f4f5f9; |
||||
border-radius: 12rpx; |
||||
border: 0; |
||||
} |
||||
|
||||
.clear-input { |
||||
font-size: 30rpx; |
||||
position: absolute; |
||||
right: 10rpx; |
||||
top: 50%; |
||||
transform: translateY(-50%); |
||||
padding: 10rpx; |
||||
color: #8e8f97; |
||||
} |
||||
} |
||||
|
||||
.r-cancel { |
||||
width: 80rpx; |
||||
box-sizing: border-box; |
||||
padding-left: 24rpx; |
||||
font-size: 28rpx; |
||||
height: 72rpx; |
||||
line-height: 72rpx; |
||||
background: transparent; |
||||
border: 0; |
||||
color: #519AD2; |
||||
} |
||||
} |
||||
} |
||||
|
||||
.reach-content { |
||||
padding-left: 36rpx; |
||||
box-sizing: border-box; |
||||
|
||||
.li { |
||||
width: 714rpx; |
||||
font-size: 28rpx; |
||||
height: 100rpx; |
||||
line-height: 100rpx; |
||||
color: #333; |
||||
position: relative; |
||||
box-sizing: border-box; |
||||
border-bottom: 2rpx solid #F5F5F5; |
||||
} |
||||
} |
||||
|
||||
.block { |
||||
padding: 0 36rpx; |
||||
box-sizing: border-box; |
||||
} |
||||
|
||||
.top-search { |
||||
line-height: 72rpx; |
||||
padding: 14rpx 30rpx 0; |
||||
box-sizing: border-box; |
||||
margin-bottom: 26rpx; |
||||
|
||||
.item { |
||||
background: #F5F5F5; |
||||
border-radius: 12rpx; |
||||
font-size: 28rpx; |
||||
text-align: center; |
||||
color: #999999; |
||||
/* #ifdef MP-ALIPAY */ |
||||
height: 72rpx; |
||||
line-height: 72rpx; |
||||
|
||||
/* #endif */ |
||||
text { |
||||
padding-left: 20rpx; |
||||
color: #c1c2cd; |
||||
vertical-align: middle; |
||||
position: relative; |
||||
top: -4rpx; |
||||
} |
||||
|
||||
} |
||||
} |
||||
|
||||
.scroll-view { |
||||
width: 100%; |
||||
height: calc(100vh - 110rpx); |
||||
box-sizing: border-box; |
||||
} |
||||
|
||||
.area { |
||||
margin-bottom: 8rpx; |
||||
|
||||
.title-wrapp { |
||||
position: sticky; |
||||
top: 0; |
||||
left: 0; |
||||
background: #fff; |
||||
} |
||||
|
||||
.c-title { |
||||
width: 100%; |
||||
box-sizing: border-box; |
||||
font-size: 28rpx; |
||||
color: #999999; |
||||
margin-bottom: 24rpx; |
||||
display: inline-flex; |
||||
justify-content: space-between; |
||||
align-items: center; |
||||
|
||||
.r { |
||||
font-size: 24rpx; |
||||
color: #8e8f97; |
||||
display: inline-block; |
||||
align-items: center; |
||||
|
||||
.iconfont { |
||||
font-size: 24rpx; |
||||
} |
||||
} |
||||
} |
||||
|
||||
.ul { |
||||
display: flex; |
||||
flex-wrap: wrap; |
||||
|
||||
.li { |
||||
width: 155rpx; |
||||
padding: 0 10rpx; |
||||
box-sizing: border-box; |
||||
height: 72rpx; |
||||
line-height: 68rpx; |
||||
text-align: center; |
||||
font-size: 32rpx; |
||||
color: #333; |
||||
border-radius: 8rpx; |
||||
margin: 0 18rpx 28rpx 0; |
||||
border: 2rpx solid #E2E2E2; |
||||
|
||||
&:nth-child(4n) { |
||||
margin-right: 0; |
||||
} |
||||
|
||||
&.now { |
||||
width: auto; |
||||
padding: 0 32rpx 0 22rpx; |
||||
|
||||
.icon { |
||||
width: 50rpx; |
||||
height: 50rpx; |
||||
background-size: 100%; |
||||
vertical-align: middle; |
||||
position: relative; |
||||
top: -4rpx; |
||||
} |
||||
|
||||
.text { |
||||
padding-left: 10rpx; |
||||
} |
||||
} |
||||
|
||||
&.active { |
||||
font-weight: 500; |
||||
background: #ffde45; |
||||
} |
||||
} |
||||
|
||||
.hover { |
||||
background: #ffde45; |
||||
} |
||||
} |
||||
} |
||||
|
||||
.city-list { |
||||
width: 750rpx; |
||||
padding-bottom: 50rpx; |
||||
|
||||
.c-title { |
||||
height: 60rpx; |
||||
line-height: 60rpx; |
||||
font-size: 30rpx; |
||||
font-weight: 500; |
||||
color: #272636; |
||||
background: #fff; |
||||
box-sizing: border-box; |
||||
padding-left: 36rpx; |
||||
position: sticky; |
||||
top: 0; |
||||
left: 0; |
||||
z-index: 2; |
||||
} |
||||
|
||||
.item { |
||||
width: 714rpx; |
||||
margin-left: 36rpx; |
||||
padding: 0 36rpx 0 0; |
||||
height: 100rpx; |
||||
line-height: 100rpx; |
||||
color: #333; |
||||
font-size: 28rpx; |
||||
box-sizing: border-box; |
||||
border-bottom: 2rpx solid #F5F5F5; |
||||
} |
||||
} |
||||
|
||||
.alphabet { |
||||
position: fixed; |
||||
right: 0; |
||||
bottom: 20%; |
||||
width: calc(750rpx - 680rpx); |
||||
text-align: center; |
||||
font-size: 20rpx; |
||||
font-weight: 700; |
||||
color: #8e8f97; |
||||
z-index: 99; |
||||
|
||||
.item { |
||||
height: 15px; |
||||
line-height: 15px; |
||||
} |
||||
|
||||
.active { |
||||
color: #222; |
||||
} |
||||
} |
||||
|
||||
.has-no-data { |
||||
font-size: 24rpx; |
||||
text-align: center; |
||||
color: #8e8f97; |
||||
margin-top: 50rpx; |
||||
} |
||||
</style> |
@ -0,0 +1,43 @@ |
||||
import request from '../request/index.js'; |
||||
|
||||
export function getExamQuestion(data) { |
||||
return request({ |
||||
url: 'wrj-api/wrjQuestionTest/test', |
||||
method: 'GET', |
||||
data |
||||
}); |
||||
} |
||||
|
||||
export function getCurrentTest(data) { |
||||
return request({ |
||||
url: 'wrj-api/wrjQuestionTest/getCurrentTest', |
||||
method: 'GET', |
||||
data |
||||
}); |
||||
} |
||||
|
||||
export function getExamInfo(data) { |
||||
return request({ |
||||
url: 'wrj-api/wrjQuestionTest/getQuestionTestMessageById', |
||||
method: 'GET', |
||||
data |
||||
}); |
||||
} |
||||
|
||||
// 交卷
|
||||
export function submitExam(data) { |
||||
return request({ |
||||
url: 'wrj-api/wrjQuestionTest/testSubmit', |
||||
method: 'POST', |
||||
data |
||||
}); |
||||
} |
||||
|
||||
// 获取考试记录
|
||||
export function getExamRecord(data) { |
||||
return request({ |
||||
url: 'wrj-api/wrjQuestionTest/getTestScore', |
||||
method: 'POST', |
||||
data |
||||
}); |
||||
} |
@ -0,0 +1,96 @@ |
||||
import request from '../request/index.js'; |
||||
|
||||
export function getCarTypeList(data) { |
||||
return request({ |
||||
url: 'wrj-api/wrjModel/list', |
||||
method: 'GET', |
||||
data, |
||||
noToken: true |
||||
}); |
||||
} |
||||
export function getDriverTypeList(data) { |
||||
return request({ |
||||
url: 'wrj-api/wrjDriverType/list', |
||||
method: 'GET', |
||||
data, |
||||
noToken: true |
||||
}); |
||||
} |
||||
|
||||
// 获取章节列表
|
||||
export function getChapterOptions(data) { |
||||
return request({ |
||||
url: 'wrj-api/wrjChapter/queryChapter', |
||||
method: 'POST', |
||||
data |
||||
}); |
||||
} |
||||
|
||||
export function getChapterInfo(data) { |
||||
return request({ |
||||
url: 'wrj-api/wrjChapter/queryChapterInfo', |
||||
method: 'POST', |
||||
data |
||||
}); |
||||
} |
||||
|
||||
export function getChapterDoneList(data) { |
||||
return request({ |
||||
url: 'wrj-api/wrjChapter/queryChapterQuestionNumWithUser', |
||||
method: 'GET', |
||||
data |
||||
}); |
||||
} |
||||
|
||||
export function uploadFile(data) { |
||||
return request({ |
||||
url: 'wrj-api/system/file/upload', |
||||
method: 'POST', |
||||
data |
||||
}); |
||||
} |
||||
|
||||
// 查询考点列表
|
||||
export function queryExamPoint(data) { |
||||
return request({ |
||||
url: 'wrj-api/wrjExamPlace/pageList', |
||||
method: 'POST', |
||||
data |
||||
}); |
||||
} |
||||
|
||||
// 查询考点时间
|
||||
export function queryExamPointTime(data) { |
||||
return request({ |
||||
url: 'wrj-api/wrjExamPlace/queryDate', |
||||
method: 'POST', |
||||
data |
||||
}); |
||||
} |
||||
|
||||
// 根据时间查询考点
|
||||
export function queryExamPointByTime(data) { |
||||
return request({ |
||||
url: 'wrj-api/wrjExamPlace/query', |
||||
method: 'POST', |
||||
data |
||||
}); |
||||
} |
||||
|
||||
// 收藏考点
|
||||
export function collectExamPoint(placeId) { |
||||
return request({ |
||||
url: 'wrj-api/wrjUserCollectPlace/update?placeId=' + placeId, |
||||
method: 'POST' |
||||
}); |
||||
} |
||||
|
||||
// 获取配置项
|
||||
export function getSysConfig(data) { |
||||
return request({ |
||||
url: 'wrj-api/wrjSysConfig/queryConfigByKey', |
||||
method: 'GET', |
||||
data, |
||||
noToken: true |
||||
}); |
||||
} |
@ -0,0 +1,24 @@ |
||||
import request from '../request/index.js'; |
||||
|
||||
export function login(data) { |
||||
return request({ |
||||
url: 'wrj-api/sysUser/login', |
||||
method: 'POST', |
||||
data, |
||||
noToken: true |
||||
}); |
||||
} |
||||
|
||||
export function logout() { |
||||
return request({ |
||||
url: 'wrj-api/sysUser/loginOut', |
||||
method: 'get' |
||||
}); |
||||
} |
||||
|
||||
export function getInfo() { |
||||
return request({ |
||||
url: 'wrj-api/sysUser/queryUserMessage', |
||||
method: 'get' |
||||
}); |
||||
} |
@ -0,0 +1,93 @@ |
||||
import request from '../request/index.js'; |
||||
|
||||
export function queryQuestion(data) { |
||||
return request({ |
||||
url: 'wrj-api/wrjQuestion/queryQuestionWithUser', |
||||
method: 'POST', |
||||
data |
||||
}); |
||||
} |
||||
|
||||
export function queryQuestionEmpty(data) { |
||||
return request({ |
||||
url: 'wrj-api/wrjQuestion/queryQuestion', |
||||
method: 'POST', |
||||
data |
||||
}); |
||||
} |
||||
|
||||
export function doExercise(data) { |
||||
return request({ |
||||
url: 'wrj-api/wrjQuestionPractice/insert', |
||||
method: 'POST', |
||||
data |
||||
}); |
||||
} |
||||
|
||||
export function clearPractice(params) { |
||||
return request({ |
||||
url: `wrj-api/wrjQuestionPractice/clear?practiceType=${params.practiceType}&businessCode=${params.businessCode}`, |
||||
method: 'POST' |
||||
}); |
||||
} |
||||
|
||||
// 收藏
|
||||
export function collectQuestion(questionId) { |
||||
return request({ |
||||
url: `wrj-api/wrjUserCollectQuestion/update?questionId=${questionId}`, |
||||
method: 'POST' |
||||
}); |
||||
} |
||||
|
||||
// 获取收藏题目
|
||||
export function queryLikeQuestion(data) { |
||||
return request({ |
||||
url: `wrj-api/wrjUserCollectQuestion/getUserCollectQuestion`, |
||||
method: 'GET', |
||||
data |
||||
}); |
||||
} |
||||
|
||||
// 获取错题
|
||||
export function queryErrorQuestion(data) { |
||||
return request({ |
||||
url: `wrj-api/wrjUserErrorQuestion/getUserErrorQuestion`, |
||||
method: 'GET', |
||||
data |
||||
}); |
||||
} |
||||
|
||||
// 获取收藏的列表
|
||||
export function queryCollectList(driverTypeId) { |
||||
return request({ |
||||
url: `wrj-api/wrjUserCollectQuestion/getUserCollectQuestionId?driverTypeId=${driverTypeId}`, |
||||
method: 'GET' |
||||
}); |
||||
} |
||||
|
||||
// 移除错题
|
||||
export function removeErrorQuestion(questionId) { |
||||
return request({ |
||||
url: `wrj-api/wrjUserErrorQuestion/remove?questionId=${questionId}`, |
||||
method: 'POST' |
||||
}); |
||||
} |
||||
|
||||
// 获取首页信息
|
||||
export function queryIndexInfo(data) { |
||||
return request({ |
||||
url: 'wrj-api/wrjQuestion/getIndexData', |
||||
method: 'GET', |
||||
data, |
||||
publicApi: true |
||||
}); |
||||
} |
||||
|
||||
// 获取考试信息
|
||||
export function queryIndexDetail(data) { |
||||
return request({ |
||||
url: 'wrj-api/wrjDriverType/detail', |
||||
method: 'GET', |
||||
data |
||||
}); |
||||
} |
@ -0,0 +1,51 @@ |
||||
import request from '../request/index.js'; |
||||
|
||||
export function getStationList(data) { |
||||
return request({ |
||||
url: 'wrj-api/wrjSchool/pageList', |
||||
method: 'POST', |
||||
data, |
||||
noToken: true |
||||
}); |
||||
} |
||||
|
||||
// 培训机构注册
|
||||
export function registerStation(data) { |
||||
return request({ |
||||
url: 'wrj-api/wrjSchool/insert', |
||||
method: 'POST', |
||||
data, |
||||
noToken: true |
||||
}); |
||||
} |
||||
|
||||
export function getStationDetail(schoolId) { |
||||
return request({ |
||||
url: 'wrj-api/wrjSchool/detail?schoolId=' + schoolId, |
||||
method: 'GET', |
||||
publicApi: true |
||||
}); |
||||
} |
||||
|
||||
// 收藏
|
||||
export function collectStation(schoolId) { |
||||
return request({ |
||||
url: 'wrj-api/wrjUserCollectSchool/update?schoolId=' + schoolId, |
||||
method: 'POST', |
||||
}); |
||||
} |
||||
|
||||
// 获取驾培机型
|
||||
export function getCarTypeList() { |
||||
return request({ |
||||
url: 'wrj-api/wrjSchoolDriverType/list', |
||||
method: 'GET', |
||||
}); |
||||
} |
||||
// 查询收藏的机构
|
||||
export function queryCollectList() { |
||||
return request({ |
||||
url: 'wrj-api/wrjUserCollectSchool/myList', |
||||
method: 'POST', |
||||
}); |
||||
} |
@ -0,0 +1,45 @@ |
||||
import request from '../request/index.js'; |
||||
|
||||
export function chooseType(data) { |
||||
return request({ |
||||
url: 'wrj-api/sysUser/driverTypeChoose', |
||||
method: 'POST', |
||||
data |
||||
}); |
||||
} |
||||
|
||||
// 修改用户资料
|
||||
export function updateUserInfo(data) { |
||||
return request({ |
||||
url: 'wrj-api/sysUser/update', |
||||
method: 'POST', |
||||
data |
||||
}); |
||||
} |
||||
|
||||
// 教员入驻
|
||||
export function teacherRegister(data) { |
||||
return request({ |
||||
url: 'wrj-api/wrjTeacher/apply', |
||||
method: 'POST', |
||||
data |
||||
}); |
||||
} |
||||
|
||||
// 报名咨询
|
||||
export function applyConsult(data) { |
||||
return request({ |
||||
url: 'wrj-api/wrjClue/consult', |
||||
method: 'POST', |
||||
data |
||||
}); |
||||
} |
||||
|
||||
|
||||
// 获取收藏的考点
|
||||
export function getCollecRoomList() { |
||||
return request({ |
||||
url: 'wrj-api/wrjUserCollectPlace/myList', |
||||
method: 'POST', |
||||
}); |
||||
} |
@ -0,0 +1,11 @@ |
||||
|
||||
// 请求状态码
|
||||
const RESPONSE_TYPE = { |
||||
SUCCESS: '0000', |
||||
RELOGIN: 'E403', |
||||
ERROR: '4000' |
||||
}; |
||||
|
||||
export default { |
||||
RESPONSE_TYPE, |
||||
}; |
@ -0,0 +1,5 @@ |
||||
import common from './common.js' |
||||
|
||||
export default { |
||||
...common |
||||
} |
@ -0,0 +1,160 @@ |
||||
import request from '../request/index.js'; |
||||
// #ifdef H5
|
||||
// import wxsdk from '@/jtools/wechat/sdk'
|
||||
// #endif
|
||||
// import wechat from '@/jtools/wechat/wechat'
|
||||
import $platform from '@/jtools/platform'; |
||||
import {prePay} from '@/jtools/api/pay' |
||||
/** |
||||
* 支付 |
||||
*
|
||||
* @param {String} payment = ['wechat','alipay','wallet'] - 支付方式 |
||||
* @param {Object} order = {} - 订单详情 |
||||
* @param {String} orderType = ['goods','recharge'] - 订单类型 |
||||
*/ |
||||
|
||||
export default class JtoolsPay { |
||||
|
||||
|
||||
// wxOfficialAccount wxMiniProgram App H5
|
||||
// wechat 公众号JSSDK支付 小程序支付 微信开放平台支付 H5网页支付
|
||||
// alipay 复制网址 复制网址 支付宝开放平台支付 直接跳转链接
|
||||
// wallet v v v v
|
||||
|
||||
|
||||
constructor(payment, order, orderType) { |
||||
this.payment = payment; |
||||
this.order = order; |
||||
this.orderType = orderType; |
||||
this.platform = $platform.get(); |
||||
let payMehod = this.getPayMethod(); |
||||
payMehod(); |
||||
|
||||
} |
||||
|
||||
getPayMethod() { |
||||
var payMethod = { |
||||
'wxMiniProgram': { |
||||
'wechat': () => { |
||||
this.wxMiniProgramPay() |
||||
}, |
||||
}, |
||||
'App': { |
||||
'wechat': () => { |
||||
this.wechatPay() |
||||
}, |
||||
'alipay': () => { |
||||
this.aliPay() |
||||
}, |
||||
}, |
||||
} |
||||
return payMethod[this.platform][this.payment]; |
||||
} |
||||
|
||||
|
||||
|
||||
// 预支付
|
||||
prepay() { |
||||
let that = this; |
||||
return new Promise((resolve, reject) => { |
||||
const p = $platform.device() |
||||
const tradeInfoType = p == 'android' ? 'Android' : p == 'ios' ? 'iOS' : 'Wap' |
||||
let params = { |
||||
"code":this.order.code, |
||||
"description": this.order.description, |
||||
"money": this.order.money, |
||||
"outTradeNo": this.order.outTradeNo, |
||||
"userId": this.order.userId, |
||||
"tradeType":'1', |
||||
"detailId": this.order.detailId |
||||
} |
||||
if (uni.getStorageSync('openId')) { |
||||
params.openId = uni.getStorageSync('openId'); |
||||
} |
||||
prePay(params).then(res => { |
||||
console.log('预支付',res); |
||||
if (res.code == '0000') { |
||||
resolve(res); |
||||
} |
||||
}) |
||||
}); |
||||
} |
||||
|
||||
|
||||
// 微信小程序支付
|
||||
async wxMiniProgramPay() { |
||||
let that = this; |
||||
let result = await this.prepay(); |
||||
const params = result.data |
||||
uni.requestPayment({ |
||||
provider: 'wxpay', |
||||
...{ |
||||
appId: params.appId, //公众号名称,由商户传入
|
||||
timeStamp: params.timeStamp, //时间戳,自1970年以来的秒数
|
||||
nonceStr: params.nonceStr, //随机串
|
||||
package: params.packageVal, |
||||
signType: params.signType, //微信签名方式:
|
||||
paySign: params.paySign, //微信签名
|
||||
}, |
||||
success: res => { |
||||
console.log(res); |
||||
that.payResult('success', result.data.orderPayNo) |
||||
}, |
||||
fail: err => { |
||||
console.log('支付取消或者失败:', err); |
||||
err.errMsg !== "requestPayment:fail cancel" && that.payResult('fail') |
||||
} |
||||
}); |
||||
} |
||||
|
||||
|
||||
|
||||
// 支付宝支付
|
||||
async aliPay() { |
||||
let that = this; |
||||
let result = await this.prepay(); |
||||
if (result.code === 1) { |
||||
uni.requestPayment({ |
||||
provider: 'alipay', |
||||
orderInfo: result.data.pay_data, //支付宝订单数据
|
||||
success: res => { |
||||
that.payResult('success') |
||||
}, |
||||
fail: err => { |
||||
err.errMsg !== "requestPayment:fail cancel" && that.payResult('fail') |
||||
} |
||||
}); |
||||
} |
||||
} |
||||
|
||||
// 微信支付
|
||||
async wechatPay() { |
||||
let that = this; |
||||
let result = await this.prepay(); |
||||
console.log('微信支付'); |
||||
if (result.code === 1) { |
||||
uni.requestPayment({ |
||||
provider: 'wxpay', |
||||
orderInfo: JSON.parse(result.data.pay_data), //微信订单数据(官方说是string。实测为object)
|
||||
success: res => { |
||||
that.payResult('success') |
||||
}, |
||||
fail: err => { |
||||
err.errMsg !== "requestPayment:fail cancel" && that.payResult('fail') |
||||
console.log('支付取消或者失败:', err); |
||||
} |
||||
}); |
||||
} |
||||
} |
||||
|
||||
|
||||
// 支付结果跳转,success:成功,fail:失败
|
||||
payResult(resultType, orderPayNo) { |
||||
const that = this; |
||||
let path = 'paySuccess' |
||||
uni.navigateTo({ |
||||
url: path |
||||
}) |
||||
} |
||||
|
||||
} |
@ -0,0 +1,75 @@ |
||||
/** |
||||
* Platform v1.0.0 |
||||
* @Class Platform |
||||
* @description jtools-platform 1.0.0 全平台兼容 |
||||
* @Author lidongtony |
||||
* @Date 2021-04-07 |
||||
* @Email lidongtony@qq.com |
||||
*/ |
||||
|
||||
// #ifdef H5
|
||||
// 微信H5
|
||||
import wxsdk from '@/jtools/wechat/sdk'; |
||||
// #endif
|
||||
export default { |
||||
// 获取当前运行平台
|
||||
get() { |
||||
let platform = ''; |
||||
// #ifdef H5
|
||||
wxsdk.isWechat() ? (platform = 'wxOfficialAccount') : (platform = 'H5'); |
||||
// #endif
|
||||
// #ifdef APP-PLUS
|
||||
platform = 'App'; |
||||
// #endif
|
||||
// #ifdef MP-WEIXIN
|
||||
platform = 'wxMiniProgram'; |
||||
// #endif
|
||||
// #ifdef MP-ALIPAY
|
||||
platform = 'alipayMiniProgram'; |
||||
// #endif
|
||||
if (platform !== '') { |
||||
uni.setStorageSync('platform', platform); |
||||
} else { |
||||
uni.showToast({ |
||||
title: '暂不支持该平台', |
||||
icon: 'none' |
||||
}); |
||||
} |
||||
return platform; |
||||
}, |
||||
set(platform) { |
||||
uni.setStorageSync('platform', platform); |
||||
return platform; |
||||
}, |
||||
|
||||
// 检测当前运行机型
|
||||
device() { |
||||
return uni.getDeviceInfo().platform; |
||||
}, |
||||
|
||||
// 获取前端真实主机
|
||||
host() { |
||||
let host = location.origin; |
||||
let basePath = router.$route.options.base; |
||||
let mode = router.$route.options.mode; |
||||
host += basePath; |
||||
if (mode === 'hash') { |
||||
host += '#/'; |
||||
} |
||||
return host; |
||||
}, |
||||
|
||||
// 处理wechat jssdk 签名网址(针对IOS微信浏览器做优化)
|
||||
entry() { |
||||
let that = this; |
||||
var entryUrl = location.href; |
||||
if (this.device() === 'ios') { |
||||
if (typeof location.entryUrl !== 'undefined') { |
||||
entryUrl = location.entryUrl; |
||||
} else { |
||||
location.entryUrl = entryUrl; |
||||
} |
||||
} |
||||
return entryUrl; |
||||
} |
||||
}; |
@ -0,0 +1,60 @@ |
||||
import storage from '../storage/index.js'; |
||||
import useUserStore from '@/jtools/store/user'; |
||||
|
||||
//把配置项单独处理
|
||||
let server_url = ' '; // 请求地址
|
||||
let token = ' '; // 凭证
|
||||
|
||||
server_url = import.meta.env.VITE_APP_BASE_API; //环境配置
|
||||
function service(options = {}) { |
||||
storage.get('token') && (token = storage.get('token')); |
||||
options.url = `${server_url}${options.url}`; |
||||
if (!options.noToken) { |
||||
if (!!options.publicApi) { |
||||
if (token.trim()) { |
||||
options.header = { |
||||
Authorization: `${token}` |
||||
}; |
||||
} |
||||
} else if (!token.trim()) { |
||||
uni.navigateTo({ |
||||
url: '/pages/me/login' |
||||
}); |
||||
} else { |
||||
options.header = { |
||||
Authorization: `${token}` |
||||
}; |
||||
} |
||||
} |
||||
return new Promise((resolved, rejected) => { |
||||
//成功
|
||||
options.success = res => { |
||||
if (res.data.code == 'E403') { |
||||
// 未登录
|
||||
uni.showToast({ |
||||
title: res?.data?.message || '请重新登录', |
||||
icon: 'none' |
||||
}); |
||||
useUserStore().logoutWithoutToken(); |
||||
//请求成功
|
||||
resolved(res.data); |
||||
} else if (res.data.code != '0000' && res.data.code != '4001' && res.data.code != 200) { |
||||
uni.hideLoading(); |
||||
uni.showToast({ |
||||
title: res?.data?.message || '访问出错', |
||||
icon: 'none' |
||||
}); |
||||
resolved(res.data); |
||||
} else { |
||||
//请求成功
|
||||
resolved(res.data); |
||||
} |
||||
}; |
||||
//错误
|
||||
options.fail = err => { |
||||
rejected(err); //错误
|
||||
}; |
||||
uni.request(options); |
||||
}); |
||||
} |
||||
export default service; |
@ -0,0 +1,40 @@ |
||||
const APP_NAME = import.meta.env.VITE_APP_TITLE |
||||
export default { |
||||
set(key, value) { |
||||
// 命名规则 小程序名称-环境
|
||||
const storageName = `${APP_NAME}-${process.env.NODE_ENV}` |
||||
const temp = uni.getStorageSync(storageName) || {} |
||||
temp[key] = value |
||||
uni.setStorageSync(storageName, temp) |
||||
}, |
||||
get(key) { |
||||
// 命名规则 小程序名称-环境
|
||||
const storageName = `${APP_NAME}-${process.env.NODE_ENV}` |
||||
const temp = uni.getStorageSync(storageName) || {} |
||||
if(temp.hasOwnProperty(key)) { |
||||
return temp[key] |
||||
} else { |
||||
return undefined |
||||
} |
||||
}, |
||||
remove(key) { |
||||
// 命名规则 小程序名称-环境
|
||||
const storageName = `${APP_NAME}-${process.env.NODE_ENV}` |
||||
const temp = uni.getStorageSync(storageName) || {} |
||||
if(temp.hasOwnProperty(key)) { |
||||
delete temp[key]; |
||||
uni.setStorageSync(storageName, temp); |
||||
} |
||||
}, |
||||
has(key) { |
||||
// 命名规则 小程序名称-环境
|
||||
const storageName = `${APP_NAME}-${process.env.NODE_ENV}` |
||||
const temp = uni.getStorageSync(storageName) || {} |
||||
return temp.hasOwnProperty(key) |
||||
}, |
||||
clear() { |
||||
// 命名规则 小程序名称-环境
|
||||
const storageName = `${APP_NAME}-${process.env.NODE_ENV}` |
||||
uni.removeStorageSync(storageName) |
||||
} |
||||
} |
@ -0,0 +1,18 @@ |
||||
import { createPinia } from 'pinia'; |
||||
|
||||
// 自动注入所有pinia模块
|
||||
const files = import.meta.globEager('./*.js'); |
||||
const modules = {}; |
||||
Object.keys(files).forEach((key) => { |
||||
modules[key.replace(/(.*\/)*([^.]+).*/gi, '$2')] = files[key].default; |
||||
}); |
||||
|
||||
export const setupPinia = (app) => { |
||||
const pinia = createPinia(); |
||||
|
||||
app.use(pinia); |
||||
}; |
||||
|
||||
export default (name) => { |
||||
return modules[name](); |
||||
}; |
@ -0,0 +1,103 @@ |
||||
import { defineStore } from 'pinia'; |
||||
import { login, getInfo } from '@/jtools/api/login'; |
||||
import storage from '@/jtools/storage'; |
||||
|
||||
const useUserStore = defineStore({ |
||||
id: 'user', |
||||
state: () => ({ |
||||
token: storage.get('token'), |
||||
isLogin: storage.get('isLogin'), // 是否登陆
|
||||
userInfo: {}, // 用户信息
|
||||
sellManId: '', // 分销人id
|
||||
currentType: { |
||||
modelId: '10001', |
||||
typeId: '20021', |
||||
showName: '多旋翼 - 视距内驾驶员' |
||||
}, |
||||
tabbarList: [] |
||||
}), |
||||
|
||||
actions: { |
||||
login(params) { |
||||
return new Promise(async (resolve, reject) => { |
||||
let newParams = { ...params }; |
||||
if (this.sellManId) { |
||||
newParams = { ...params, distributionId: this.sellManId }; |
||||
} |
||||
const resp = await login(newParams); |
||||
if (resp.code === '0000') { |
||||
// 保存登录信息,用于重新登录
|
||||
this.isLogin = true; |
||||
this.token = resp.data.token; |
||||
this.userInfo = resp.data; |
||||
storage.set('isLogin', true); |
||||
storage.set('token', resp.data.token); |
||||
storage.set('userInfo', resp.data); |
||||
resolve(resp.data); |
||||
} else { |
||||
reject(); |
||||
} |
||||
}); |
||||
}, |
||||
// 登出
|
||||
logout(force = false) { |
||||
return new Promise((resolve, reject) => { |
||||
this.resetUserData(); |
||||
uni.navigateTo({ |
||||
url: '/pages/me/login' |
||||
}); |
||||
resolve(); |
||||
}); |
||||
}, |
||||
//过期登出
|
||||
logoutWithoutToken(force = false) { |
||||
return new Promise((resolve, reject) => { |
||||
this.resetUserData(); |
||||
resolve(); |
||||
}); |
||||
}, |
||||
setSellManId(id) { |
||||
this.sellManId = id; |
||||
this.logout(); |
||||
}, |
||||
// 获取用户信息
|
||||
getUserInfo() { |
||||
getInfo().then(resp => { |
||||
if (resp.code == '0000') { |
||||
this.userInfo = resp.data; |
||||
if (resp.data.driverTypeId && resp.data.modelId) { |
||||
this.currentType = { |
||||
modelId: resp.data.modelId, |
||||
typeId: resp.data.driverTypeId, |
||||
showName: `${resp.data.modelName} - ${resp.data.driverTypeName}` |
||||
}; |
||||
} |
||||
storage.set('userInfo', resp.data); |
||||
} |
||||
}); |
||||
}, |
||||
setUserInfo(info) { |
||||
this.userInfo = info; |
||||
}, |
||||
resetUserData() { |
||||
this.isLogin = false; |
||||
this.token = ''; |
||||
this.userInfo = {}; |
||||
storage.remove('isLogin'); |
||||
storage.remove('token'); |
||||
storage.remove('userInfo'); |
||||
}, |
||||
setType(modelId, typeId, showName) { |
||||
this.currentType = { |
||||
modelId, |
||||
typeId, |
||||
showName |
||||
}; |
||||
}, |
||||
setTabbarList(list) { |
||||
this.tabbarList = list; |
||||
} |
||||
} |
||||
}); |
||||
|
||||
export default useUserStore; |
@ -0,0 +1,45 @@ |
||||
export function numberToChinese(num, isUpper = false) { |
||||
// 检查是否为合法的正整数
|
||||
if (typeof num !== 'number' || num < 0 || !Number.isInteger(num)) { |
||||
throw new Error('请输入非负整数'); |
||||
} |
||||
|
||||
// 中文数字字符集
|
||||
const digits = isUpper ? ['零', '壹', '贰', '叁', '肆', '伍', '陆', '柒', '捌', '玖'] : ['零', '一', '二', '三', '四', '五', '六', '七', '八', '九']; |
||||
|
||||
// 中文单位
|
||||
const units = isUpper ? ['', '拾', '佰', '仟', '万', '拾', '佰', '仟', '亿', '拾', '佰', '仟', '万亿'] : ['', '十', '百', '千', '万', '十', '百', '千', '亿', '十', '百', '千', '万亿']; |
||||
|
||||
// 处理零
|
||||
if (num === 0) return digits[0]; |
||||
|
||||
let chinese = ''; |
||||
let numStr = num.toString(); |
||||
const len = numStr.length; |
||||
|
||||
for (let i = 0; i < len; i++) { |
||||
const digit = parseInt(numStr[i]); |
||||
const position = len - i - 1; // 当前数字的位置
|
||||
|
||||
// 处理零
|
||||
if (digit === 0) { |
||||
// 如果不是最后一位且下一位不是零,添加零
|
||||
if (i < len - 1 && parseInt(numStr[i + 1]) !== 0 && !chinese.endsWith(digits[0])) { |
||||
chinese += digits[0]; |
||||
} |
||||
// 处理万亿、亿、万的单位
|
||||
if (position % 4 === 0 && chinese && !chinese.endsWith(units[position])) { |
||||
chinese += units[position]; |
||||
} |
||||
} else { |
||||
chinese += digits[digit] + units[position]; |
||||
} |
||||
} |
||||
|
||||
// 特殊处理十位数(如11 => 十一,而非一十)
|
||||
if (len === 2 && parseInt(numStr[0]) === 1 && !isUpper) { |
||||
chinese = chinese.substring(1); // 去掉"一十"的"一"
|
||||
} |
||||
|
||||
return chinese; |
||||
} |
@ -0,0 +1,31 @@ |
||||
let timer; |
||||
let flag; |
||||
/** |
||||
* 节流原理:在一定时间内,只能触发一次 |
||||
* |
||||
* @param {Function} func 要执行的回调函数 |
||||
* @param {Number} wait 延时的时间 |
||||
* @param {Boolean} immediate 是否立即执行 |
||||
* @return null |
||||
*/ |
||||
function throttle(func, wait = 500, immediate = true) { |
||||
if (immediate) { |
||||
if (!flag) { |
||||
flag = true; |
||||
// 如果是立即执行,则在wait毫秒内开始时执行
|
||||
typeof func === 'function' && func(); |
||||
timer = setTimeout(() => { |
||||
flag = false; |
||||
}, wait); |
||||
} else { |
||||
} |
||||
} else if (!flag) { |
||||
flag = true; |
||||
// 如果是非立即执行,则在wait毫秒内的结束处执行
|
||||
timer = setTimeout(() => { |
||||
flag = false; |
||||
typeof func === 'function' && func(); |
||||
}, wait); |
||||
} |
||||
} |
||||
export default throttle; |
@ -0,0 +1,167 @@ |
||||
/** |
||||
* 判断url是否是http或https |
||||
* @param {string} path |
||||
* @returns {Boolean} |
||||
*/ |
||||
export function isHttp(url) { |
||||
return url.indexOf('http://') !== -1 || url.indexOf('https://') !== -1; |
||||
} |
||||
|
||||
/** |
||||
* 判断path是否为外链 |
||||
* @param {string} path |
||||
* @returns {Boolean} |
||||
*/ |
||||
export function isExternal(path) { |
||||
return /^(https?:|mailto:|tel:)/.test(path); |
||||
} |
||||
|
||||
/** |
||||
* @param {string} str |
||||
* @returns {Boolean} |
||||
*/ |
||||
export function validUsername(str) { |
||||
const valid_map = ['admin', 'editor']; |
||||
return valid_map.indexOf(str.trim()) >= 0; |
||||
} |
||||
|
||||
/** |
||||
* @param {string} url |
||||
* @returns {Boolean} |
||||
*/ |
||||
export function isURL(url) { |
||||
const reg = |
||||
/^(https?|ftp):\/\/([a-zA-Z0-9.-]+(:[a-zA-Z0-9.&%$-]+)*@)*((25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]?)(\.(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3}|([a-zA-Z0-9-]+\.)*[a-zA-Z0-9-]+\.(com|edu|gov|int|mil|net|org|biz|arpa|info|name|pro|aero|coop|museum|[a-zA-Z]{2}))(:[0-9]+)*(\/($|[a-zA-Z0-9.,?'\\+&%$#=~_-]+))*$/; |
||||
return reg.test(url); |
||||
} |
||||
|
||||
/** |
||||
* @param {string} str |
||||
* @returns {Boolean} |
||||
*/ |
||||
export function validLowerCase(str) { |
||||
const reg = /^[a-z]+$/; |
||||
return reg.test(str); |
||||
} |
||||
|
||||
/** |
||||
* @param {string} str |
||||
* @returns {Boolean} |
||||
*/ |
||||
export function validUpperCase(str) { |
||||
const reg = /^[A-Z]+$/; |
||||
return reg.test(str); |
||||
} |
||||
|
||||
/** |
||||
* @param {string} str |
||||
* @returns {Boolean} |
||||
*/ |
||||
export function validAlphabets(str) { |
||||
const reg = /^[A-Za-z]+$/; |
||||
return reg.test(str); |
||||
} |
||||
|
||||
/** |
||||
* @param {string} email |
||||
* @returns {Boolean} |
||||
*/ |
||||
export function isEmail(email) { |
||||
const reg = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/; |
||||
return reg.test(email); |
||||
} |
||||
|
||||
/** |
||||
* @param {string} str |
||||
* @returns {Boolean} |
||||
*/ |
||||
export function isString(str) { |
||||
if (typeof str === 'string' || str instanceof String) { |
||||
return true; |
||||
} |
||||
return false; |
||||
} |
||||
|
||||
export function isPhone(str) { |
||||
return str && /^1[3456789]\d{9}$/.test(str) |
||||
} |
||||
|
||||
/** |
||||
* @param {Array} arg |
||||
* @returns {Boolean} |
||||
*/ |
||||
export function isArray(arg) { |
||||
if (typeof Array.isArray === 'undefined') { |
||||
return Object.prototype.toString.call(arg) === '[object Array]'; |
||||
} |
||||
return Array.isArray(arg); |
||||
} |
||||
|
||||
// 是否纯英文
|
||||
export function isAllEN(val) { |
||||
return /^[a-zA-Z]*$/.test(val); |
||||
} |
||||
|
||||
// 是否纯中文
|
||||
export function isAllCN(val) { |
||||
return /^[\u4E00-\u9FA5]*$/.test(val); |
||||
} |
||||
|
||||
// 校验手机号
|
||||
export function validPhone(rule, value, callback) { |
||||
if (value && !/^1[3456789]\d{9}$/.test(value)) { |
||||
return callback(new Error('请输入正确的11位号码')); |
||||
} else { |
||||
return callback(); |
||||
} |
||||
} |
||||
|
||||
// 校验固话和手机号
|
||||
export function validPhoneAndMobile(rule, value, callback) { |
||||
if (value && !/^((0\d{2,3}-?\d{7,8})|(1[3465789]\d{9}))$/.test(value)) { |
||||
return callback(new Error('请输入正确的电话号码')); |
||||
} else { |
||||
return callback(); |
||||
} |
||||
} |
||||
|
||||
// 校验邮箱
|
||||
export function validEmail(rule, value, callback) { |
||||
if (value && !isEmail(value)) { |
||||
return callback(new Error('请输入正确的邮箱')); |
||||
} else { |
||||
return callback(); |
||||
} |
||||
} |
||||
|
||||
// 校验纳税人识别号
|
||||
export function validTaxpayer(rule, value, callback) { |
||||
if (value && !/^[A-Z0-9]{15}$|^[A-Z0-9]{18}$|^[A-Z0-9]{20}$/.test(value)) { |
||||
return callback(new Error('请输入正确的纳税人识别号')); |
||||
} else { |
||||
return callback(); |
||||
} |
||||
} |
||||
|
||||
// 校验是否网站
|
||||
export function validUrl(rule, value, callback) { |
||||
if (value && !isURL(value)) { |
||||
return callback(new Error('请输入正确的网站')); |
||||
} else { |
||||
return callback(); |
||||
} |
||||
} |
||||
|
||||
// 校验银行卡
|
||||
export function validBankCard(rule, value, callback) { |
||||
const strBin = '10,18,30,35,37,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,58,60,62,65,68,69,84,87,88,94,95,98,99'; |
||||
if (!value) { |
||||
return callback(); |
||||
} else if (!Number.isInteger(+value)) { |
||||
callback(new Error('银行卡号必须全为数字')); |
||||
} else if (value.trim().length < 8 || value.trim().length > 32) { |
||||
callback(new Error('银行卡号长度必须在8到32之间')); |
||||
} else { |
||||
callback(); |
||||
} |
||||
} |
@ -0,0 +1,171 @@ |
||||
// var jweixin = require("jweixin-module");
|
||||
|
||||
import * as jweixin from 'jweixin-module'; |
||||
import http from '@/jtools/request/index'; |
||||
import $platform from '@/jtools/platform'; |
||||
export default { |
||||
//判断是否在微信中
|
||||
isWechat() { |
||||
var ua = window.navigator.userAgent.toLowerCase(); |
||||
if (ua.match(/micromessenger/i) == 'micromessenger') { |
||||
return true; |
||||
} else { |
||||
return false; |
||||
} |
||||
}, |
||||
// 鉴权页面
|
||||
initJssdk(callback) { |
||||
http('common.wxJssdk', { |
||||
uri: encodeURIComponent($platform.entry()) |
||||
}).then(res => { |
||||
jweixin.config({ |
||||
debug: res.data.debug, |
||||
appId: res.data.appId, |
||||
timestamp: res.data.timestamp, |
||||
nonceStr: res.data.nonceStr, |
||||
signature: res.data.signature, |
||||
jsApiList: res.data.jsApiList, |
||||
openTagList: res.data.openTagList |
||||
}); |
||||
if (callback) { |
||||
callback(res.data); |
||||
} |
||||
}); |
||||
}, |
||||
|
||||
//在需要定位页面调用
|
||||
getLocation(callback) { |
||||
this.isWechat() && |
||||
this.initJssdk(function (res) { |
||||
jweixin.ready(function () { |
||||
jweixin.getLocation({ |
||||
type: 'gcj02', // 默认为wgs84的gps坐标,如果要返回直接给openLocation用的火星坐标,可传入'gcj02'
|
||||
success: function (res) { |
||||
callback(res); |
||||
}, |
||||
fail: function (res) { |
||||
console.log('%c微信H5sdk,getLocation失败:', 'color:green;background:yellow'); |
||||
} |
||||
}); |
||||
}); |
||||
}); |
||||
}, |
||||
|
||||
//获取微信收货地址
|
||||
openAddress(callback) { |
||||
this.isWechat() && |
||||
this.initJssdk(function (res) { |
||||
jweixin.ready(function () { |
||||
jweixin.openAddress({ |
||||
success: function (res) { |
||||
callback(res); |
||||
}, |
||||
fail: function (err) { |
||||
console.log('%c微信H5sdk,openAddress失败:', 'color:green;background:yellow'); |
||||
}, |
||||
complete: function (msg) {} |
||||
}); |
||||
}); |
||||
}); |
||||
}, |
||||
|
||||
// 微信扫码
|
||||
scanQRCode(callback) { |
||||
this.isWechat() && |
||||
this.initJssdk(function (res) { |
||||
jweixin.ready(function () { |
||||
jweixin.scanQRCode({ |
||||
needResult: 1, // 默认为0,扫描结果由微信处理,1则直接返回扫描结果,
|
||||
scanType: ['qrCode', 'barCode'], // 可以指定扫二维码还是一维码,默认二者都有
|
||||
success: function (res) { |
||||
callback(res); |
||||
}, |
||||
fail: function (res) { |
||||
console.log('%c微信H5sdk,scanQRCode失败:', 'color:green;background:yellow'); |
||||
} |
||||
}); |
||||
}); |
||||
}); |
||||
}, |
||||
|
||||
// 微信分享
|
||||
share(data, callback) { |
||||
this.isWechat() && |
||||
this.initJssdk(function (res) { |
||||
jweixin.ready(function () { |
||||
var shareData = { |
||||
title: data.title, |
||||
desc: data.desc, |
||||
link: data.path, |
||||
imgUrl: data.image, |
||||
success: function (res) { |
||||
callback(res); |
||||
// 分享后的一些操作,比如分享统计等等
|
||||
}, |
||||
cancel: function (res) {} |
||||
}; |
||||
|
||||
jweixin.updateAppMessageShareData(shareData); //新版接口
|
||||
//分享到朋友圈接口
|
||||
// jweixin.updateTimelineShareData(shareData);
|
||||
}); |
||||
}); |
||||
}, |
||||
|
||||
// 打开坐标位置
|
||||
openLocation(data, callback) { |
||||
//打开位置
|
||||
this.isWechat() && |
||||
this.initJssdk(function (res) { |
||||
jweixin.ready(function () { |
||||
jweixin.openLocation({ |
||||
//根据传入的坐标打开地图
|
||||
latitude: data.latitude, |
||||
longitude: data.longitude |
||||
}); |
||||
}); |
||||
}); |
||||
}, |
||||
// 选择图片
|
||||
chooseImage(callback) { |
||||
//选择图片
|
||||
this.isWechat() && |
||||
this.initJssdk(function (res) { |
||||
jweixin.ready(function () { |
||||
jweixin.chooseImage({ |
||||
count: 1, |
||||
sizeType: ['compressed'], |
||||
sourceType: ['album'], |
||||
success: function (rs) { |
||||
callback(rs); |
||||
} |
||||
}); |
||||
}); |
||||
}); |
||||
}, |
||||
|
||||
//微信支付
|
||||
wxpay(data, callback) { |
||||
let that = this; |
||||
this.isWechat() && |
||||
this.initJssdk(function (res) { |
||||
jweixin.ready(function () { |
||||
jweixin.chooseWXPay({ |
||||
timestamp: data.timeStamp, // 支付签名时间戳,注意微信jssdk中的所有使用timestamp字段均为小写。但最新版的支付后台生成签名使用的timeStamp字段名需大写其中的S字符
|
||||
nonceStr: data.nonceStr, // 支付签名随机串,不长于 32 位
|
||||
package: data.package, // 统一支付接口返回的prepay_id参数值,提交格式如:prepay_id=\*\*\*)
|
||||
signType: data.signType, // 签名方式,默认为'SHA1',使用新版支付需传入'MD5'
|
||||
paySign: data.paySign, // 支付签名
|
||||
success: function (res) { |
||||
callback(res); |
||||
}, |
||||
fail: function (res) { |
||||
console.log('%c微信H5sdk,chooseWXPay失败:', 'color:green;background:yellow'); |
||||
callback(res); |
||||
}, |
||||
cancel: function (res) {} |
||||
}); |
||||
}); |
||||
}); |
||||
} |
||||
}; |
@ -0,0 +1,261 @@ |
||||
/** |
||||
* Wechat v1.1.0 |
||||
* @Class Wechat |
||||
* @description jtools-wechat 1.1.0 wehcat第三方登录组件 |
||||
* @Author lidongtony |
||||
* @Date 2020-05-20 |
||||
* @Email lidongtony@qq.com |
||||
*/ |
||||
import api from "@/jtools/request/index"; |
||||
import $platform from "@/jtools/platform"; |
||||
import store from "@/jtools/store"; |
||||
import { |
||||
API_URL |
||||
} from "@/env"; |
||||
|
||||
export default { |
||||
eventMap(event) { |
||||
let map = ""; |
||||
switch (event) { |
||||
case "login": |
||||
map = "登录中..."; |
||||
break; |
||||
case "refresh": |
||||
map = "更新中..."; |
||||
break; |
||||
case "bind": |
||||
map = "绑定中..."; |
||||
break; |
||||
} |
||||
return map; |
||||
}, |
||||
|
||||
async login() { |
||||
let token = ""; |
||||
// #ifdef MP-WEIXIN
|
||||
token = await this.wxMiniProgramOauth("login"); |
||||
return token; |
||||
// #endif
|
||||
// #ifdef H5
|
||||
this.wxOfficialAccountOauth("login"); |
||||
// #endif
|
||||
// #ifdef APP-PLUS
|
||||
token = await this.wxOpenPlatformOauth("login"); |
||||
return token; |
||||
// #endif
|
||||
}, |
||||
async refresh() { |
||||
let token = ""; |
||||
// #ifdef MP-WEIXIN
|
||||
token = await this.wxMiniProgramOauth("refresh"); |
||||
return token; |
||||
// #endif
|
||||
// #ifdef H5
|
||||
this.wxOfficialAccountOauth("refresh"); |
||||
// #endif
|
||||
// #ifdef APP-PLUS
|
||||
token = await this.wxOpenPlatformOauth("refresh"); |
||||
return token; |
||||
// #endif
|
||||
}, |
||||
async bind() { |
||||
let token = ""; |
||||
// #ifdef MP-WEIXIN
|
||||
token = await this.wxMiniProgramOauth("bind"); |
||||
return token; |
||||
// #endif
|
||||
// #ifdef H5
|
||||
this.wxOfficialAccountOauth("bind"); |
||||
// #endif
|
||||
// #ifdef APP-PLUS
|
||||
token = await this.wxOpenPlatformOauth("bind"); |
||||
return token; |
||||
// #endif
|
||||
}, |
||||
|
||||
// #ifdef H5
|
||||
// 微信公众号网页登录&刷新头像昵称&绑定
|
||||
wxOfficialAccountOauth(event = "login") { |
||||
if ($platform.get() !== "wxOfficialAccount") { |
||||
uni.showToast({ |
||||
title: "请在微信浏览器中打开", |
||||
icon: "none" |
||||
}); |
||||
throw false; |
||||
} |
||||
let host = $platform.host(); |
||||
let payloadObject = { |
||||
host: host, |
||||
event, |
||||
token: (event !== "login" && store.getters.isLogin) ? uni.getStorageSync("token") : "" |
||||
}; |
||||
let payload = encodeURIComponent(JSON.stringify(payloadObject)); |
||||
let redirect_uri = encodeURIComponent(`${API_URL}user/wxOfficialAccountOauth?payload=${payload}`); |
||||
let oauthUrl = "https://open.weixin.qq.com/connect/oauth2/authorize?appid=" + store.getters.initWechat.appid + |
||||
`&redirect_uri=${redirect_uri}&response_type=code&scope=snsapi_userinfo&state=1`; |
||||
uni.setStorageSync("lastPage", window.location.href); |
||||
window.location = oauthUrl; |
||||
}, |
||||
|
||||
// 微信公众号网页静默登录:临时登录获取OpenId 不入库不绑定用户
|
||||
wxOfficialAccountBaseLogin() { |
||||
let state = encodeURIComponent(window.location.href); |
||||
window.location = "https://open.weixin.qq.com/connect/oauth2/authorize?appid=" + store.getters.initWechat.appid + |
||||
`&redirect_uri=${API_URL}user/wxOfficialAccountBaseLogin&response_type=code&scope=snsapi_base&state=${state}`; |
||||
throw "stop"; |
||||
}, |
||||
// #endif
|
||||
|
||||
// #ifdef APP-PLUS
|
||||
// 微信开放平台登录
|
||||
wxOpenPlatformOauth(event = "login") { |
||||
let that = this; |
||||
return new Promise((resolve, reject) => { |
||||
uni.login({ |
||||
provider: "weixin", |
||||
success: function(loginRes) { |
||||
if (loginRes.errMsg === "login:ok") { |
||||
let authResult = loginRes.authResult; |
||||
api("user.wxOpenPlatformOauth", { |
||||
authResult, |
||||
event |
||||
}, that.eventMap(event)).then(res => { |
||||
if (res.code === 1) { |
||||
resolve(res.data.token); |
||||
} else { |
||||
resolve(false); |
||||
} |
||||
}); |
||||
} |
||||
}, |
||||
fail: function(res) { |
||||
uni.showToast({ |
||||
title: "登录失败,请稍后再试" |
||||
}); |
||||
resolve(false); |
||||
api("common.debug", { |
||||
info: res |
||||
}); |
||||
}, |
||||
complete: function(res) {} |
||||
}); |
||||
}); |
||||
}, |
||||
// #endif
|
||||
|
||||
// #ifdef MP-WEIXIN
|
||||
// 微信小程序静默登录
|
||||
async getWxMiniProgramSessionKey(autoLogin = true) { |
||||
let sessionStatus = false; |
||||
let session_key = ""; |
||||
return new Promise((resolve, reject) => { |
||||
uni.checkSession({ |
||||
success(res) { |
||||
if (res.errMsg === "checkSession:ok") sessionStatus = true; |
||||
}, |
||||
complete() { |
||||
if (uni.getStorageSync("session_key") && sessionStatus && !autoLogin) { |
||||
resolve(uni.getStorageSync("session_key")); |
||||
} else { |
||||
uni.login({ |
||||
success: function(info) { |
||||
let code = info.code; |
||||
api("user.getWxMiniProgramSessionKey", { |
||||
code: code, |
||||
autoLogin: autoLogin |
||||
}).then(res => { |
||||
if (res.code === 1) { |
||||
uni.setStorageSync("session_key", res |
||||
.data.session_key); |
||||
if (autoLogin) { |
||||
if (res.data.token) { |
||||
resolve(res.data.token); |
||||
} else { |
||||
resolve(false); |
||||
} |
||||
} |
||||
resolve(res.data.session_key); |
||||
} else { |
||||
reject(res.msg); |
||||
} |
||||
}); |
||||
} |
||||
}); |
||||
} |
||||
} |
||||
}); |
||||
}); |
||||
}, |
||||
|
||||
// 微信小程序获取用户信息登录
|
||||
wxMiniProgramOauth(event = "login") { |
||||
let that = this; |
||||
let session_key = uni.getStorageSync("session_key"); |
||||
uni.showLoading({ |
||||
title: that.eventMap(event) |
||||
}); |
||||
return new Promise((resolve, reject) => { |
||||
uni.getUserProfile({ // 必须手动确认触发
|
||||
desc: "完善会员资料", // 声明获取用户个人信息后的用途,后续会展示在弹窗中,请谨慎填写
|
||||
success: res => { |
||||
if (res.errMsg === "getUserProfile:ok") { |
||||
api("user.wxMiniProgramOauth", { |
||||
event, |
||||
session_key, |
||||
encryptedData: res.encryptedData, |
||||
iv: res.iv, |
||||
signature: res.signature, |
||||
}).then(res => { |
||||
console.log(res) |
||||
if (res.code === 1) { |
||||
resolve(res.data.token); |
||||
} else { |
||||
uni.removeStorageSync("session_key"); |
||||
that.getWxMiniProgramSessionKey(false); |
||||
resolve(false); |
||||
} |
||||
}); |
||||
} |
||||
}, |
||||
complete: res => { |
||||
uni.hideLoading(); |
||||
} |
||||
}); |
||||
}); |
||||
|
||||
}, |
||||
|
||||
// 小程序更新
|
||||
checkMiniProgramUpdate() { |
||||
if (uni.canIUse("getUpdateManager")) { |
||||
const updateManager = uni.getUpdateManager(); |
||||
updateManager.onCheckForUpdate(function(res) { |
||||
// 请求完新版本信息的回调
|
||||
if (res.hasUpdate) { |
||||
updateManager.onUpdateReady(function() { |
||||
uni.showModal({ |
||||
title: "更新提示", |
||||
content: "新版本已经准备好,是否重启应用?", |
||||
success: function(res) { |
||||
if (res.confirm) { |
||||
// 新的版本已经下载好,调用 applyUpdate 应用新版本并重启
|
||||
updateManager.applyUpdate(); |
||||
} |
||||
} |
||||
}); |
||||
}); |
||||
updateManager.onUpdateFailed(function() { |
||||
// 新的版本下载失败
|
||||
uni.showModal({ |
||||
title: "已经有新版本了哟~", |
||||
content: "新版本已经上线啦~,请您删除当前小程序,重新搜索打开哟~" |
||||
}); |
||||
}); |
||||
} |
||||
}); |
||||
} |
||||
}, |
||||
// #endif
|
||||
|
||||
|
||||
}; |
@ -0,0 +1,21 @@ |
||||
import { createSSRApp } from 'vue'; |
||||
import uviewPlus from './uni_modules/uview-plus'; |
||||
import platform from '@/jtools/platform'; |
||||
import constants from '@/jtools/constants'; |
||||
import storage from '@/jtools/storage'; |
||||
import * as Pinia from 'pinia'; |
||||
import App from './App.vue'; |
||||
import mpShare from '@/uni_modules/uview-plus/libs/mixin/mpShare.js'; |
||||
export function createApp() { |
||||
const app = createSSRApp(App); |
||||
app.config.globalProperties.$platform = platform; |
||||
app.config.globalProperties.$constants = constants; |
||||
app.config.globalProperties.$storage = storage; |
||||
app.use(uviewPlus); |
||||
app.use(Pinia.createPinia()); |
||||
app.mixin(mpShare); |
||||
return { |
||||
app, |
||||
Pinia |
||||
}; |
||||
} |
@ -0,0 +1,80 @@ |
||||
{ |
||||
"name": "寻驾-无人机", |
||||
"appid": "__UNI__59447F7", |
||||
"description": "", |
||||
"versionName": "1.0.2", |
||||
"versionCode": "100", |
||||
"transformPx": false, |
||||
"app-plus": { |
||||
"usingComponents": true, |
||||
"nvueStyleCompiler": "uni-app", |
||||
"compilerVersion": 3, |
||||
"splashscreen": { |
||||
"alwaysShowBeforeRender": true, |
||||
"waiting": true, |
||||
"autoclose": true, |
||||
"delay": 0 |
||||
}, |
||||
"modules": {}, |
||||
"distribute": { |
||||
"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.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.ACCESS_NETWORK_STATE\"/>", |
||||
"<uses-permission android:name=\"android.permission.CAMERA\"/>", |
||||
"<uses-permission android:name=\"android.permission.GET_ACCOUNTS\"/>", |
||||
"<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.FLASHLIGHT\"/>", |
||||
"<uses-feature android:name=\"android.hardware.camera\"/>", |
||||
"<uses-permission android:name=\"android.permission.WRITE_SETTINGS\"/>" |
||||
] |
||||
}, |
||||
"ios": {}, |
||||
"sdkConfigs": {} |
||||
} |
||||
}, |
||||
"quickapp": {}, |
||||
"mp-weixin": { |
||||
"appid": "wx0668c6fabb1a9c44", |
||||
"setting": { |
||||
"urlCheck": true, |
||||
"minified": true, |
||||
"es6": true, |
||||
"postcss": true |
||||
}, |
||||
"usingComponents": true, |
||||
"permission": { |
||||
"scope.userLocation": { |
||||
"desc": "根据城市获取不同题库" |
||||
} |
||||
} |
||||
}, |
||||
"mp-alipay": { |
||||
"usingComponents": true |
||||
}, |
||||
"mp-baidu": { |
||||
"usingComponents": true |
||||
}, |
||||
"mp-toutiao": { |
||||
"usingComponents": true, |
||||
"appid": "ttbbd1cd6c24e1c00801", |
||||
"setting": { |
||||
"es6": true, |
||||
"postcss": true, |
||||
"minified": true |
||||
} |
||||
}, |
||||
"uniStatistics": { |
||||
"enable": false |
||||
}, |
||||
"vueVersion": "3", |
||||
"fallbackLocale": "zh-Hans", |
||||
"locale": "zh-Hans" |
||||
} |
@ -0,0 +1,18 @@ |
||||
{ |
||||
"id": "yan-qr", |
||||
"name": "动态生成二维码", |
||||
"displayName": "动态生成二维码", |
||||
"version": "1.0.0", |
||||
"description": "动态生成二维码", |
||||
"keywords": [ |
||||
"二维码", |
||||
"生成二维码", |
||||
"动态二维码" |
||||
], |
||||
"dcloudext": { |
||||
"category": [ |
||||
"前端组件", |
||||
"通用组件" |
||||
] |
||||
} |
||||
} |
@ -0,0 +1,98 @@ |
||||
{ |
||||
"easycom": { |
||||
"^u-(.*)": "uview-plus/components/u-$1/u-$1.vue" |
||||
}, |
||||
"pages": [ |
||||
{ |
||||
"path": "pages/course/index", |
||||
"style": { |
||||
"navigationStyle": "custom" |
||||
} |
||||
}, |
||||
{ |
||||
"path": "pages/index/index", |
||||
"style": { |
||||
"navigationStyle": "custom" |
||||
} |
||||
}, |
||||
{ |
||||
"path": "pages/choseCity/choseCity", |
||||
"style": { |
||||
"navigationStyle": "custom" |
||||
} |
||||
}, |
||||
{ |
||||
"path": "pages/me/index", |
||||
"style": { |
||||
"navigationStyle": "custom" |
||||
} |
||||
}, |
||||
{ |
||||
"path": "pages/course/chapter", |
||||
"style": { |
||||
"navigationBarTitleText": "章节" |
||||
} |
||||
}, |
||||
{ |
||||
"path": "pages/course/detail", |
||||
"style": { |
||||
"navigationBarTitleText": "课程详情" |
||||
} |
||||
}, |
||||
{ |
||||
"path": "pages/me/userInfo", |
||||
"style": { |
||||
"navigationBarTitleText": "个人信息" |
||||
} |
||||
}, |
||||
{ |
||||
"path": "pages/me/good", |
||||
"style": { |
||||
"navigationBarTitleText": "我的点赞" |
||||
} |
||||
}, |
||||
{ |
||||
"path": "pages/me/like", |
||||
"style": { |
||||
"navigationBarTitleText": "我的收藏" |
||||
} |
||||
}, |
||||
{ |
||||
"path": "pages/me/look", |
||||
"style": { |
||||
"navigationBarTitleText": "我的关注" |
||||
} |
||||
}, |
||||
{ |
||||
"path": "pages/me/login", |
||||
"style": { |
||||
"navigationBarTitleText": "登录" |
||||
} |
||||
} |
||||
], |
||||
"globalStyle": { |
||||
"navigationBarTextStyle": "black", |
||||
"navigationBarTitleText": "寻驾-无人机", |
||||
"navigationBarBackgroundColor": "#FFF", |
||||
"backgroundColor": "#FFF" |
||||
}, |
||||
"tabBar": { |
||||
"color": "#333", |
||||
"selectedColor": "#18AFFF", |
||||
"backgroundColor": "#FFF", |
||||
"list": [ |
||||
{ |
||||
"pagePath": "pages/course/index", |
||||
"text": "课程", |
||||
"iconPath": "static/image/tabbar/tab-book.png", |
||||
"selectedIconPath": "static/image/tabbar/tab-book-selected.png" |
||||
}, |
||||
{ |
||||
"pagePath": "pages/me/index", |
||||
"text": "我的", |
||||
"iconPath": "static/image/tabbar/tab-mine.png", |
||||
"selectedIconPath": "static/image/tabbar/tab-mine-selected.png" |
||||
} |
||||
] |
||||
} |
||||
} |
@ -0,0 +1,33 @@ |
||||
<template> |
||||
<view> |
||||
<chose-city @selectCity="selectCity" v-if="showCity" @closeModal="closeModal"></chose-city> |
||||
</view> |
||||
</template> |
||||
|
||||
<script> |
||||
import choseCity from "@/components/chose-city/chose-city" |
||||
export default { |
||||
components: { |
||||
choseCity |
||||
}, |
||||
data() { |
||||
return { |
||||
showCity:true |
||||
} |
||||
}, |
||||
methods: { |
||||
selectCity(item) { |
||||
uni.setStorageSync('city', item.name) |
||||
uni.navigateBack() |
||||
// this.showCity = false |
||||
}, |
||||
closeModal() { |
||||
this.showCity = false |
||||
}, |
||||
} |
||||
} |
||||
</script> |
||||
|
||||
<style> |
||||
|
||||
</style> |
@ -0,0 +1,72 @@ |
||||
<template> |
||||
<view class="p15"> |
||||
<view class="chapter_item" v-for="(item, index) of chapterList" :key="index" @tap="toDetail(item)"> |
||||
<view style="line-height: 20px;"> |
||||
<text class="j-tag" style="background: #DDEEFF;color: #1A8CFE">第{{ String(index+1).padStart(2,'0') }}讲·庄子</text> |
||||
<text class="fs14 ml5 ">阴极阳转,阳转阴转,实现生命永恒的自然轮转</text> |
||||
</view> |
||||
<view class="mt10 flex ai-c jc-sb fs12 mt8 cor-999"> |
||||
<text>郭老师</text> |
||||
<text>2020-01-01 19:00</text> |
||||
<view class="flex ai-c"> |
||||
<u-icon name="eye" color="#999" size="14" :label="index*7" label-color="#999" label-size="12"></u-icon> |
||||
<u-icon class="ml20" name="thumb-up" color="#999" size="14" :label="index*3" label-color="#999" label-size="12"></u-icon> |
||||
</view> |
||||
</view> |
||||
</view> |
||||
</view> |
||||
</template> |
||||
|
||||
<script> |
||||
// import { getChapterDoneList } from '@/jtools/api/index' |
||||
|
||||
export default { |
||||
data() { |
||||
return { |
||||
chapterList:[], |
||||
} |
||||
}, |
||||
onLoad(){ |
||||
this.getChapterList() |
||||
}, |
||||
methods:{ |
||||
getChapterList(){ |
||||
this.chapterList = [1,2,3] |
||||
// getChapterDoneList({driverTypeId}).then(resp=>{ |
||||
// if(resp.code==='0000'){ |
||||
// this.chapterList=resp.data |
||||
// } |
||||
// }) |
||||
}, |
||||
toDetail(chapter){ |
||||
uni.navigateTo({ |
||||
url: `/pages/course/detail?id=${chapter.id}` |
||||
}); |
||||
}, |
||||
} |
||||
} |
||||
</script> |
||||
|
||||
<style lang="scss" scoped> |
||||
.chapter_item { |
||||
padding: 10px; |
||||
margin-bottom: 10px; |
||||
border-radius: 5px; |
||||
background-color: #fff; |
||||
} |
||||
.chapter_item:hover { |
||||
background-color: rgb(210, 209, 214); |
||||
} |
||||
|
||||
.j-tag { |
||||
// display: inline-flex; |
||||
// align-items: center; |
||||
// justify-content: center; |
||||
padding: 1px 3px; |
||||
// height: 16px; |
||||
border-radius: 3px; |
||||
font-size: 12px; |
||||
line-height: 14px; |
||||
color: #fff; |
||||
} |
||||
</style> |
File diff suppressed because one or more lines are too long
@ -0,0 +1,80 @@ |
||||
<template> |
||||
<view class="wp100 hp100"> |
||||
<view class="p5" style="background-color: #fff;"> |
||||
<u-search v-model="queryParams.placeName" placeholder="搜索标题/作者" :showAction="false" |
||||
@search="handleSearch">搜索</u-search> |
||||
</view> |
||||
<u-list v-if="pageList.length > 0" @scrolltolower="scrolltolower" class="course-list"> |
||||
<u-list-item v-for="(item, index) in pageList" :key="index"> |
||||
<view class="flex ai-c jc-sb p10lr p5tb bc-fff" @click="handleClick(item)"> |
||||
<view class="flex ai-c"> |
||||
<image src="https://ss-cloud.ahduima.com/wrj/file/1949715991365947392.jpg" mode="aspectFill" style="width: 160px;height: 100px;border-radius: 6px;" /> |
||||
</view> |
||||
<view class="flex-1 ml10 overflow-h"> |
||||
<view class="fs14">课程标题 {{ index + 1 }}</view> |
||||
<view class="fs13 mt8 cor-999 text-ellipsis">课程简介内容,简要描述课程内容和目标。</view> |
||||
<view class="flex ai-c jc-sb fs12 mt8 cor-999"> |
||||
<u-icon name="eye" color="#999" size="14" :label="index*7" label-color="#999" label-size="12"></u-icon> |
||||
<u-icon name="thumb-up" color="#999" size="14" :label="index*3" label-color="#999" label-size="12"></u-icon> |
||||
<text>2020-01-01 19:00</text> |
||||
</view> |
||||
</view> |
||||
</view> |
||||
</u-list-item> |
||||
</u-list> |
||||
<u-empty v-else mode="list" text="暂无数据"></u-empty> |
||||
</view> |
||||
</template> |
||||
|
||||
<script> |
||||
export default { |
||||
data() { |
||||
return { |
||||
pageList: [], |
||||
total: 0, |
||||
queryParams: { |
||||
placeName: '', |
||||
pageNo: 1, |
||||
pageSize: 20 |
||||
} |
||||
} |
||||
}, |
||||
mounted() { |
||||
this.handleSearch() |
||||
}, |
||||
methods: { |
||||
scrolltolower() { |
||||
if (this.pageList.length < this.total) { |
||||
this.queryParams.pageNo++ |
||||
this.getPageList() |
||||
} |
||||
}, |
||||
handleSearch() { |
||||
this.pageList = [] |
||||
this.queryParams.pageNo = 1 |
||||
this.getPageList() |
||||
}, |
||||
getPageList() { |
||||
this.pageList = [1,2,3] |
||||
this.total = 3 |
||||
// const _this = this |
||||
// const params = { ...this.queryParams } |
||||
// queryExamPoint(params).then(res => { |
||||
// _this.pageList = [..._this.pageList, ...res.data.records] |
||||
// _this.total = res.data.total |
||||
// }); |
||||
}, |
||||
handleClick(item) { |
||||
uni.navigateTo({ |
||||
url: `/pages/course/chapter` |
||||
}); |
||||
} |
||||
} |
||||
} |
||||
</script> |
||||
|
||||
<style lang="scss" scoped> |
||||
.course-list { |
||||
background-color: #fff; |
||||
} |
||||
</style> |
@ -0,0 +1,151 @@ |
||||
<template> |
||||
<view> |
||||
<!-- 用j-navbar 组件实现导航栏 --> |
||||
<j-navbar :isBack="false" :background="{ background: '#1A8CFE' }" :extraHeight="42"> |
||||
<template #left> |
||||
<view class="cor-fff"> |
||||
<view class="navbar-left"> |
||||
<text class="ml10 fs16">{{ title }}</text> |
||||
<text class="ml10 fs12">无人机驾考平台</text> |
||||
</view> |
||||
<view class="mt10 p5tb p15lr" style="width: 100vw"> |
||||
<u-search v-model="searchValue" placeholder="搜索培训机构" :showAction="false" disabled @click="next('/pages/index/search', false)">搜索</u-search> |
||||
</view> |
||||
</view> |
||||
</template> |
||||
</j-navbar> |
||||
<view class="container" style="background: #1a8cfe"> |
||||
<view class="p15tb" style="background: #1a8cfe"> |
||||
<view class="flex ai-c"> |
||||
<view class="text-center" style="width: 30%" @click="next('/pages/index/testRoom', true)"> |
||||
<text class="custom-icon custom-icon-kaodian fs28 cor-fff"></text> |
||||
<view class="mt2 cor-fff fs12">CAAC考点</view> |
||||
</view> |
||||
<view class="text-center" style="width: 30%" @click="next('/pages/index/testCalendar', true)"> |
||||
<text class="custom-icon custom-icon-kaoshishijian fs28 cor-fff"></text> |
||||
<view class="mt2 cor-fff fs12">CAAC考试时间</view> |
||||
</view> |
||||
</view> |
||||
</view> |
||||
<view class="mt5 p15 bc-fff" style="border-radius: 16px 16px 0 0"> |
||||
<!-- 入驻 --> |
||||
<view class="flex jc-c ai-c"> |
||||
<view class="fl1 br10" style="background: linear-gradient(to bottom, #0478d6, #01e2f3)"> |
||||
<view class="flex jc-c ai-c p10" @tap="next('/pages/index/registerStation', true)"> |
||||
<view class="fl1"> |
||||
<view class="fs18 cor-fff">机构入驻</view> |
||||
<view class="mt12 fs12 bc-fff text-center br9" style="width: 68px; height: 18px; line-height: 18px; color: #0478d6">立即申请</view> |
||||
</view> |
||||
<image src="@/static/image/index/wrj1.png" style="width: 64px; height: 64px" /> |
||||
</view> |
||||
</view> |
||||
<view class="fl1 br10 ml10" style="background: linear-gradient(to bottom, #e78728, #f2a547)"> |
||||
<view class="flex jc-c ai-c p10" @tap="next('/pages/index/registerCoach', true)"> |
||||
<view class="fl1"> |
||||
<view class="fs18 cor-fff">教员入驻</view> |
||||
<view class="mt12 fs12 bc-fff text-center br9" style="width: 68px; height: 18px; line-height: 18px; color: #e78728">立即申请</view> |
||||
</view> |
||||
<image src="@/static/image/index/wrj2.png" style="width: 64px; height: 64px" /> |
||||
</view> |
||||
</view> |
||||
</view> |
||||
<!-- 找驾校 --> |
||||
<view class="br10 mt10" style="background: linear-gradient(to bottom, #7783e4, #8ebfff)" @tap="next('/pages/index/consult', true)"> |
||||
<view class="flex jc-c ai-c p10" style="height: 84px"> |
||||
<view class="fl1"> |
||||
<view class="fs24 cor-fff fw600">为您甄选优质驾校</view> |
||||
<view class="fs14 mt5 cor-fff">离家近 价格低 口碑好 有折扣</view> |
||||
</view> |
||||
<view class="fs16 bc-fff text-center br14 p5lr" style="height: 28px; line-height: 28px; color: #7783e4">帮我找驾校</view> |
||||
</view> |
||||
</view> |
||||
<!-- 驾校列表 --> |
||||
<view class="mt10"> |
||||
<u-sticky offsetTop="120"> |
||||
<view class="p10tb flex jc-sb ai-c bc-fff"> |
||||
<view class="fs15 fw600">无人机驾校</view> |
||||
<view class="flex fs12 cor-333" @click="next('/pages/choseCity/choseCity', false)"> |
||||
<text class="mr5">{{ queryParams.address || '全部城市' }}</text> |
||||
<u-icon name="arrow-down" /> |
||||
</view> |
||||
</view> |
||||
</u-sticky> |
||||
<u-list @scrolltolower="scrolltolower" height="calc(100vh - 120px)"> |
||||
<u-list-item v-for="(item, index) in pageList" :key="index"> |
||||
<j-station :info="item" /> |
||||
</u-list-item> |
||||
</u-list> |
||||
</view> |
||||
</view> |
||||
</view> |
||||
<u-tabbar :value="tabIndex" @change="name => changeTab(name)"> |
||||
<u-tabbar-item v-for="(item, index) in tabbarList" :key="index" :text="item.text" :icon="item.icon" :name="item.name"></u-tabbar-item> |
||||
</u-tabbar> |
||||
</view> |
||||
</template> |
||||
<script> |
||||
import { getStationList } from '@/jtools/api/station'; |
||||
import { mapState } from 'pinia'; //引入映射函数 |
||||
import useUserStore from '@/jtools/store/user'; //引入store |
||||
|
||||
export default { |
||||
computed: { |
||||
...mapState(useUserStore, ['tabbarList']) |
||||
}, |
||||
data() { |
||||
return { |
||||
searchValue: '', |
||||
title: import.meta.env.VITE_APP_TITLE || '首页', |
||||
queryParams: { |
||||
address: '', |
||||
pageNo: 1, |
||||
pageSize: 20 |
||||
}, |
||||
total: 0, |
||||
pageList: [], |
||||
tabIndex: '/pages/index/index', |
||||
}; |
||||
}, |
||||
onShow() { |
||||
this.queryParams.address = uni.getStorageSync('city'); |
||||
this.pageList = []; |
||||
this.queryParams.pageNo = 1; |
||||
this.getPageList(); |
||||
}, |
||||
methods: { |
||||
getPageList() { |
||||
const _this = this; |
||||
const params = { ...this.queryParams }; |
||||
getStationList(params).then(res => { |
||||
_this.pageList = [..._this.pageList, ...res.data.records]; |
||||
_this.total = res.data.total; |
||||
}); |
||||
}, |
||||
next(url, needLogin = false) { |
||||
if(needLogin && !useUserStore().isLogin) { |
||||
uni.showToast({title: '请先登录', icon: 'none'}) |
||||
uni.navigateTo({ |
||||
url: '/pages/me/login' |
||||
}) |
||||
} |
||||
uni.navigateTo({ |
||||
url: url |
||||
}); |
||||
}, |
||||
scrolltolower() { |
||||
if (this.pageList.length < this.total) { |
||||
this.queryParams.pageNo++; |
||||
this.getPageList(); |
||||
} |
||||
}, |
||||
changeTab(name) { |
||||
this.tabIndex = name; |
||||
uni.redirectTo({ |
||||
url: name |
||||
}); |
||||
} |
||||
} |
||||
}; |
||||
</script> |
||||
|
||||
<style lang="scss" scoped></style> |
@ -0,0 +1,13 @@ |
||||
<template> |
||||
<view>我的点赞</view> |
||||
</template> |
||||
|
||||
<script> |
||||
export default { |
||||
|
||||
} |
||||
</script> |
||||
|
||||
<style lang="scss" scoped> |
||||
|
||||
</style> |
@ -0,0 +1,100 @@ |
||||
<template> |
||||
<view class="container"> |
||||
<view class="p15"> |
||||
<!-- 用户信息 --> |
||||
<view class="user-info" @tap="next('/pages/me/userInfo')"> |
||||
<view class="fl1 flex ai-c"> |
||||
<u-avatar size="48"></u-avatar> |
||||
<view class="ml10 fs16 fw600"> |
||||
<view>{{ isLogin ? userInfo?.userName : '点击登陆' }}</view> |
||||
<view class="fs12 cor-999">{{ isLogin ? userInfo?.phone : '未登录' }}</view> |
||||
</view> |
||||
</view> |
||||
<u-icon name="arrow-right" size="16"></u-icon> |
||||
</view> |
||||
|
||||
<!-- cells 列表 --> |
||||
<u-cell-group :customStyle="{ 'background-color': '#fff', 'margin-top': '10px', 'border-radius': '8px' }"> |
||||
<u-cell icon="thumb-up" size="large" title="我的点赞" isLink @tap="next('/pages/me/good')"></u-cell> |
||||
<u-cell icon="heart" size="large" title="我的收藏" isLink @tap="next('/pages/me/like')"></u-cell> |
||||
<!-- <button open-type="share" class="share"> |
||||
<u-cell icon="share" title="分享" size="large" isLink></u-cell> |
||||
</button> --> |
||||
<!-- <u-cell v-if="isLogin" icon="thumb-up" size="large" title="我的关注" isLink @tap="next('/pages/me/look')"></u-cell> --> |
||||
|
||||
<u-cell icon="level" size="large" title="当前版本" :value="version"></u-cell> |
||||
<u-cell icon="phone" size="large" title="联系我们" :value="contactInfo.configDesc" isLink @tap="makePhone"></u-cell> |
||||
</u-cell-group> |
||||
|
||||
<!-- 退出登陆 --> |
||||
<u-button v-if="isLogin" plain :customStyle="{ 'margin-top': '20px' }" @tap="logout">退出登录</u-button> |
||||
</view> |
||||
</view> |
||||
</template> |
||||
|
||||
<script> |
||||
import { getSysConfig } from '@/jtools/api/index'; |
||||
import { mapState, mapActions } from 'pinia'; //引入映射函数 |
||||
import useUserStore from '@/jtools/store/user'; //引入store |
||||
export default { |
||||
computed: { |
||||
...mapState(useUserStore, ['userInfo', 'isLogin']) |
||||
}, |
||||
data() { |
||||
return { |
||||
version: uni.getAppBaseInfo().appVersion, |
||||
contactInfo: { |
||||
configValue: '18056811878', |
||||
configDesc: '周老师' |
||||
} |
||||
}; |
||||
}, |
||||
onLoad() { |
||||
getSysConfig({ configKey: 'AppletContact', driverTypeId: -1 }).then(res => { |
||||
this.contactInfo = res.data; |
||||
}); |
||||
}, |
||||
methods: { |
||||
...mapActions(useUserStore, ['logout']), |
||||
next(url) { |
||||
if (this.isLogin) { |
||||
uni.navigateTo({ |
||||
url: url |
||||
}); |
||||
} else { |
||||
uni.navigateTo({ |
||||
url: '/pages/me/login' |
||||
}); |
||||
} |
||||
}, |
||||
makePhone() { |
||||
uni.makePhoneCall({ |
||||
phoneNumber: this.contactInfo.configValue |
||||
}); |
||||
}, |
||||
} |
||||
}; |
||||
</script> |
||||
|
||||
<style lang="scss" scoped> |
||||
.container { |
||||
width: 100vw; |
||||
height: 100vh; |
||||
background: linear-gradient(180deg, rgb(242, 242, 242), #fff); // 线性渐变 |
||||
.user-info { |
||||
display: flex; |
||||
align-items: center; |
||||
justify-content: space-between; |
||||
background-color: #fff; |
||||
border-radius: 8px; |
||||
padding: 15px; |
||||
} |
||||
.share { |
||||
background-color: #fff; |
||||
width: 100%; |
||||
padding: 0; |
||||
text-align: left; |
||||
border: 0; |
||||
} |
||||
} |
||||
</style> |
@ -0,0 +1,13 @@ |
||||
<template> |
||||
<view>我的收藏</view> |
||||
</template> |
||||
|
||||
<script> |
||||
export default { |
||||
|
||||
} |
||||
</script> |
||||
|
||||
<style lang="scss" scoped> |
||||
|
||||
</style> |
@ -0,0 +1,49 @@ |
||||
<template> |
||||
<view class="content"> |
||||
<view class="mb40" style="border-bottom: 1px solid #eee;margin-top: 100px;"> |
||||
<u-input border="none" v-model="loginForm.phone" type="number" maxlength="11" |
||||
placeholder="输入手机号" /> |
||||
</view> |
||||
<u-button shape="circle" type="primary" @click="bindLogin()">授权登录</u-button> |
||||
</view> |
||||
</template> |
||||
|
||||
<script> |
||||
import useUserStore from '@/jtools/store/user' |
||||
import storage from '@/jtools/storage'; |
||||
export default { |
||||
data() { |
||||
return { |
||||
loginForm: { |
||||
phone: '', |
||||
code: '000000' |
||||
}, |
||||
countDown: 0, |
||||
js: undefined |
||||
}; |
||||
}, |
||||
methods: { |
||||
bindLogin() { |
||||
let params = { ...this.loginForm } |
||||
if (storage.get('companyId')) { |
||||
params.id = storage.get('companyId') |
||||
} |
||||
useUserStore().login(params).then(resp => { |
||||
if (resp.userId) { |
||||
useUserStore().getUserInfo() |
||||
uni.navigateBack() |
||||
} |
||||
}) |
||||
}, |
||||
} |
||||
} |
||||
</script> |
||||
|
||||
<style> |
||||
.content { |
||||
width: 100vw; |
||||
height: 100vh; |
||||
padding: 20px; |
||||
background-color: #fff; |
||||
} |
||||
</style> |
@ -0,0 +1,15 @@ |
||||
<template> |
||||
<div> |
||||
|
||||
</div> |
||||
</template> |
||||
|
||||
<script> |
||||
export default { |
||||
|
||||
} |
||||
</script> |
||||
|
||||
<style lang="scss" scoped> |
||||
|
||||
</style> |
@ -0,0 +1,115 @@ |
||||
<template> |
||||
<view class="container"> |
||||
<view class="flex ai-c jc-sb p15lr p5tb bb1"> |
||||
<view class="fs14 fl1">头像</view> |
||||
<u-avatar size="56" :src="form.avatar" @tap="chooseAvatar" /> |
||||
</view> |
||||
<view class="flex ai-c jc-sb p15 bb1"> |
||||
<view class="fs14"> |
||||
<text style="color: red;">*</text> |
||||
<text class="ml2">昵称</text> |
||||
</view> |
||||
<input |
||||
type="text" |
||||
v-model="form.userName" |
||||
placeholder="请输入昵称" |
||||
style="width: 100px;text-align: right; flex: 1;" |
||||
/> |
||||
</view> |
||||
<view class="flex ai-c jc-sb p15 bb1"> |
||||
<view class="fs14">真实姓名</view> |
||||
<input |
||||
type="text" |
||||
v-model="form.userName" |
||||
placeholder="请输入真实姓名" |
||||
style="width: 100px;text-align: right; flex: 1;" |
||||
/> |
||||
</view> |
||||
<view class="flex ai-c jc-sb p15 bb1"> |
||||
<view class="fs14">性别</view> |
||||
<view class="flex" @tap="showPicker"> |
||||
<text class="cor-666">{{ form.sex || '请选择性别' }}</text> |
||||
<u-icon name="arrow-right" size="16" class="ml10"></u-icon> |
||||
</view> |
||||
</view> |
||||
<view class="flex ai-c jc-sb p15 bb1"> |
||||
<view class="fs14">生日</view> |
||||
<view class="flex" @tap="showPicker"> |
||||
<text class="cor-666">{{ form.birthday || '请选择出生日期' }}</text> |
||||
<u-icon name="arrow-right" size="16" class="ml10"></u-icon> |
||||
</view> |
||||
</view> |
||||
<view class="flex ai-c jc-sb p15 bb1"> |
||||
<view class="fs14 fl1">手机号码</view> |
||||
<text class="cor-999">{{ form.phone }}</text> |
||||
</view> |
||||
|
||||
<!-- 保存 --> |
||||
<view class="p15 mt20"> |
||||
<u-button type="primary" @tap="submit">保存</u-button> |
||||
</view> |
||||
</view> |
||||
</template> |
||||
|
||||
<script> |
||||
import { updateUserInfo } from '@/jtools/api/user' |
||||
import useUserStore from '@/jtools/store/user' //引入store |
||||
export default { |
||||
name: 'UserInfo', |
||||
data() { |
||||
return { |
||||
form: {...useUserStore().userInfo}, |
||||
saving: false, |
||||
} |
||||
}, |
||||
methods: { |
||||
async submit() { |
||||
const res = await updateUserInfo(this.form) |
||||
if (res.code == '0000') { |
||||
uni.showToast({ |
||||
title: '修改成功', |
||||
icon: 'none' |
||||
}) |
||||
useUserStore().setUserInfo(this.form) |
||||
uni.navigateBack() |
||||
} |
||||
}, |
||||
chooseAvatar() { |
||||
const _this = this |
||||
uni.chooseImage({ |
||||
count: 1, |
||||
success: (res) => { |
||||
_this.form.avatar = res.tempFilePaths[0] |
||||
_this.saving = true |
||||
_this.uploadAvatar(res.tempFilePaths[0]) |
||||
} |
||||
}) |
||||
}, |
||||
uploadAvatar(url) { |
||||
uni.uploadFile({ |
||||
url: import.meta.env.VITE_UPLOAD_URL + 'wrj-api/system/file/upload', // 仅为示例,非真实的接口地址 |
||||
filePath: url, |
||||
name: 'file', |
||||
success: (res) => { |
||||
// setTimeout(() => { |
||||
// resolve(JSON.parse(res.data).data); |
||||
// }, 100); |
||||
this.saving = false; |
||||
}, |
||||
fail: () => { |
||||
resolve(null); |
||||
this.saving = false; |
||||
} |
||||
}); |
||||
} |
||||
} |
||||
} |
||||
</script> |
||||
|
||||
<style lang="scss" scoped> |
||||
.container { |
||||
width: 100vw; |
||||
height: 100vh; |
||||
background-color: #fff; |
||||
} |
||||
</style> |
@ -0,0 +1,13 @@ |
||||
<template> |
||||
|
||||
|
||||
<u-empty mode="page"> |
||||
<u-button slot="bottom" size="medium" @click="$Router.pushTab('/pages/tabbar/home')"> |
||||
去首页 |
||||
</u-button> |
||||
</u-empty> |
||||
</template> |
||||
|
||||
<script></script> |
||||
|
||||
<style></style> |
@ -0,0 +1,27 @@ |
||||
#选择城市,城市搜索弹窗 |
||||
## 引入 |
||||
import choseCity from "@/components/chose-city/chose-city" |
||||
export default { |
||||
components: { |
||||
choseCity |
||||
}, |
||||
data() { |
||||
return { |
||||
showCity:true // 默弹窗显示 |
||||
} |
||||
}, |
||||
methods: { |
||||
selectCity(item) { |
||||
console.log('-您选择的城市-',item) |
||||
// this.showCity = false |
||||
}, |
||||
closeModal() { |
||||
this.showCity = false |
||||
}, |
||||
} |
||||
} |
||||
## 页面引用 |
||||
<chose-city @selectCity="selectCity" v-if="showCity" @closeModal="closeModal"></chose-city> |
||||
showCity:弹窗是否显示 |
||||
selectCity:选择后的回调 |
||||
closeModal:点击取消的回调 |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,47 @@ |
||||
@font-face { |
||||
font-family: "custom-icon"; /* Project id 4964828 */ |
||||
src: url('iconfont.woff2?t=1752573741103') format('woff2'), |
||||
url('iconfont.woff?t=1752573741103') format('woff'), |
||||
url('iconfont.ttf?t=1752573741103') format('truetype'); |
||||
} |
||||
|
||||
.custom-icon { |
||||
font-family: "custom-icon" !important; |
||||
font-size: 16px; |
||||
font-style: normal; |
||||
-webkit-font-smoothing: antialiased; |
||||
-moz-osx-font-smoothing: grayscale; |
||||
} |
||||
|
||||
.custom-icon-kaodian:before { |
||||
content: "\e601"; |
||||
} |
||||
|
||||
.custom-icon-kaoshishijian:before { |
||||
content: "\e614"; |
||||
} |
||||
|
||||
.custom-icon-wodeshoucang:before { |
||||
content: "\e699"; |
||||
} |
||||
|
||||
.custom-icon-wodecuoti:before { |
||||
content: "\e64a"; |
||||
} |
||||
|
||||
.custom-icon-qicheqianlian-:before { |
||||
content: "\e611"; |
||||
} |
||||
|
||||
.custom-icon-feiji:before { |
||||
content: "\e6a9"; |
||||
} |
||||
|
||||
.custom-icon-helicopter-full:before { |
||||
content: "\e9dc"; |
||||
} |
||||
|
||||
.custom-icon-wurenji:before { |
||||
content: "\e872"; |
||||
} |
||||
|
File diff suppressed because one or more lines are too long
@ -0,0 +1,65 @@ |
||||
{ |
||||
"id": "4964828", |
||||
"name": "无人机", |
||||
"font_family": "custom-icon", |
||||
"css_prefix_text": "custom-icon-", |
||||
"description": "", |
||||
"glyphs": [ |
||||
{ |
||||
"icon_id": "1894917", |
||||
"name": "机构-考点", |
||||
"font_class": "kaodian", |
||||
"unicode": "e601", |
||||
"unicode_decimal": 58881 |
||||
}, |
||||
{ |
||||
"icon_id": "7316903", |
||||
"name": "考试时间", |
||||
"font_class": "kaoshishijian", |
||||
"unicode": "e614", |
||||
"unicode_decimal": 58900 |
||||
}, |
||||
{ |
||||
"icon_id": "908562", |
||||
"name": "我的收藏", |
||||
"font_class": "wodeshoucang", |
||||
"unicode": "e699", |
||||
"unicode_decimal": 59033 |
||||
}, |
||||
{ |
||||
"icon_id": "9570813", |
||||
"name": "我的错题", |
||||
"font_class": "wodecuoti", |
||||
"unicode": "e64a", |
||||
"unicode_decimal": 58954 |
||||
}, |
||||
{ |
||||
"icon_id": "2038774", |
||||
"name": "飞机-02", |
||||
"font_class": "qicheqianlian-", |
||||
"unicode": "e611", |
||||
"unicode_decimal": 58897 |
||||
}, |
||||
{ |
||||
"icon_id": "17427028", |
||||
"name": "飞机", |
||||
"font_class": "feiji", |
||||
"unicode": "e6a9", |
||||
"unicode_decimal": 59049 |
||||
}, |
||||
{ |
||||
"icon_id": "18170586", |
||||
"name": "直升机", |
||||
"font_class": "helicopter-full", |
||||
"unicode": "e9dc", |
||||
"unicode_decimal": 59868 |
||||
}, |
||||
{ |
||||
"icon_id": "36636166", |
||||
"name": "无人机", |
||||
"font_class": "wurenji", |
||||
"unicode": "e872", |
||||
"unicode_decimal": 59506 |
||||
} |
||||
] |
||||
} |
Binary file not shown.
Binary file not shown.
Binary file not shown.
After Width: | Height: | Size: 656 B |
After Width: | Height: | Size: 297 B |
After Width: | Height: | Size: 285 B |
After Width: | Height: | Size: 633 B |
After Width: | Height: | Size: 601 B |
@ -0,0 +1,3 @@ |
||||
page { |
||||
color: $uni-color-primary; |
||||
} |
@ -0,0 +1,434 @@ |
||||
/*每个页面公共css */ |
||||
page { |
||||
background: #f4f4f4; |
||||
color: #383838; |
||||
font-size: 26rpx; |
||||
} |
||||
/* image{ |
||||
background: skyblue; |
||||
} */ |
||||
image, |
||||
video { |
||||
display: block; |
||||
} |
||||
image{will-change: transform} |
||||
/*字体颜色*/ |
||||
.cor_fff { |
||||
color: #fff; |
||||
} |
||||
.cor_000 { |
||||
color: #000; |
||||
} |
||||
.cor_red { |
||||
color: #eb3831; |
||||
} |
||||
.cor_333 { |
||||
color: #333; |
||||
} |
||||
.cor_666 { |
||||
color: #666; |
||||
} |
||||
.cor_999 { |
||||
color: #999; |
||||
} |
||||
.cor_ccc { |
||||
color: #ccc; |
||||
} |
||||
.cor_eee{ |
||||
color: #eee; |
||||
} |
||||
.cor_text { |
||||
color: #262626; |
||||
} |
||||
.cor_38{ |
||||
color: #383838; |
||||
} |
||||
.cor_8c { |
||||
color: #8c8c8c; |
||||
} |
||||
.cor_80 { |
||||
color: #808080; |
||||
} |
||||
.cor_A6 { |
||||
color: #A6A6A6; |
||||
} |
||||
.cor_theme { |
||||
color: $uni-color-primary !important; |
||||
} |
||||
.cor_blue { |
||||
color: #43aefd; |
||||
} |
||||
.bk_theme { |
||||
background-color: $uni-color-primary !important; |
||||
color: #fff !important; |
||||
} |
||||
|
||||
.fwb { |
||||
font-weight: bold; |
||||
} |
||||
|
||||
/**图片大小**/ |
||||
.img16 { |
||||
width: 16rpx; |
||||
height: 16rpx; |
||||
} |
||||
|
||||
.mt70 { |
||||
margin-top: 70rpx; |
||||
} |
||||
.mt80 { |
||||
margin-top: 80rpx; |
||||
} |
||||
.mt90 { |
||||
margin-top: 90rpx; |
||||
} |
||||
|
||||
.mr60 { |
||||
margin-right: 60rpx; |
||||
} |
||||
.mr70 { |
||||
margin-right: 70rpx; |
||||
} |
||||
.mr100 { |
||||
margin-right: 100rpx; |
||||
} |
||||
.m20lr { |
||||
margin-left: 20rpx; |
||||
margin-right: 20rpx; |
||||
} |
||||
.m30lr { |
||||
margin-left: 30rpx; |
||||
margin-right: 30rpx; |
||||
} |
||||
|
||||
/**border**/ |
||||
.bb1 { |
||||
border-bottom: solid 1px #f4f4f4; |
||||
} |
||||
.bt1 { |
||||
border-top: solid 1px #eee; |
||||
} |
||||
.border1 { |
||||
border: solid 1px #eee; |
||||
} |
||||
.border_tb1{ |
||||
border-bottom: solid 1px #eee; |
||||
border-top: solid 1px #eee; |
||||
} |
||||
/***背景**/ |
||||
.bk_f { |
||||
background-color: #fff; |
||||
} |
||||
.bk_f9 { |
||||
background-color: #f9f9f9; |
||||
} |
||||
.bk_f2 { |
||||
background-color: #f2f2f2; |
||||
} |
||||
.bk_rgba05 { |
||||
background-color: rgba(0, 0, 0, 0.5); |
||||
} |
||||
.bk_main { |
||||
background-color: #3d92e1; |
||||
} |
||||
.bk_blue { |
||||
background: skyblue; |
||||
} |
||||
.bk_red { |
||||
background-color: #ff2d17; |
||||
} |
||||
.bk_white { |
||||
background-color: #fff; |
||||
} |
||||
.opt5 { |
||||
opacity: 0.5; |
||||
} |
||||
|
||||
.br_p50 { |
||||
border-radius: 50%; |
||||
} |
||||
.br_ltb{ |
||||
border-radius: 50% 0 0 50% !important; |
||||
} |
||||
.br_rtb{ |
||||
border-radius: 0 50% 50% 0 !important; |
||||
} |
||||
|
||||
/**宽度**/ |
||||
.wp20 { |
||||
width: 20%; |
||||
} |
||||
.wp25 { |
||||
width: 25%; |
||||
} |
||||
.wp40 { |
||||
width: 40%; |
||||
} |
||||
.wp50 { |
||||
width: 50%; |
||||
} |
||||
.wp100 { |
||||
width: 100%; |
||||
} |
||||
|
||||
/**高度**/ |
||||
.hp100 { |
||||
height: 100%; |
||||
} |
||||
|
||||
/**行距**/ |
||||
.lh1 { |
||||
line-height: 1; |
||||
} |
||||
.lh50{ |
||||
line-height: 50rpx; |
||||
} |
||||
/**flex 设置**/ |
||||
.df { |
||||
display: flex; |
||||
} |
||||
.fldr { |
||||
flex-direction: row !important; |
||||
} |
||||
.fldc { |
||||
flex-direction: column !important; |
||||
} |
||||
.fldrr { |
||||
flex-direction: row-reverse !important; |
||||
} |
||||
.jcsb { |
||||
justify-content: space-between !important; |
||||
} |
||||
.jcsba { |
||||
justify-content: space-around !important; |
||||
} |
||||
.jcfs { |
||||
justify-content: flex-start !important; |
||||
} |
||||
.jcc { |
||||
justify-content: center !important; |
||||
} |
||||
.jcfe { |
||||
justify-content: flex-end; |
||||
} |
||||
.fl1 { |
||||
flex: 1 !important; |
||||
} |
||||
.fw { |
||||
flex-wrap: wrap; |
||||
} |
||||
.ai-center { |
||||
align-items: center !important; |
||||
} |
||||
.ai-start { |
||||
align-items: flex-start; |
||||
} |
||||
.ai-baseline { |
||||
align-items: flex-end; |
||||
} |
||||
.ai-end { |
||||
align-items: flex-end; |
||||
} |
||||
.fls0 { |
||||
flex-shrink: 0; |
||||
} |
||||
|
||||
/*对齐*/ |
||||
.tac { |
||||
text-align: center; |
||||
} |
||||
.tar { |
||||
text-align: right; |
||||
} |
||||
.tal { |
||||
text-align: left; |
||||
} |
||||
|
||||
/** 其他样式 **/ |
||||
.ov { |
||||
overflow: hidden; |
||||
} |
||||
.ovya { |
||||
overflow-y: auto; |
||||
} |
||||
.bsb { |
||||
box-sizing: border-box; |
||||
} |
||||
.re { |
||||
position: relative; |
||||
} |
||||
.ab { |
||||
position: absolute; |
||||
} |
||||
.ab_full { |
||||
position: absolute; |
||||
left: 0; |
||||
top: 0; |
||||
right: 0; |
||||
bottom: 0; |
||||
} |
||||
.fixed { |
||||
position: fixed; |
||||
} |
||||
.db { |
||||
display: block; |
||||
} |
||||
.di { |
||||
display: inline; |
||||
} |
||||
.dib { |
||||
display: inline-block; |
||||
} |
||||
.dif { |
||||
display: inline-flex; |
||||
} |
||||
.v-middle { |
||||
position: absolute; |
||||
top: 50%; |
||||
transform: translateY(-50%); |
||||
} |
||||
.h-middle { |
||||
position: absolute; |
||||
left: 50%; |
||||
transform: translateX(-50%); |
||||
} |
||||
.middle { |
||||
position: absolute; |
||||
top: 50%; |
||||
left: 50%; |
||||
transform: translate(-50%, -50%); |
||||
} |
||||
.text-line-through { |
||||
text-decoration: line-through; |
||||
} |
||||
.text-underline { |
||||
text-decoration: underline; |
||||
} |
||||
.wb { |
||||
display: block; |
||||
word-break: break-all; |
||||
word-wrap: break-word; |
||||
} |
||||
.vam { |
||||
vertical-align: middle; |
||||
} |
||||
|
||||
/*灰色分割条*/ |
||||
.gray_bar { |
||||
height: 20rpx; |
||||
background: #f5f5f5; |
||||
} |
||||
|
||||
.scroll-box { |
||||
flex: 1; |
||||
height: 100%; |
||||
position: relative; |
||||
} |
||||
.content_box { |
||||
flex: 1; |
||||
overflow-y: auto; |
||||
} |
||||
.theme-tag { |
||||
display: inline-block; |
||||
padding: 0 25rpx; |
||||
height: 36rpx; |
||||
line-height: 36rpx; |
||||
border-radius: 20rpx; |
||||
border: 2rpx solid $uni-color-primary; |
||||
box-sizing: content-box; |
||||
font-size: 24rpx; |
||||
color: $uni-color-primary; |
||||
} |
||||
.selector { |
||||
position: relative; |
||||
padding-left: 30rpx; |
||||
padding-right: 20rpx; |
||||
height: 60rpx; |
||||
line-height: 60rpx; |
||||
border-radius: 30rpx; |
||||
font-size: 24rpx; |
||||
color: #333; |
||||
background-color: #fff; |
||||
} |
||||
.selector.actived { |
||||
color: $uni-color-primary; |
||||
border: 1rpx solid $uni-color-primary; |
||||
background: #e6f2ff; |
||||
} |
||||
|
||||
|
||||
.img24 { |
||||
width: 24px; |
||||
height: 24px; |
||||
} |
||||
|
||||
.img36 { |
||||
width: 36px; |
||||
height: 36px; |
||||
} |
||||
|
||||
.img48 { |
||||
width: 48px; |
||||
height: 48px; |
||||
} |
||||
|
||||
.img50 { |
||||
width: 50px; |
||||
height: 50px; |
||||
} |
||||
|
||||
.img120 { |
||||
width: 120px; |
||||
height: 120px; |
||||
} |
||||
|
||||
.img140 { |
||||
width: 140px; |
||||
height: 140px; |
||||
} |
||||
|
||||
.theme-bg-light { |
||||
background-color: $uni-color-primary; |
||||
} |
||||
.pt100 { |
||||
padding-top: 100rpx; |
||||
} |
||||
|
||||
.theme-btn { |
||||
padding: 0 20px; |
||||
min-width: 250rpx; |
||||
height: 78rpx; |
||||
line-height: 80rpx; |
||||
text-align: center; |
||||
font-size: 28rpx; |
||||
color: #fff; |
||||
border-radius: 40rpx; |
||||
background-color: $uni-color-primary; |
||||
} |
||||
|
||||
.theme-btn-light { |
||||
padding: 0 20px; |
||||
min-width: 250rpx; |
||||
height: 78rpx; |
||||
line-height: 80rpx; |
||||
text-align: center; |
||||
font-size: 28rpx; |
||||
color: #fff; |
||||
border-radius: 40rpx; |
||||
color: $uni-color-primary; |
||||
border: 1px solid $uni-color-primary; |
||||
} |
||||
|
||||
.img70 { |
||||
width:70px; |
||||
height: 70px; |
||||
} |
||||
|
||||
// .u-tabbar { |
||||
// max-height: 50px; |
||||
// } |
||||
|
||||
.j-tag { |
||||
display: inline-block; |
||||
margin-right: 2px; |
||||
} |
@ -0,0 +1,674 @@ |
||||
html, |
||||
body, |
||||
#app { |
||||
box-sizing: border-box; |
||||
height: 100%; |
||||
font-family: Avenir, Helvetica, Arial, sans-serif; |
||||
} |
||||
|
||||
/* 背景 */ |
||||
.bc-000 { |
||||
background-color: #000; |
||||
} |
||||
.bc-f5 { |
||||
background-color: #f5f5f5; |
||||
} |
||||
.bc-f7 { |
||||
background-color: #f7f7f7; |
||||
} |
||||
.bc-fff { |
||||
background-color: #fff; |
||||
} |
||||
.bc-t { |
||||
background-color: transparent; |
||||
} |
||||
|
||||
/* border */ |
||||
.border-top { |
||||
border-top: solid 1px #eee; |
||||
} |
||||
.border-bottom { |
||||
border-bottom: solid 1px #eee; |
||||
} |
||||
.border-0 { |
||||
border: 0px; |
||||
} |
||||
.border-1 { |
||||
border: 1px solid #eee; |
||||
} |
||||
.border-2 { |
||||
border: 2px solid #eee; |
||||
} |
||||
.border-3 { |
||||
border: 3px solid #eee; |
||||
} |
||||
.border-4 { |
||||
border: 4px solid #eee; |
||||
} |
||||
.border-5 { |
||||
border: 5px solid #eee; |
||||
} |
||||
|
||||
/* 文本格式 */ |
||||
.i { |
||||
word-wrap: break-word; |
||||
text-align: justify; |
||||
text-justify: inter-ideograph; |
||||
} |
||||
|
||||
/* 字体颜色 */ |
||||
.cor-000 { |
||||
color: #000000; |
||||
} |
||||
.cor-333 { |
||||
color: #333333; |
||||
} |
||||
.cor-666 { |
||||
color: #666666; |
||||
} |
||||
.cor-999 { |
||||
color: #999999; |
||||
} |
||||
.cor-aaa { |
||||
color: #aaaaaa; |
||||
} |
||||
.cor-ccc { |
||||
color: #cccccc; |
||||
} |
||||
.cor-ddd { |
||||
color: #dddddd; |
||||
} |
||||
.cor-fff { |
||||
color: #ffffff; |
||||
} |
||||
.cor-price { |
||||
color: #C03639; |
||||
} |
||||
|
||||
/* 行距 */ |
||||
.lh10 { |
||||
line-height: 1; |
||||
} |
||||
.lh11 { |
||||
line-height: 1.1; |
||||
} |
||||
.lh12 { |
||||
line-height: 1.2; |
||||
} |
||||
.lh13 { |
||||
line-height: 1.3; |
||||
} |
||||
.lh14 { |
||||
line-height: 1.4; |
||||
} |
||||
.lh15 { |
||||
line-height: 1.5; |
||||
} |
||||
.lh16 { |
||||
line-height: 1.6; |
||||
} |
||||
.lh18 { |
||||
line-height: 1.8; |
||||
} |
||||
.lh20 { |
||||
line-height: 2; |
||||
} |
||||
.lh25 { |
||||
line-height: 2.5; |
||||
} |
||||
.lh30 { |
||||
line-height: 3; |
||||
} |
||||
|
||||
/* 高度 */ |
||||
.hvh100 { |
||||
height: 100vh; |
||||
overflow: hidden; |
||||
} |
||||
.hp100 { |
||||
height: 100%; |
||||
overflow: hidden; |
||||
} |
||||
|
||||
/* float */ |
||||
.float-l { |
||||
float: left; |
||||
} |
||||
.float-r { |
||||
float: right; |
||||
} |
||||
.clearfix-both::after { |
||||
display: table; |
||||
clear: both; |
||||
content: ''; |
||||
} |
||||
|
||||
/* flex */ |
||||
.flex { |
||||
display: flex; |
||||
} |
||||
.fl0 { |
||||
flex: 0; |
||||
} |
||||
.fl1 { |
||||
flex: 1; |
||||
} |
||||
.fl2 { |
||||
flex: 2; |
||||
} |
||||
.fl3 { |
||||
flex: 3; |
||||
} |
||||
.fl4 { |
||||
flex: 4; |
||||
} |
||||
.fld-r { |
||||
flex-direction: row; |
||||
} |
||||
.fld-c { |
||||
flex-direction: column; |
||||
} |
||||
.fld-rr { |
||||
flex-direction: row-reverse; |
||||
} |
||||
.flw-w { |
||||
flex-wrap: wrap; |
||||
} |
||||
.fls0 { |
||||
flex-shrink: 0; |
||||
} |
||||
|
||||
.jc-sb { |
||||
justify-content: space-between; |
||||
} |
||||
.jc-sa { |
||||
justify-content: space-around; |
||||
} |
||||
.jc-fs { |
||||
justify-content: flex-start; |
||||
} |
||||
.jc-c { |
||||
justify-content: center; |
||||
} |
||||
.jc-fe { |
||||
justify-content: flex-end; |
||||
} |
||||
|
||||
.ai-c { |
||||
align-items: center; |
||||
} |
||||
.ai-s { |
||||
align-items: stretch; |
||||
} |
||||
.ai-fs { |
||||
align-items: flex-start; |
||||
} |
||||
.ai-fe { |
||||
align-items: flex-end; |
||||
} |
||||
|
||||
/* 对齐 */ |
||||
.text-center { |
||||
text-align: center; |
||||
} |
||||
.text-right { |
||||
text-align: right; |
||||
} |
||||
.text-left { |
||||
text-align: left; |
||||
} |
||||
|
||||
/* display */ |
||||
.none { |
||||
display: none; |
||||
} |
||||
.block { |
||||
display: block; |
||||
} |
||||
.inline { |
||||
display: inline; |
||||
} |
||||
.inline-block { |
||||
display: inline-block; |
||||
} |
||||
|
||||
/* 溢出 */ |
||||
.text-ellipsis { |
||||
overflow: hidden; |
||||
text-overflow: ellipsis; |
||||
white-space: nowrap; |
||||
} |
||||
.text-ellipsis2 { |
||||
overflow: hidden; |
||||
text-overflow: ellipsis; |
||||
display: -webkit-box; |
||||
-webkit-box-orient: vertical; |
||||
-webkit-line-clamp: 2; |
||||
} |
||||
.text-ellipsis3 { |
||||
overflow: hidden; |
||||
text-overflow: ellipsis; |
||||
display: -webkit-box; |
||||
-webkit-box-orient: vertical; |
||||
-webkit-line-clamp: 3; |
||||
} |
||||
|
||||
/* 其他 */ |
||||
.middle { |
||||
position: absolute; |
||||
z-index: 2; |
||||
top: 50%; |
||||
left: 50%; |
||||
transform: translate(-50%, -50%); |
||||
} |
||||
.middle-y { |
||||
position: absolute; |
||||
z-index: 2; |
||||
top: 50%; |
||||
transform: translateY(-50%); |
||||
} |
||||
.middle-x { |
||||
position: absolute; |
||||
z-index: 2; |
||||
left: 50%; |
||||
transform: translateX(-50%); |
||||
} |
||||
.text-line-through { |
||||
text-decoration: line-through; |
||||
} |
||||
.text-underline { |
||||
text-decoration: underline; |
||||
} |
||||
.overflow-h { |
||||
overflow: hidden; |
||||
} |
||||
.overflow-y { |
||||
overflow-y: auto; |
||||
overflow-x: hidden; |
||||
} |
||||
.overflow-x { |
||||
overflow-x: auto; |
||||
overflow-y: hidden; |
||||
} |
||||
.border-box { |
||||
box-sizing: border-box; |
||||
} |
||||
.content-box { |
||||
box-sizing: content-box; |
||||
} |
||||
.relative { |
||||
position: relative; |
||||
} |
||||
.absolute { |
||||
position: absolute; |
||||
} |
||||
.absolute-full { |
||||
position: absolute; |
||||
top: 0; |
||||
left: 0; |
||||
right: 0; |
||||
bottom: 0; |
||||
} |
||||
.fixed { |
||||
position: fixed; |
||||
} |
||||
.break-all { |
||||
display: block; |
||||
word-break: break-all; |
||||
word-wrap: break-word; |
||||
} |
||||
.nowrap { |
||||
white-space: nowrap; |
||||
} |
||||
.va-m { |
||||
vertical-align: middle; |
||||
} |
||||
.va-t { |
||||
vertical-align: top; |
||||
} |
||||
.va-b { |
||||
vertical-align: bottom; |
||||
} |
||||
|
||||
.opacity0 { |
||||
opacity: 0; |
||||
} |
||||
.opacity1 { |
||||
opacity: 0.1; |
||||
} |
||||
.opacity2 { |
||||
opacity: 0.2; |
||||
} |
||||
.opacity3 { |
||||
opacity: 0.3; |
||||
} |
||||
.opacity4 { |
||||
opacity: 0.4; |
||||
} |
||||
.opacity5 { |
||||
opacity: 0.5; |
||||
} |
||||
.opacity6 { |
||||
opacity: 0.6; |
||||
} |
||||
.opacity7 { |
||||
opacity: 0.7; |
||||
} |
||||
.opacity8 { |
||||
opacity: 0.8; |
||||
} |
||||
.opacity9 { |
||||
opacity: 0.9; |
||||
} |
||||
.opacity10 { |
||||
opacity: 1; |
||||
} |
||||
|
||||
/* z-index */ |
||||
.z-index-1 { |
||||
z-index: -1; |
||||
} |
||||
.z-index0 { |
||||
z-index: 0; |
||||
} |
||||
.z-index1 { |
||||
z-index: 1; |
||||
} |
||||
.z-index2 { |
||||
z-index: 2; |
||||
} |
||||
.z-index3 { |
||||
z-index: 3; |
||||
} |
||||
.z-index4 { |
||||
z-index: 4; |
||||
} |
||||
.z-index5 { |
||||
z-index: 5; |
||||
} |
||||
.z-index6 { |
||||
z-index: 6; |
||||
} |
||||
.z-index7 { |
||||
z-index: 7; |
||||
} |
||||
.z-index8 { |
||||
z-index: 8; |
||||
} |
||||
.z-index9 { |
||||
z-index: 9; |
||||
} |
||||
.z-index10 { |
||||
z-index: 10; |
||||
} |
||||
.z-index15 { |
||||
z-index: 15; |
||||
} |
||||
.z-index19 { |
||||
z-index: 19; |
||||
} |
||||
.z-index20 { |
||||
z-index: 20; |
||||
} |
||||
.z-index99 { |
||||
z-index: 99; |
||||
} |
||||
.z-index100 { |
||||
z-index: 100; |
||||
} |
||||
.z-index300 { |
||||
z-index: 300; |
||||
} |
||||
.z-index500 { |
||||
z-index: 500; |
||||
} |
||||
.z-index999 { |
||||
z-index: 999; |
||||
} |
||||
|
||||
/* 宽度 */ |
||||
.wp20 { |
||||
width: 20%; |
||||
} |
||||
.wp23 { |
||||
width: 23%; |
||||
} |
||||
.wp24 { |
||||
width: 24%; |
||||
} |
||||
.wp25 { |
||||
width: 25%; |
||||
} |
||||
.wp30 { |
||||
width: 30%; |
||||
} |
||||
.wp31 { |
||||
width: 31%; |
||||
} |
||||
.wp32 { |
||||
width: 32%; |
||||
} |
||||
.wp33 { |
||||
width: 33%; |
||||
} |
||||
.wp40 { |
||||
width: 40%; |
||||
} |
||||
.wp45 { |
||||
width: 45%; |
||||
} |
||||
.wp48 { |
||||
width: 48%; |
||||
} |
||||
.wp49 { |
||||
width: 49%; |
||||
} |
||||
.wp50 { |
||||
width: 50%; |
||||
} |
||||
.wp60 { |
||||
width: 60%; |
||||
} |
||||
.wp70 { |
||||
width: 70%; |
||||
} |
||||
.wp80 { |
||||
width: 80%; |
||||
} |
||||
.wp85 { |
||||
width: 85%; |
||||
} |
||||
.wp90 { |
||||
width: 90%; |
||||
} |
||||
.wp95 { |
||||
width: 95%; |
||||
} |
||||
.wp100 { |
||||
width: 100%; |
||||
} |
||||
.wvw100 { |
||||
width: 100vw; |
||||
} |
||||
.wp100-i { |
||||
width: 100% !important; |
||||
} |
||||
|
||||
/* 字体样式 */ |
||||
.arial { |
||||
font-family: Arial; |
||||
} |
||||
|
||||
/* 字体大小 */ |
||||
@for $i from 0 through 100 { |
||||
.fs#{$i} { |
||||
font-size: $i + px; |
||||
} |
||||
.img#{$i} { |
||||
width: $i + px; |
||||
height: $i + px; |
||||
} |
||||
} |
||||
|
||||
.fw400 { |
||||
font-weight: 400; |
||||
} |
||||
.fw500 { |
||||
font-weight: 500; |
||||
} |
||||
.fw600 { |
||||
font-weight: 600; |
||||
} |
||||
.fw700 { |
||||
font-weight: 700; |
||||
} |
||||
.fw800 { |
||||
font-weight: 800; |
||||
} |
||||
.fw900 { |
||||
font-weight: 900; |
||||
} |
||||
|
||||
.m0a { |
||||
margin: 0 auto; |
||||
} |
||||
|
||||
.br-p50 { |
||||
border-radius: 50%; |
||||
} |
||||
|
||||
/* marging */ |
||||
.mt-3 { |
||||
margin-top: -3px; |
||||
} |
||||
.mt-2 { |
||||
margin-top: -2px; |
||||
} |
||||
.mt-1 { |
||||
margin-top: -1px; |
||||
} |
||||
|
||||
.mr-3 { |
||||
margin-right: -3px; |
||||
} |
||||
.mr-2 { |
||||
margin-right: -2px; |
||||
} |
||||
.mr-1 { |
||||
margin-right: -1px; |
||||
} |
||||
|
||||
.mr-p1 { |
||||
margin-right: 1%; |
||||
} |
||||
.mr-p2 { |
||||
margin-right: 2%; |
||||
} |
||||
.mr-p3 { |
||||
margin-right: 3%; |
||||
} |
||||
.mr-p4 { |
||||
margin-right: 4%; |
||||
} |
||||
.mr-p5 { |
||||
margin-right: 5%; |
||||
} |
||||
|
||||
.mb-5 { |
||||
margin-bottom: -5px; |
||||
} |
||||
.mb-4 { |
||||
margin-bottom: -4px; |
||||
} |
||||
.mb-3 { |
||||
margin-bottom: -3px; |
||||
} |
||||
.mb-2 { |
||||
margin-bottom: -2px; |
||||
} |
||||
.mb-1 { |
||||
margin-bottom: -1px; |
||||
} |
||||
|
||||
.ml-5 { |
||||
margin-left: -5px; |
||||
} |
||||
.ml-4 { |
||||
margin-left: -4px; |
||||
} |
||||
.ml-3 { |
||||
margin-left: -3px; |
||||
} |
||||
.ml-2 { |
||||
margin-left: -2px; |
||||
} |
||||
.ml-1 { |
||||
margin-left: -1px; |
||||
} |
||||
|
||||
@for $i from 0 through 50 { |
||||
.m#{$i} { |
||||
margin: $i + px; |
||||
} |
||||
.mt#{$i} { |
||||
margin-top: $i + px; |
||||
} |
||||
.ml#{$i} { |
||||
margin-left: $i + px; |
||||
} |
||||
.mb#{$i} { |
||||
margin-bottom: $i + px; |
||||
} |
||||
.mr#{$i} { |
||||
margin-right: $i + px; |
||||
} |
||||
.m#{$i}tb { |
||||
margin-top: $i + px; |
||||
margin-bottom: $i + px; |
||||
} |
||||
.m#{$i}lr { |
||||
margin-left: $i + px; |
||||
margin-right: $i + px; |
||||
} |
||||
.p#{$i} { |
||||
padding: $i + px; |
||||
} |
||||
.pt#{$i} { |
||||
padding-top: $i + px; |
||||
} |
||||
.pl#{$i} { |
||||
padding-left: $i + px; |
||||
} |
||||
.pb#{$i} { |
||||
padding-bottom: $i + px; |
||||
} |
||||
.pr#{$i} { |
||||
padding-right: $i + px; |
||||
} |
||||
.p#{$i}lr { |
||||
padding-left: $i + px; |
||||
padding-right: $i + px; |
||||
} |
||||
.p#{$i}tb { |
||||
padding-top: $i + px; |
||||
padding-bottom: $i + px; |
||||
} |
||||
.br#{$i} { |
||||
border-radius: $i + px; |
||||
} |
||||
} |
||||
|
||||
@for $i from -10 through 20 { |
||||
.top#{$i} { |
||||
top: $i + px; |
||||
} |
||||
.left#{$i} { |
||||
left: $i + px; |
||||
} |
||||
.right#{$i} { |
||||
right: $i + px; |
||||
} |
||||
.bottom#{$i} { |
||||
bottom: $i + px; |
||||
} |
||||
} |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,129 @@ |
||||
|
||||
@import '@/static/style/colorui.css'; |
||||
@import './base.scss'; |
||||
@import './app.scss'; |
||||
page { |
||||
-webkit-overflow-scrolling: touch; // ios滑动不流畅 |
||||
height: 100%; |
||||
background: #f6f6f6; |
||||
width: 100%; |
||||
font-size: 30rpx; |
||||
font-family: Arial; |
||||
word-break: break-all; //英文文本不换行 |
||||
white-space: normal; |
||||
color: $u-main-color; |
||||
// padding-bottom: constant(safe-area-inset-bottom); |
||||
// padding-bottom: env(safe-area-inset-bottom); |
||||
// box-sizing: content-box; |
||||
} |
||||
|
||||
/* #ifdef MP-WEIXIN || APP-PLUS */ |
||||
::-webkit-scrollbar { |
||||
display: none; |
||||
width: 0 !important; |
||||
height: 0 !important; |
||||
-webkit-appearance: none; |
||||
background: transparent; |
||||
color: transparent; |
||||
} |
||||
/* #endif */ |
||||
|
||||
uni-tabbar.uni-tabbar-bottom .uni-tabbar { |
||||
padding-bottom: constant(safe-area-inset-bottom); |
||||
padding-bottom: env(safe-area-inset-bottom); |
||||
box-sizing: content-box; |
||||
} |
||||
.box-safe-area { |
||||
padding-bottom: constant(safe-area-inset-bottom); |
||||
padding-bottom: env(safe-area-inset-bottom); |
||||
box-sizing: content-box; |
||||
} |
||||
|
||||
.u-tabs .uni-scroll-view::-webkit-scrollbar { |
||||
width: 0; |
||||
height: 0; |
||||
color: transparent; |
||||
display: none !important; |
||||
} |
||||
|
||||
.content-wrapper { |
||||
padding: 25rpx; |
||||
} |
||||
|
||||
.input-placeholder { |
||||
font-size: 28rpx !important; |
||||
color: #a6a6a6 !important; |
||||
font-weight: 400 !important; |
||||
} |
||||
.uni-input-input, .uni-textarea-textarea, { |
||||
font-size: 28rpx; |
||||
color: #333; |
||||
} |
||||
.value-form .u-form-item__body { |
||||
flex-wrap: wrap !important; |
||||
align-items: flex-start !important; |
||||
} |
||||
.u-form-item__body__right__message { |
||||
margin-left: 0 !important; |
||||
text-align: center; |
||||
} |
||||
.u-form-item__body { |
||||
padding-top: 30rpx !important; |
||||
padding-bottom: 30rpx !important; |
||||
.u-form-item__body__left { |
||||
margin-right: 30rpx !important; |
||||
} |
||||
.u-form-item__body__right { |
||||
font-size: 28rpx !important; |
||||
} |
||||
} |
||||
|
||||
.form-label { |
||||
font-size: 28rpx; |
||||
color: #666; |
||||
line-height: 1; |
||||
} |
||||
.form-value { |
||||
font-size: 28rpx; |
||||
color: #000; |
||||
line-height: 40rpx; |
||||
} |
||||
|
||||
.u-tabs__wrapper__nav__line { |
||||
bottom: 0 !important; |
||||
} |
||||
|
||||
.u-notice .uicon-volume { |
||||
font-size: 40rpx !important; |
||||
} |
||||
|
||||
.uni-modal__btn_primary { |
||||
color: $uni-color-primary !important; |
||||
} |
||||
|
||||
.u-empty__text { |
||||
font-size: 30rpx !important; |
||||
} |
||||
|
||||
.notice .u-icon__icon { |
||||
color: $uni-color-primary !important; |
||||
} |
||||
|
||||
.u-popup { |
||||
flex: none !important; |
||||
.u-popup__content__close { |
||||
padding: 15rpx; |
||||
} |
||||
} |
||||
|
||||
input[type='password'] { |
||||
font-size: 14px; |
||||
} |
||||
|
||||
rich-text { |
||||
display: block !important; |
||||
font-size: 13px; |
||||
white-space: pre-wrap; |
||||
line-height: 1.8; |
||||
padding: 5px 0; |
||||
} |
@ -0,0 +1,26 @@ |
||||
@charset "UTF-8"; |
||||
/** |
||||
* 这里是uni-app内置的常用样式变量 |
||||
* |
||||
* uni-app 官方扩展插件及插件市场(https://ext.dcloud.net.cn)上很多三方插件均使用了这些样式变量 |
||||
* 如果你是插件开发者,建议你使用scss预处理,并在插件代码中直接使用这些变量(无需 import 这个文件),方便用户通过搭积木的方式开发整体风格一致的App |
||||
* |
||||
*/ |
||||
/** |
||||
* 如果你是App开发者(插件使用者),你可以通过修改这些变量来定制自己的插件主题,实现自定义主题功能 |
||||
* |
||||
* 如果你的项目同样使用了scss预处理,你也可以直接在你的 scss 代码中使用如下变量,同时无需 import 这个文件 |
||||
*/ |
||||
/* 颜色变量 */ |
||||
/* 行为相关颜色 */ |
||||
/* 文字基本颜色 */ |
||||
/* 背景颜色 */ |
||||
/* 边框颜色 */ |
||||
/* 尺寸变量 */ |
||||
/* 文字尺寸 */ |
||||
/* 图片尺寸 */ |
||||
/* Border Radius */ |
||||
/* 水平间距 */ |
||||
/* 垂直间距 */ |
||||
/* 透明度 */ |
||||
/* 文章场景相关 */ |
@ -0,0 +1 @@ |
||||
page{padding-top:0 !important}.uni-page-head{display:none !important} |
@ -0,0 +1,76 @@ |
||||
/** |
||||
* 这里是uni-app内置的常用样式变量 |
||||
* |
||||
* uni-app 官方扩展插件及插件市场(https://ext.dcloud.net.cn)上很多三方插件均使用了这些样式变量 |
||||
* 如果你是插件开发者,建议你使用scss预处理,并在插件代码中直接使用这些变量(无需 import 这个文件),方便用户通过搭积木的方式开发整体风格一致的App |
||||
* |
||||
*/ |
||||
|
||||
/** |
||||
* 如果你是App开发者(插件使用者),你可以通过修改这些变量来定制自己的插件主题,实现自定义主题功能 |
||||
* |
||||
* 如果你的项目同样使用了scss预处理,你也可以直接在你的 scss 代码中使用如下变量,同时无需 import 这个文件 |
||||
*/ |
||||
|
||||
/* 颜色变量 */ |
||||
@import '@/uni_modules/uview-plus/theme.scss'; |
||||
/* 行为相关颜色 */ |
||||
$uni-color-primary: #007aff; |
||||
$uni-color-success: #4cd964; |
||||
$uni-color-warning: #f0ad4e; |
||||
$uni-color-error: #dd524d; |
||||
|
||||
/* 文字基本颜色 */ |
||||
$uni-text-color:#333;//基本色 |
||||
$uni-text-color-inverse:#fff;//反色 |
||||
$uni-text-color-grey:#999;//辅助灰色,如加载更多的提示信息 |
||||
$uni-text-color-placeholder: #808080; |
||||
$uni-text-color-disable:#c0c0c0; |
||||
|
||||
/* 背景颜色 */ |
||||
$uni-bg-color:#ffffff; |
||||
$uni-bg-color-grey:#f8f8f8; |
||||
$uni-bg-color-hover:#f1f1f1;//点击状态颜色 |
||||
$uni-bg-color-mask:rgba(0, 0, 0, 0.4);//遮罩颜色 |
||||
|
||||
/* 边框颜色 */ |
||||
$uni-border-color:#c8c7cc; |
||||
|
||||
/* 尺寸变量 */ |
||||
|
||||
/* 文字尺寸 */ |
||||
$uni-font-size-sm:24rpx; |
||||
$uni-font-size-base:28rpx; |
||||
$uni-font-size-lg:32rpx; |
||||
|
||||
/* 图片尺寸 */ |
||||
$uni-img-size-sm:40rpx; |
||||
$uni-img-size-base:52rpx; |
||||
$uni-img-size-lg:80rpx; |
||||
|
||||
/* Border Radius */ |
||||
$uni-border-radius-sm: 4rpx; |
||||
$uni-border-radius-base: 6rpx; |
||||
$uni-border-radius-lg: 12rpx; |
||||
$uni-border-radius-circle: 50%; |
||||
|
||||
/* 水平间距 */ |
||||
$uni-spacing-row-sm: 10px; |
||||
$uni-spacing-row-base: 20rpx; |
||||
$uni-spacing-row-lg: 30rpx; |
||||
|
||||
/* 垂直间距 */ |
||||
$uni-spacing-col-sm: 8rpx; |
||||
$uni-spacing-col-base: 16rpx; |
||||
$uni-spacing-col-lg: 24rpx; |
||||
|
||||
/* 透明度 */ |
||||
$uni-opacity-disabled: 0.3; // 组件禁用态的透明度 |
||||
|
||||
/* 文章场景相关 */ |
||||
$uni-color-title: #2C405A; // 文章标题颜色 |
||||
$uni-font-size-title:40rpx; |
||||
$uni-color-subtitle: #555555; // 二级标题颜色 |
||||
$uni-font-size-subtitle:36rpx; |
||||
$uni-color-paragraph: #3F536E; // 文章段落颜色 |
||||
$uni-font-size-paragraph:30rpx; |
@ -0,0 +1,21 @@ |
||||
MIT License |
||||
|
||||
Copyright (c) 2024 https://uiadmin.net/uview-plus |
||||
|
||||
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. |
@ -0,0 +1,74 @@ |
||||
<p align="center"> |
||||
<img alt="logo" src="https://uiadmin.net/uview-plus/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-plus 3.0</h3> |
||||
<h3 align="center">多平台快速开发的UI框架</h3> |
||||
|
||||
[](https://github.com/ijry/uview-plus) |
||||
[](https://github.com/ijry/uview-plus) |
||||
[](https://github.com/ijry/uview-plus/issues) |
||||
[](https://gitee.com/jry/uview-plus/releases) |
||||
[](https://en.wikipedia.org/wiki/MIT_License) |
||||
|
||||
## 说明 |
||||
|
||||
uview-plus,是uni-app全面兼容vue3/nvue/鸿蒙/uni-app-x(即将发布)的uni-app生态框架,全面的组件和便捷的工具会让您信手拈来,如鱼得水。uview-plus是基于uView2.x移植的支持vue3的版本,感谢uView。 |
||||
|
||||
## 可视化设计 |
||||
|
||||
uview-plus现已推出免费可视化设计,可以方便的进行页面可视化设计,导出源码即可使用。极大提高前端页面开发效率;如产品经理设计师直接使用更可作为高保真高可用原型制作工具,让设计稿即代码,无需传统的设计稿开发还原步骤。 |
||||
|
||||
<img src="https://s3.bmp.ovh/imgs/2024/11/24/fd58d00071e6e5df.png" width="900" height="auto" > |
||||
<img src="https://s3.bmp.ovh/imgs/2024/11/24/8e85a519fe627fb1.png" width="900" height="auto" > |
||||
|
||||
|
||||
## 文档 |
||||
[官方文档:https://uview-plus.jiangruyi.com](https://uview-plus.jiangruyi.com) |
||||
[备用文档:https://uiadmin.net/uview-plus](https://uiadmin.net/uview-plus) |
||||
|
||||
|
||||
## 预览 |
||||
|
||||
您可以通过**微信**扫码,查看最佳的演示效果。 |
||||
<br> |
||||
<br> |
||||
<img src="https://uview-plus.jiangruyi.com/common/h5_qrcode.png" width="220" height="220" > |
||||
|
||||
## 链接 |
||||
|
||||
- [官方文档](https://uview-plus.jiangruyi.com) |
||||
- [更新日志](https://uview-plus.jiangruyi.com/components/changelog.html) |
||||
- [升级指南](https://uview-plus.jiangruyi.com/components/changeGuide.html) |
||||
- [关于我们](https://uview-plus.jiangruyi.com/cooperation/about.html) |
||||
|
||||
## 交流反馈 |
||||
|
||||
欢迎加入我们的QQ群交流反馈:[点此跳转](https://uview-plus.jiangruyi.com/components/addQQGroup.html) |
||||
|
||||
## 关于PR |
||||
|
||||
> 我们非常乐意接受各位的优质PR,但在此之前我希望您了解uview-plus是一个需要兼容多个平台的(小程序、h5、ios app、android app)包括nvue页面、vue页面。 |
||||
> 所以希望在您修复bug并提交之前尽可能的去这些平台测试一下兼容性。最好能携带测试截图以方便审核。非常感谢! |
||||
|
||||
## 安装 |
||||
|
||||
#### **uni-app插件市场链接** —— [https://ext.dcloud.net.cn/plugin?name=uview-plus](https://ext.dcloud.net.cn/plugin?name=uview-plus) |
||||
|
||||
请通过[官网安装文档](https://uview-plus.jiangruyi.com/components/install.html)了解更详细的内容 |
||||
|
||||
## 快速上手 |
||||
|
||||
请通过[快速上手](https://uview-plus.jiangruyi.com/components/quickstart.html)了解更详细的内容 |
||||
|
||||
## 使用方法 |
||||
配置easycom规则后,自动按需引入,无需`import`组件,直接引用即可。 |
||||
|
||||
```html |
||||
<template> |
||||
<u-button text="按钮"></u-button> |
||||
</template> |
||||
``` |
||||
|
||||
## 版权信息 |
||||
uview-plus遵循[MIT](https://en.wikipedia.org/wiki/MIT_License)开源协议,意味着您无需支付任何费用,也无需授权,即可将uview-plus应用到您的产品中。 |
||||
|
@ -0,0 +1,909 @@ |
||||
## 3.4.48(2025-07-10) |
||||
fix: 官方文档Card示例组件多行显示省略号样式异常 |
||||
|
||||
feat: album组件支持自定义preview事件 |
||||
|
||||
## 3.4.47(2025-07-09) |
||||
fix: 修复datetime-picker打开时,数值可能出现对不上的问题 |
||||
|
||||
feat: Subsection 分段器添加支持从 list中读取激活文字颜色和未激活文字颜色 |
||||
|
||||
fix: 修复modal定义confirmButton |
||||
|
||||
fix: safe-bottom底部安全距离在小程序优先用JS计算 |
||||
|
||||
feat: 新增tree树形组件 |
||||
|
||||
## 3.4.46(2025-07-08) |
||||
feat: 上传组件预览视频支持videoPreviewObjectFit参数 |
||||
|
||||
feat: td增加多个样式props |
||||
|
||||
fix: 修复noticeBar字号增大时文字遮挡 |
||||
|
||||
feat: 项目工程增加pinia |
||||
|
||||
## 3.4.45(2025-07-01) |
||||
fix: 修复picker-data组件缺少name |
||||
|
||||
fix: 优化picker高度单位 |
||||
|
||||
## 3.4.44(2025-06-30) |
||||
fix: 修复indexList中stikcy属性写死的问题(always true) |
||||
|
||||
feat: 搜索框添加新的右侧插槽 |
||||
|
||||
fix: 修复indexList中丢失的select event |
||||
|
||||
fix: 解决因为层级问题导致点击picker选择器无法正常弹出 |
||||
|
||||
## 3.4.43(2025-06-16) |
||||
feat: table2支持header插槽 |
||||
|
||||
## 3.4.42(2025-06-12) |
||||
fix: 修复qrcode中默认id问题及canvas2时App无法绘制二维码 感谢@jiaruiyan |
||||
|
||||
## 3.4.41(2025-06-11) |
||||
feat: qrcode支持 新参数useRootHeightAndWidth 是否使用根节点的宽高 感谢@YJR |
||||
|
||||
feat: toast支持设置zIndex层级 |
||||
|
||||
|
||||
|
||||
## 3.4.40(2025-06-06) |
||||
fix: 升级二维码 canvas -> canvas2 感谢@yjr |
||||
|
||||
## 3.4.39(2025-05-31) |
||||
fix: 修改步骤条微信小程序下的布局 感谢@jiaruiyan |
||||
|
||||
fix: u-tabs在屏幕尺寸发生变化时滑块位置没有发生变化 感谢@aqzhft |
||||
|
||||
fix: 鸿蒙平台不支持plus.runtime.openWeb 感谢@aqzhft |
||||
|
||||
## 3.4.38(2025-05-30) |
||||
fix: 修复picker-data快捷组件缺少index |
||||
|
||||
fix: 修复picker组件双向绑定初始化及取消后复原再次打开后的当前项目 |
||||
|
||||
## 3.4.37(2025-05-29) |
||||
feat: modal支持设置动画时间 |
||||
|
||||
fix: DatetimePicker v-model 绑定异步设置无效 (#803) |
||||
|
||||
## 3.4.36(2025-05-28) |
||||
fix: lazy-load图片为空时显示错误 |
||||
|
||||
## 3.4.35(2025-05-28) |
||||
feat: 进度条支持从右往左加载 |
||||
|
||||
## 3.4.34(2025-05-28) |
||||
feat: table2支持自定义标题和单元格样式 |
||||
|
||||
## 3.4.33(2025-05-27) |
||||
fix: 修复小程序cate-tab第一次切换时没反应 感谢@jiaruiyan |
||||
|
||||
fix: 修复datetimepicker传入空字符串时导致组件崩溃 感谢@jiaruiyan |
||||
|
||||
fix: 修复album带单位的字符串参与计算导致的计算数据错误 感谢@jiaruiyan |
||||
|
||||
## 3.4.32(2025-05-26) |
||||
feat: 增加状态栏独立颜色配置支持支付宝小程序状态栏对背景色识别的不友好的情况 |
||||
|
||||
fix: 抖音二维码兼容修复 |
||||
|
||||
feat: cate-tab组件增加rightTop插槽 #715 |
||||
|
||||
fix: 修改 test.promise(res) 预期结果不一致 |
||||
|
||||
## 3.4.31(2025-05-17) |
||||
fix: 修复parse富文本组件导致鸿蒙运行白屏 |
||||
|
||||
fix: 去除演示项目中uni.$u用法便于兼容鸿蒙 |
||||
|
||||
feat: modal新增popupBottom插槽适用类似关闭按钮与内容区域分离的场景 |
||||
|
||||
## 3.4.30(2025-05-16) |
||||
feat: 新增pagination分页器组件 |
||||
|
||||
feat: popup新增bottom插槽适用类似关闭按钮与内容区域分离的场景 |
||||
|
||||
## 3.4.29(2025-05-15) |
||||
fix: 修复table2横向滚动样式 |
||||
|
||||
fix: 修复table2组件宽度兼容 |
||||
|
||||
fix: 修复image显示png图片时默认背景色问题 |
||||
|
||||
feat: cate-tab新增height参数便于设置组件高度 |
||||
|
||||
feat: 在index.js种导出digit.js便于使用 |
||||
|
||||
fix: 修复tag组件缺失iconColor属性 |
||||
|
||||
fix: 优化index-list的setValueForTouch方法逻辑 #708 |
||||
|
||||
feat: number-box支持change事件返回变动是点击了增加还是减少按钮 |
||||
|
||||
fix: 修复table2在小程序下部分情形不显示表格 |
||||
|
||||
## 3.4.28(2025-05-12) |
||||
feat: 新增table表格组件 |
||||
|
||||
feat: 新增element-plus风格的table2组件 |
||||
|
||||
## 3.4.27(2025-05-06) |
||||
fix: 修复card组件props |
||||
|
||||
## 3.4.26(2025-05-06) |
||||
fix: 修复test工具引入 |
||||
|
||||
feat: card组件支持全局设置props默认值 |
||||
|
||||
fix: 修复image在加载错误情况下高度和宽度不正确问题 |
||||
|
||||
fix: 修复picker-data快捷组件默认picker选中 |
||||
|
||||
fix: 修复日历month子组件缺失emits定义 |
||||
|
||||
## 3.4.25(2025-04-27) |
||||
fix: up-form编译在微信小程序里样式缺失 #640 |
||||
|
||||
fix: number-box输入为空时自动设为最小值 |
||||
|
||||
feat: picker与datetimepicke组件hasInput模式支持inputProps属性 |
||||
|
||||
## 3.4.24(2025-04-25) |
||||
fix: 修复upload上传逻辑(感谢@semdy) |
||||
|
||||
## 3.4.23(2025-04-24) |
||||
chore: 补全chooseFile TS类型(感谢@semdy) |
||||
|
||||
feat: u-search组件的图标支持显示在右边(感谢@semdy) |
||||
|
||||
chore: 修正chooseFile返回的数据TS类型(感谢@semdy) |
||||
|
||||
fix: PR导致缺失name影响uplad自动上传扩展名 |
||||
|
||||
|
||||
## 3.4.22(2025-04-22) |
||||
fix: 修复自动上传偶发的success被覆盖为uploading |
||||
|
||||
fix: float-button缺少key #677 |
||||
|
||||
fix: upload组件完善优化(感谢@semdy) |
||||
|
||||
fix: toolbar组件confirmColor属性默认改为空,以便默认使用主题色、标题字体加粗(感谢@semdy) |
||||
|
||||
## 3.4.21(2025-04-21) |
||||
feat: subsection分段器支持双向绑定current |
||||
|
||||
feat: select组件支持maxHeight属性 |
||||
|
||||
feat: datetime-picker支持inputBorder属性 |
||||
|
||||
## 3.4.20(2025-04-17) |
||||
fix: 修复navbar-mini提示border不存在 |
||||
|
||||
feat: status-bar支持对外暴露状态栏高度值 |
||||
|
||||
feat: upload支持自定义自动上传后处理逻辑便于对接不同规范后端 |
||||
|
||||
feat: 优化tag组件插槽 |
||||
|
||||
|
||||
## 3.4.19(2025-04-14) |
||||
fix: 修复model组件增加contentStyle带来的语法问题 |
||||
|
||||
## 3.4.18(2025-04-14) |
||||
fix: upload组件支持所有文件类型的onClickPreview事件 |
||||
|
||||
## 3.4.17(2025-04-11) |
||||
feat: select组件text插槽增加scope传递currentLabel |
||||
|
||||
## 3.4.16(2025-04-10) |
||||
fix: 修复安卓新加载字体方式导致Cannot read property '$page' of undefined |
||||
|
||||
## 3.4.15(2025-04-10) |
||||
improvment: 优化移步加载数据时swiper组件displayMultipleItems报错 |
||||
|
||||
feat: modal增加contentStyle属性 |
||||
|
||||
fix: 修复下拉菜单收起动画缺失 |
||||
|
||||
fix: 修复sticky的offset属性值为响应式数据时失效 #237 |
||||
|
||||
|
||||
## 3.4.14(2025-04-09) |
||||
feat: 支持自托管内置图标及扩展自定义图标 |
||||
|
||||
## 3.4.13(2025-04-08) |
||||
fix: tabs点击当前tab触发change事件 |
||||
|
||||
## 3.4.12(2025-04-02) |
||||
fix: dropdown关闭后遮挡页面内容 #653 |
||||
|
||||
fix u-sticky.vue Uncaught TypeError: e.querySelector is not a function at uni-app-view.umd.js |
||||
|
||||
## 3.4.11(2025-03-31) |
||||
fix: 优化upload组件预览视频的弹窗占位 |
||||
|
||||
## 3.4.10(2025-03-28) |
||||
feat: select组件新增多个props属性及优化 |
||||
|
||||
fix: 修复cate-tab报错index is not defined #661 |
||||
|
||||
|
||||
## 3.4.9(2025-03-27) |
||||
fix: 修复upload组件split报错 |
||||
|
||||
fix: 修复float-button缺少flex样式 |
||||
|
||||
## 3.4.8(2025-03-27) |
||||
fix: 修复upload组件split报错 |
||||
|
||||
fix: 移除mapState |
||||
|
||||
## 3.4.7(2025-03-26) |
||||
fix: 修复action-sheet-data和picker-data数据回显 |
||||
|
||||
fix: 优化upload组件视频封面兼容 |
||||
|
||||
## 3.4.6(2025-03-25) |
||||
feat: checkbox触发change时携带name参数 |
||||
|
||||
feat: upload组件支持服务器本机和阿里云OSS自动上传功能及上传进度条 |
||||
|
||||
feat: upload组件支持视频预览及oss上传时获取视频封面图 |
||||
|
||||
feat: 新增up-action-sheet-data快捷组件 |
||||
|
||||
feat: 新增up-picker-data快捷组件 |
||||
|
||||
## 3.4.5(2025-03-24) |
||||
feat: tag组件新增textSize/height/padding/borderRadius属性 |
||||
|
||||
feat: 新增genLightColor自动计算浅色方法及tag组件支持autoBgColor自动计算背景色 |
||||
|
||||
## 3.4.4(2025-03-13) |
||||
feat: modal增加异步操作进行中点击取消弹出提示特性防止操作被中断 |
||||
|
||||
fix: 修复toast组件show方法类型声明 |
||||
|
||||
## 3.4.3(2025-03-12) |
||||
fix: 修复textarea自动增高时在输入时高度异常 |
||||
|
||||
## 3.4.2(2025-03-11) |
||||
feat: step组件增加title插槽及增加辅助class便于自定义样式 |
||||
|
||||
## 3.4.1(2025-03-11) |
||||
feat: 新机制确保setConfig与http在nvue等环境下生效 |
||||
|
||||
## 3.3.74(2025-03-06) |
||||
fix: CateTab语法问题 |
||||
|
||||
## 3.3.73(2025-03-06) |
||||
feat: CateTab新增v-model:current属性 |
||||
|
||||
## 3.3.72(2025-02-28) |
||||
feat: tabs组件支持icon图标及插槽 |
||||
|
||||
## 3.3.71(2025-02-27) |
||||
feat: 折叠面板collapse增加titileStyle/iconStyle/rightIconStyle属性 |
||||
|
||||
feat: 折叠面板组件新增cellCustomStyle/cellCustomClass属性 |
||||
|
||||
fix: select组件盒模型 |
||||
|
||||
## 3.3.70(2025-02-24) |
||||
fix: 修改u-checkbox-group组件changes事件发生位置 |
||||
|
||||
## 3.3.69(2025-02-19) |
||||
picker允许传递禁用颜色props |
||||
|
||||
slider组件isRange状态下增加min max插槽分开显示内容 |
||||
|
||||
feat: 新增经典下拉框组件up-select |
||||
|
||||
## 3.3.68(2025-02-12) |
||||
fix: 修复weekText类型 |
||||
|
||||
feat: 日历增加单选与多选指定禁止选中的日期功能 |
||||
|
||||
fix: NumberBox删除数字时取值有误 #613 |
||||
|
||||
## 3.3.67(2025-02-11) |
||||
feat: navbar支持返回全局拦截器配置 |
||||
|
||||
feat: 表单-校验-支持无提示-得到校验结果 |
||||
|
||||
feat: picker传递hasInput属性时候,可以禁用输入框点击 |
||||
|
||||
## 3.3.66(2025-02-09) |
||||
feat: steps-item增加content插槽 |
||||
|
||||
## 3.3.65(2025-02-05) |
||||
feat: number-box组件新增按钮圆角/按钮宽度/数据框背景色/迷你模式 |
||||
## 3.3.64(2025-01-18) |
||||
feat: 日历组件支持自定义星期文案 |
||||
|
||||
## 3.3.63(2025-01-13) |
||||
fix: cate-tab支持支付宝小程序 |
||||
|
||||
fix: textarea 修复 placeholder-style |
||||
|
||||
fix: 修复在图片加载及加载失败时容器宽度 |
||||
|
||||
fix: waterfall组件报错Maximum recursive updates |
||||
|
||||
## 3.3.62(2025-01-10) |
||||
feat: sleder滑动选择器双滑块增加外层触发值的变动功能 |
||||
|
||||
fix: picker支持hasInput优化 |
||||
|
||||
## 3.3.61(2024-12-31) |
||||
fix: 修复微信getSystemInfoSync接口废弃警告 |
||||
|
||||
fix: 'u-status-bar' symbol missing |
||||
|
||||
## 3.3.60(2024-12-30) |
||||
feat: 日期组件支持禁用 |
||||
|
||||
fix: ts定义修复 #600 |
||||
|
||||
feat: Tabs组件选中时增加一个active的class #595 |
||||
|
||||
## 3.3.59(2024-12-30) |
||||
fix: Property "isH5" was accessed during render |
||||
|
||||
## 3.3.58(2024-12-26) |
||||
fix: slider组件change事件传参 |
||||
|
||||
## 3.3.57(2024-12-23) |
||||
fix: slider组件change事件传参 |
||||
|
||||
feat: 更新u-picker组件增加当前选中class类名 |
||||
|
||||
## 3.3.56(2024-12-18) |
||||
feat: 在u-alert组件中添加关闭事件 |
||||
|
||||
## 3.3.55(2024-12-17) |
||||
add: swiper增加双向绑定 |
||||
|
||||
## 3.3.54(2024-12-11) |
||||
add: qrcode支持props控制是否开启点击预览 |
||||
|
||||
add: 新增cate-tab垂直分类组件 |
||||
|
||||
## 3.3.53(2024-12-10) |
||||
fix: 修复popup居中模式点击内容区域触发关闭 |
||||
|
||||
## 3.3.52(2024-12-09) |
||||
add: notice-bar支持justifyContent属性 |
||||
|
||||
## 3.3.51(2024-12-09) |
||||
add: radio增加label插槽 |
||||
|
||||
## 3.3.50(2024-12-05) |
||||
fix: 优化popup等对禁止背景滚动机制 |
||||
|
||||
add: slider在弹窗使用示例 |
||||
|
||||
fix: card组件类名问题 |
||||
|
||||
## 3.3.49(2024-12-02) |
||||
fix: 去除album多余的$u引用 |
||||
|
||||
fix: 优化图片组件兼容性 |
||||
|
||||
add: picker组件增加zIndex属性 |
||||
|
||||
add: text增加是否占满剩余空间属性 |
||||
|
||||
add: input颜色示例 |
||||
|
||||
## 3.3.48(2024-11-29) |
||||
add: 文本行数限制样式提高到10行 |
||||
|
||||
del: 去除不跨端的inputmode |
||||
## 3.3.47(2024-11-28) |
||||
fix: 时间选择器在hasInput模式下部分机型键盘弹出 |
||||
|
||||
## 3.3.46(2024-11-26) |
||||
fix: 修复text传递事件参数 |
||||
|
||||
## 3.3.45(2024-11-24) |
||||
add: navbar组件支持配置标题颜色 |
||||
|
||||
fix: 边框按钮警告类型下颜色变量使用错误 |
||||
|
||||
## 3.3.43(2024-11-18) |
||||
fix: 支持瀑布流组件v-model置为[] |
||||
|
||||
add: 新增字符串路径访问工具方法getValueByPath |
||||
|
||||
add: 新增float-button悬浮按钮组件 |
||||
|
||||
## 3.3.42(2024-11-15) |
||||
add: button组件支持stop参数阻止冒泡 |
||||
|
||||
## 3.3.41(2024-11-13) |
||||
fix: u-radio-group invalid import |
||||
|
||||
improvement: 优化图片组件宽高及修复事件event传递 |
||||
|
||||
## 3.3.40(2024-11-11) |
||||
add: 组件radioGroup增加gap属性用于设置item间隔 |
||||
|
||||
fix: 修复H5全局导入 |
||||
|
||||
## 3.3.39(2024-11-04) |
||||
fix: 修复相册组件 |
||||
|
||||
## 3.3.38(2024-11-04) |
||||
fix: 修复视频预览报错 #510 |
||||
|
||||
add: album组件增加stop参数支持阻止事件冒泡 |
||||
|
||||
## 3.3.37(2024-10-21) |
||||
fix: 修复因为修改组件名称前缀,导致h5打包后$parent方法内找不到父组件的问题 |
||||
|
||||
fix: 修复datetime-picker选择2000年以前日期出错 |
||||
|
||||
## 3.3.36(2024-10-09) |
||||
fix: toast 自动关闭 |
||||
|
||||
feat: 增加微信小程序用户昵称审核完毕回调及修改 ts 定义文件 |
||||
|
||||
## 3.3.35(2024-10-08) |
||||
feat: modal和picker支持v-model:show双向绑定 |
||||
|
||||
feat: 支持checkbox使用slot自定义label后自带点击事件 #522 |
||||
|
||||
feat: swipe-action支持自动关闭特性及初始化打开状态 |
||||
|
||||
## 3.3.34(2024-09-23) |
||||
feat: 支持toast设置duration值为-1时不自动关闭 |
||||
|
||||
## 3.3.33(2024-09-18) |
||||
fix: 修复test.date('008')等验证结果不准确 |
||||
|
||||
## 3.3.32(2024-09-09) |
||||
fix: u-keyboard名称冲突warning |
||||
|
||||
## 3.3.31(2024-08-31) |
||||
feat: qrcode初步支持nvue |
||||
|
||||
## 3.3.30(2024-08-30) |
||||
fix: slider兼容step为字符串类型 |
||||
|
||||
## 3.3.29(2024-08-30) |
||||
fix: 修复tabs组件current参数为字符串处理逻辑 |
||||
|
||||
## 3.3.28(2024-08-26) |
||||
fix: list组件滑动偏移量不一样取绝对值导致iOS下拉偏移量计算错误 |
||||
|
||||
## 3.3.27(2024-08-22) |
||||
fix: 修复up-datetime-picker组件toolbarRightSlot定义缺失 |
||||
|
||||
fix: 修复FormItem的rules更新错误的问题 |
||||
|
||||
## 3.3.26(2024-08-22) |
||||
fix: 批量注册全局组件优化 |
||||
|
||||
## 3.3.25(2024-08-21) |
||||
fix: 修复slider在app-vue下样式问题 |
||||
|
||||
## 3.3.24(2024-08-19) |
||||
fix: 修复时间选择器hasInput模式小程序不生效 |
||||
|
||||
feat: 支持H5导入所有组件 |
||||
|
||||
## 3.3.23(2024-08-17) |
||||
feat: swipe-action增加closeAll方法 |
||||
|
||||
fix: 兼容tabs在某些场景下index小于0时自动设置为0 |
||||
|
||||
add: 通用mixin新增navTo页面跳转方法 |
||||
|
||||
## 3.3.21(2024-08-15) |
||||
improvement: 优化二维码组件loading及支持预览与长按事件 #351 |
||||
|
||||
fix: 修复swipe-action自动关闭其它功能及组件卸载自动关闭 |
||||
|
||||
## 3.3.20(2024-08-15) |
||||
refactor: props默认值文件移至组件文件夹内便于查找 |
||||
## 3.3.19(2024-08-14) |
||||
fix: 修复2被rpx兼容处理只在数字值生效 |
||||
|
||||
add: 增加swiper自定义插槽示例 |
||||
|
||||
## 3.3.18(2024-08-13) |
||||
feat: 新增支持datetime-picker工具栏插槽及picker插槽支持修复 |
||||
## 3.3.17(2024-08-12) |
||||
feat: swiper组件增加默认slot便于自定义 |
||||
|
||||
feat: grid新增间隔参数 |
||||
|
||||
feat: picker新增toolbar-right和toolbar-bottom插槽 |
||||
|
||||
## 3.3.16(2024-08-12) |
||||
fix: 解决swiper中title换行后多余的内容未被遮挡问题 |
||||
|
||||
fix: 修复迷你导航适配异形屏 |
||||
|
||||
## 3.3.15(2024-08-09) |
||||
fix: 修复默认单位设置为rpx时一些组件高度间距异常 |
||||
|
||||
fix: 修复日历在rpx单位下布局异常 |
||||
|
||||
feat: code-input支持App端展示输入光标 |
||||
|
||||
## 3.3.14(2024-08-09) |
||||
add: 增加box组件 |
||||
|
||||
add: 增加card卡片组件 |
||||
|
||||
|
||||
## 3.3.13(2024-08-08) |
||||
feat: input支持调用原生组件的focus和blur方法 |
||||
|
||||
improvement: grid-item条件编译优化 |
||||
|
||||
add: 新增迷你导航组件 |
||||
|
||||
## 3.3.12(2024-08-06) |
||||
improvement: $u挂载时机调整便于打包分离chunk |
||||
|
||||
fix: steps新增itemStyle属性名称冲突 |
||||
|
||||
## 3.3.11(2024-08-05) |
||||
feat: 新增支持upload组件的deletable/maxCount/accept变更监听 #333 |
||||
|
||||
feat: 新增支持tabs在swiper中使用 |
||||
|
||||
feat: 新增FormItem支持独立设置验证规则rules |
||||
|
||||
fix: 修复index-list未设置$slots.header时索引高亮失效 |
||||
|
||||
## 3.3.10(2024-08-02) |
||||
fix: 修复index-list偶发的滑动最后一个索引报错top不存在 |
||||
|
||||
fix: 修复gird在QQ、抖音小程序下布局 |
||||
|
||||
feat: 优化step支持自定义样式prop |
||||
|
||||
feat: action-sheet组件支持v-model:show双向绑定 |
||||
|
||||
fix: 小程序下steps和grid都统一采用grid布局 |
||||
|
||||
fix: 修复支付宝小程序下input类型为数字时双向绑定失效 |
||||
|
||||
feat : form 表单 validate 校验不通过后 error增加字段prop信息 #304 |
||||
|
||||
fix: form组件异步校异常验问题 #393 |
||||
|
||||
## 3.3.9(2024-08-01) |
||||
fix: 优化获取nvue元素 |
||||
|
||||
feat: modal新增contentTextAlign设置文案对齐方式 |
||||
|
||||
fix: 修复NVUE下tabbar文字不显示 #458 |
||||
|
||||
feat: loading-page增加zIndex属性 |
||||
|
||||
fix: 相册在宽度较小时换行问题 |
||||
|
||||
feat: album相册增加自适应自动换行模式 |
||||
|
||||
feat: album相册增加图片尺寸单位prop |
||||
|
||||
fix: 修复calendar日历月份居中 |
||||
|
||||
## 3.3.8(2024-07-31) |
||||
feat: slider支持进度条任意位置触发按钮拖动 |
||||
|
||||
fix: 修复app-vue下modal标题不居中 |
||||
|
||||
fix: #459 TS setConfig 声明异常 |
||||
|
||||
feat: tabs组件增加longPress长按事件 |
||||
|
||||
feat: 新增showRight属性控制collapse右侧图标显隐 |
||||
|
||||
fix: 优化nvue下css警告 |
||||
|
||||
## 3.3.7(2024-07-29) |
||||
feat: 支持IndexList组件支持在弹窗等场景下使用及联动优化 |
||||
|
||||
feat: popup组件支持v-model:show双向绑定 |
||||
|
||||
feat: 优化tabs的current双向绑定 |
||||
|
||||
fix: checkbox独立使用时checked赋初始值可以,但是手动切换时值没有做双向绑定! #455 |
||||
|
||||
feat: slider组件支持区间双滑块 |
||||
|
||||
fix: toast 支持自定义图标?可传入了决对路径的 icon也没有用 #409 |
||||
|
||||
feat: form-item校验失败时 增加class方便自定义显示错误的展示方式 #394 |
||||
|
||||
fix: up-cell的required配置不生效 #395 |
||||
|
||||
fix: 横向滚动组件,微信小程序编译后会有警告 #415 |
||||
|
||||
fix: u-picker内部对默认值defaultIndex的监听 #425 |
||||
|
||||
feat: toast 组件支持遮掩层穿透 #417 |
||||
|
||||
fix: 兼容vue的slot编译bug #423 |
||||
|
||||
fix: upload 微信小程序 点击预览视频报错 #424 |
||||
|
||||
fix: u-number-box 组件修改【integer, decimalLength, min, max 】props时没有触发绑定值更新 #429 |
||||
|
||||
feat: Tabs组件能否支持自定义插槽 #439 |
||||
|
||||
feat: ActionSheet 可以配置最大高度吗, 我当做select使用了。 #445 |
||||
|
||||
fix: cursor-pointer优化 |
||||
|
||||
feat: 新版slider组件兼容NVUE改造 |
||||
|
||||
feat: 新增slider组件手动实现以支持样式自定义 |
||||
|
||||
perf:补充TS声明提示信息 |
||||
|
||||
修复:ActionSheet 操作菜单cancelText属性为空DOM节点还存在并且可以点击问题 |
||||
|
||||
fix: 去除预留的beforeDestroy兼容容易在某些sdk下不识别条件编译 |
||||
|
||||
## 3.3.6(2024-07-23) |
||||
feat: u-album组件添加radius,shape参数,定义参考当前u-image参数 |
||||
|
||||
fix: 修复了calendar组件title和日期title未垂直居中的问题 |
||||
|
||||
fix: update:modelValue缺失emit定义 |
||||
|
||||
## 3.3.5(2024-07-10) |
||||
picker组件支持hasInput模式 |
||||
|
||||
## 3.3.4(2024-07-07) |
||||
fix: input组件双向绑定问题 #419 |
||||
|
||||
lazy-load完善emit |
||||
|
||||
优化通用小程序分享 |
||||
|
||||
## 3.3.2(2024-06-27) |
||||
fix: 在Nvue环境中编译,出现大量警告 #406 |
||||
## 3.3.1(2024-06-27) |
||||
u-button组件报错,找不到button mixins #407 |
||||
## 3.3.0(2024-06-27) |
||||
feat: checkbox支持label设置slot |
||||
|
||||
feat: modal增加customClass |
||||
|
||||
feat: navbar、popup、tabs、text支持customClass |
||||
|
||||
fix: cell组建缺少flex布局 |
||||
|
||||
fix: 修复微信小程序真机调试时快速输入出现文本回退问题 |
||||
|
||||
feat: tag增加默认slot |
||||
|
||||
公共mixin改造为按需导入语法 |
||||
|
||||
refactor: 组件props混入mixin改造为按需导入语法 |
||||
|
||||
fix: u-tabbar 安卓手机点击按钮变蓝问题 #396 |
||||
|
||||
feat: upload组建增加extension属性 |
||||
|
||||
fix: upload组件参数mode添加left |
||||
|
||||
fix: 修复阴影在非nvue时白色背景色不显示 |
||||
|
||||
## 3.2.24(2024-06-11) |
||||
fix: 修复时间选择器confirm事件触发时机导致2次才会触发v-model更新 |
||||
## 3.2.23(2024-05-30) |
||||
fix: #378 H5 u-input 在表单中初始值为空也会触发一次 formValidate(this,"change")事件导致进入页面直接校验了一次 |
||||
|
||||
fix: #373 搜索组件up-search的@clear事件无效 |
||||
|
||||
fix: #372 ActionSheet 组件的取消按钮触发区域太小 |
||||
|
||||
## 3.2.22(2024-05-13) |
||||
上传组件支持微信小程序预览视频 |
||||
|
||||
修复折叠面板右侧箭头不显示 |
||||
|
||||
修复uxp2px |
||||
|
||||
## 3.2.21(2024-05-10) |
||||
fix: loading-icon修复flex布局 |
||||
## 3.2.20(2024-05-10) |
||||
修复瀑布流大小写#355 |
||||
## 3.2.19(2024-05-10) |
||||
去除意外的文件引入 |
||||
## 3.2.18(2024-05-09) |
||||
fix: 349 popup 组件设置 zIndex 属性后,组件渲染异常# |
||||
feat: 搜索框增加adjustPosition属性 |
||||
fix: #331增加u-action-sheet__cancel |
||||
优化mixin兼容性 |
||||
feat: #326 up-list增加下拉刷新功能 |
||||
fix: #319 优化up-tabs参数与定义匹配 |
||||
fix: index-list组件微信小程序端使用自定义导航栏异常 |
||||
fix: #285 pickerimmediateChange 写死为true |
||||
fix: #111 u-scroll-list组件,隐藏指示器后报错, 提示找不到ref |
||||
list增加微信小程序防抖配置 |
||||
|
||||
## 3.2.17(2024-05-08) |
||||
fix: 支付宝小程序二维码渲染 |
||||
## 3.2.16(2024-05-06) |
||||
修复tabs中,当前激活样式的undefined bug |
||||
|
||||
fix: #341u-code 倒计时没结束前退出,再次进入结束后退出界面,再次进入重新开始倒计时bug |
||||
|
||||
受到uni-app内置text样式影响修复 |
||||
|
||||
## 3.2.15(2024-04-28) |
||||
优化时间选择器hasInput模式初始化值 |
||||
## 3.2.14(2024-04-24) |
||||
去除pleaseSetTranspileDependencies |
||||
|
||||
http采用useStore |
||||
|
||||
## 3.2.13(2024-04-22) |
||||
修复modal标题样式 |
||||
|
||||
优化日期选择器hasInput模式宽度 |
||||
|
||||
## 3.2.12(2024-04-22) |
||||
修复color应用 |
||||
## 3.2.11(2024-04-18) |
||||
修复import化带来的问题 |
||||
## 3.2.10(2024-04-17) |
||||
完善input清空事件App端失效的兼容性 |
||||
|
||||
修复日历组件二次打开后当前月份显示不正确 |
||||
|
||||
## 3.2.9(2024-04-16) |
||||
组件内uni.$u用法改为import引入 |
||||
|
||||
规范化及兼容性增强 |
||||
|
||||
## 3.2.8(2024-04-15) |
||||
修复up-tag语法错 |
||||
## 3.2.7(2024-04-15) |
||||
修复下拉菜单背景色在支付宝小程序无效 |
||||
|
||||
setConfig改为浅拷贝解决无法用import导入代替uni.$u.props设置 |
||||
|
||||
## 3.2.6(2024-04-14) |
||||
修复某些情况下滑动单元格默认右侧按钮是展开的问题 |
||||
## 3.2.5(2024-04-13) |
||||
调整分段器尺寸及修复窗口大小改变时重新计算尺寸 |
||||
|
||||
多个组件支持cursor-pointer增强PC端体验 |
||||
|
||||
## 3.2.4(2024-04-12) |
||||
初步支持typescript |
||||
## 3.2.3(2024-04-12) |
||||
fix: 修复square属性在小程序下无效问题 |
||||
|
||||
fix:修复lastIndex异常导致的column异常问题 |
||||
|
||||
fix: alipayapp picker style |
||||
|
||||
feat(button): 添加用户同意隐私协议事件回调 |
||||
|
||||
fix: input switch password |
||||
|
||||
fix: 修复u-code组件keepRuning失效问题 |
||||
|
||||
feat: form-item添加labelPosition属性 |
||||
|
||||
新增dropdown组件 |
||||
|
||||
分段器支持内部current值 |
||||
|
||||
优化cell和action-sheet视觉大小 |
||||
|
||||
修复tabs文字换行 |
||||
|
||||
## 3.2.2(2024-04-11) |
||||
修复换行符问题 |
||||
## 3.2.1(2024-04-11) |
||||
修复演示H5二维码 |
||||
|
||||
fix: #270 ReadMore 展开阅读更多内容变化兼容 |
||||
|
||||
fix: #238Calendar组件maxDate修改为不能小于minDate |
||||
|
||||
checkbox支持独立使用 |
||||
|
||||
修复popup中在微信小程序中真机调试滚动失效 |
||||
|
||||
## 3.2.0(2024-04-10) |
||||
修复轮播图在nvue显示 |
||||
修复疑似u-slider名称被占用导致slider在App下不显示 |
||||
解决微信小程序提示 Some selectors are not allowed in component wxss |
||||
示例中u-前缀统一为up- |
||||
增加瀑布流与图片懒加载组件 |
||||
fix: #308修复tag组件缺失iconColor参数 |
||||
fix: #297使用grid布局解决目前编译为抖音小程序无法开启virtualHost |
||||
## 3.1.52(2024-04-07) |
||||
工具类方法调用import化改造 |
||||
新增up-copy复制组件 |
||||
## 3.1.51(2024-04-07) |
||||
优化时间选择器自带输入框格式化显示 |
||||
防止按钮文字换行 |
||||
修复订单列表模板滑动 |
||||
增加u-qrcode二维码组件 |
||||
## 3.1.49(2024-03-27) |
||||
日期时间组件支持自带输入框 |
||||
fix: popup弹窗滚动穿透问题 |
||||
fix: 修复小程序numberbox bug |
||||
## 3.1.48(2024-03-18) |
||||
fix:[plugin:uni:pre-css] Unbalanced delimiter found in string |
||||
## 3.1.47(2024-03-18) |
||||
fix: setConfig设置组件默认参数无效问题 |
||||
fix: 修复自定义图标无效问题 |
||||
feat: 增加u-form-item单独设置规则变量 |
||||
fix:#293小程序是自定义导航栏的时候即传了customNavHeight的时候会出现跳转偏移的情况 |
||||
|
||||
## 3.1.46(2024-01-29) |
||||
beforeUnmount |
||||
## 3.1.45(2024-01-24) |
||||
fix: #262ext组件为超链接的情况下size属性不生效 |
||||
fix: #263最新版本3.1.42中微信小程序u-swipe-action-item报错 |
||||
fix: #224最新版本3.1.42中微信小程序u-swipe-action-item报错 |
||||
fix: #263支持支付宝小程序 |
||||
fix: #261u-input在直接修改v-model的绑定值时,每隔一次会无法出发change事件 |
||||
优化折叠面板兼容微信小程序 |
||||
## 3.1.42(2024-01-15) |
||||
修复u-number-box默认值0时在小程序不显示值 |
||||
优化u-code的timer判断 |
||||
优化支付宝小程序下textarea字数统计兼容 |
||||
优化u-calendar |
||||
## 3.1.41(2023-11-18) |
||||
#215优化u-cell图标容器间距问题 |
||||
## 3.1.40(2023-11-16) |
||||
修复u-slider双向绑定 |
||||
## 3.1.39(2023-11-10) |
||||
修复头条小程序不支持env(safe-area-inset-bottom) |
||||
优化#201u-grid 指定列数导致闪烁 |
||||
#193IndexList 索引列表 高度错误 |
||||
其他优化 |
||||
## 3.1.38(2023-10-08) |
||||
修复u-slider |
||||
## 3.1.37(2023-09-13) |
||||
完善emits定义及修复code-input双向数据绑定 |
||||
## 3.1.36(2023-08-08) |
||||
修复富文本事件名称大小写 |
||||
## 3.1.35(2023-08-02) |
||||
修复编译到支付宝小程序u-form报错 |
||||
## 3.1.34(2023-07-27) |
||||
修复App打包uni.$u.mpMixin方式sdk暂时不支持导致报错 |
||||
## 3.1.33(2023-07-13) |
||||
修复弹窗进入动画、模板页面样式等 |
||||
## 3.1.31(2023-07-11) |
||||
修复dayjs引用 |
||||
## 3.0.8(2022-07-12) |
||||
修复u-tag默认宽度撑满容器 |
||||
## 3.0.7(2022-07-12) |
||||
修复u-navbar自定义插槽演示示例 |
||||
## 3.0.6(2022-07-11) |
||||
修复u-image缺少emits申明 |
||||
## 3.0.5(2022-07-11) |
||||
修复u-upload缺少emits申明 |
||||
## 3.0.4(2022-07-10) |
||||
修复u-textarea/u-input/u-datetime-picker/u-number-box/u-radio-group/u-switch/u-rate在vue3下数据绑定 |
||||
## 3.0.3(2022-07-09) |
||||
启用自建演示二维码 |
||||
## 3.0.2(2022-07-09) |
||||
修复dayjs/clipboard等导致打包报错 |
||||
## 3.0.1(2022-07-09) |
||||
增加插件市场地址 |
||||
## 3.0.0(2022-07-09) |
||||
# uview-plus(vue3)初步发布 |
@ -0,0 +1,85 @@ |
||||
<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'; |
||||
import { mpMixin } from '../../libs/mixin/mpMixin'; |
||||
import { mixin } from '../../libs/mixin/mixin'; |
||||
export default { |
||||
// #ifdef MP-WEIXIN |
||||
name: 'u-form', |
||||
// #endif |
||||
// #ifndef MP-WEIXIN |
||||
name: 'u--form', |
||||
// #endif |
||||
mixins: [mpMixin, props, mixin], |
||||
components: { |
||||
uvForm |
||||
}, |
||||
created() { |
||||
this.children = [] |
||||
}, |
||||
methods: { |
||||
// 手动设置校验的规则,如果规则中有函数的话,微信小程序中会过滤掉,所以只能手动调用设置规则 |
||||
setRules(rules) { |
||||
this.$refs.uForm.setRules(rules) |
||||
}, |
||||
/** |
||||
* 校验全部数据 |
||||
* @param {Object} options |
||||
* @param {Boolean} options.showErrorMsg -是否显示校验信息, |
||||
*/ |
||||
validate(options) { |
||||
/** |
||||
* 在微信小程序中,通过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(options) |
||||
}, |
||||
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> |
@ -0,0 +1,50 @@ |
||||
<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'; |
||||
import { mpMixin } from '../../libs/mixin/mpMixin'; |
||||
import { mixin } from '../../libs/mixin/mixin'; |
||||
export default { |
||||
name: 'u--image', |
||||
mixins: [mpMixin, props, mixin], |
||||
components: { |
||||
uvImage |
||||
}, |
||||
emits: ['click', 'error', 'load'] |
||||
} |
||||
</script> |
@ -0,0 +1,74 @@ |
||||
<template> |
||||
<uvInput |
||||
<!-- #ifdef VUE2 --> |
||||
:value="value" |
||||
@input="e => $emit('input', e)" |
||||
<!-- #endif --> |
||||
<!-- #ifdef VUE3 --> |
||||
:modelValue="modelValue" |
||||
@update:modelValue="e => $emit('update:modelValue', e)" |
||||
<!-- #endif --> |
||||
: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" |
||||
> |
||||
<!-- #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'; |
||||
import { mpMixin } from '../../libs/mixin/mpMixin'; |
||||
import { mixin } from '../../libs/mixin/mixin'; |
||||
export default { |
||||
name: 'u--input', |
||||
mixins: [mpMixin, props, mixin], |
||||
components: { |
||||
uvInput |
||||
}, |
||||
} |
||||
</script> |
@ -0,0 +1,45 @@ |
||||
<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" |
||||
></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"; |
||||
import { mpMixin } from '../../libs/mixin/mpMixin.js' |
||||
import { mixin } from '../../libs/mixin/mixin.js' |
||||
export default { |
||||
name: "u--text", |
||||
mixins: [mpMixin, mixin, props,], |
||||
components: { |
||||
uvText, |
||||
}, |
||||
}; |
||||
</script> |
@ -0,0 +1,47 @@ |
||||
<template> |
||||
<uvTextarea |
||||
:value="value" |
||||
:modelValue="modelValue" |
||||
: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" |
||||
@input="e => $emit('input', e)" |
||||
@update:modelValue="e => $emit('update:modelValue', e)" |
||||
></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'; |
||||
import { mpMixin } from '../../libs/mixin/mpMixin'; |
||||
import { mixin } from '../../libs/mixin/mixin'; |
||||
export default { |
||||
name: 'u--textarea', |
||||
mixins: [mpMixin, props, mixin], |
||||
components: { |
||||
uvTextarea |
||||
}, |
||||
} |
||||
</script> |
@ -0,0 +1,109 @@ |
||||
<template> |
||||
<view class="u-action-sheet-data"> |
||||
<view class="u-action-sheet-data__trigger"> |
||||
<slot name="trigger"></slot> |
||||
<up-input |
||||
v-if="!$slots['trigger']" |
||||
:modelValue="current" |
||||
disabled |
||||
disabledColor="#ffffff" |
||||
:placeholder="title" |
||||
border="none" |
||||
></up-input> |
||||
<view @click="show = true" |
||||
class="u-action-sheet-data__trigger__cover"></view> |
||||
</view> |
||||
<up-action-sheet |
||||
:show="show" |
||||
:actions="options" |
||||
:title="title" |
||||
safeAreaInsetBottom |
||||
:description="description" |
||||
@close="show = false" |
||||
@select="select" |
||||
> |
||||
</up-action-sheet> |
||||
</view> |
||||
</template> |
||||
|
||||
<script> |
||||
export default { |
||||
props: { |
||||
modelValue: { |
||||
type: [String, Number], |
||||
default: '' |
||||
}, |
||||
title: { |
||||
type: String, |
||||
default: '' |
||||
}, |
||||
description: { |
||||
type: String, |
||||
default: '' |
||||
}, |
||||
options: { |
||||
type: Array, |
||||
default: () => { |
||||
return [] |
||||
} |
||||
}, |
||||
valueKey: { |
||||
type: String, |
||||
default: 'value' |
||||
}, |
||||
labelKey: { |
||||
type: String, |
||||
default: 'name' |
||||
} |
||||
}, |
||||
data() { |
||||
return { |
||||
show: false, |
||||
current: '', |
||||
} |
||||
}, |
||||
created() { |
||||
if (this.modelValue) { |
||||
this.options.forEach((ele) => { |
||||
if (ele[this.valueKey] == this.modelValue) { |
||||
this.current = ele[this.labelKey] |
||||
} |
||||
}) |
||||
} |
||||
}, |
||||
emits: ['update:modelValue'], |
||||
watch: { |
||||
modelValue() { |
||||
this.options.forEach((ele) => { |
||||
if (ele[this.valueKey] == this.modelValue) { |
||||
this.current = ele[this.labelKey] |
||||
} |
||||
}) |
||||
} |
||||
}, |
||||
methods: { |
||||
hideKeyboard() { |
||||
uni.hideKeyboard() |
||||
}, |
||||
select(e) { |
||||
this.$emit('update:modelValue', e[this.valueKey]) |
||||
this.current = e[this.labelKey] |
||||
}, |
||||
} |
||||
} |
||||
</script> |
||||
|
||||
<style lang="scss" scoped> |
||||
.u-action-sheet-data { |
||||
&__trigger { |
||||
position: relative; |
||||
&__cover { |
||||
position: absolute; |
||||
top: 0; |
||||
left: 0; |
||||
right: 0; |
||||
bottom: 0; |
||||
} |
||||
} |
||||
} |
||||
</style> |
@ -0,0 +1,26 @@ |
||||
/* |
||||
* @Author : LQ |
||||
* @Description : |
||||
* @version : 1.0 |
||||
* @Date : 2021-08-20 16:44:21 |
||||
* @LastAuthor : LQ |
||||
* @lastTime : 2021-08-20 16:44:35 |
||||
* @FilePath : /u-view2.0/uview-ui/libs/config/props/actionSheet.js |
||||
*/ |
||||
export default { |
||||
// action-sheet组件
|
||||
actionSheet: { |
||||
show: false, |
||||
title: '', |
||||
description: '', |
||||
actions: [], |
||||
index: '', |
||||
cancelText: '', |
||||
closeOnClickAction: true, |
||||
safeAreaInsetBottom: true, |
||||
openType: '', |
||||
closeOnClickOverlay: true, |
||||
round: 0, |
||||
wrapMaxHeight: '600px' |
||||
} |
||||
} |
@ -0,0 +1,62 @@ |
||||
import { defineMixin } from '../../libs/vue' |
||||
import defProps from '../../libs/config/props.js' |
||||
|
||||
export const props = defineMixin({ |
||||
props: { |
||||
// 操作菜单是否展示 (默认false)
|
||||
show: { |
||||
type: Boolean, |
||||
default: () => defProps.actionSheet.show |
||||
}, |
||||
// 标题
|
||||
title: { |
||||
type: String, |
||||
default: () => defProps.actionSheet.title |
||||
}, |
||||
// 选项上方的描述信息
|
||||
description: { |
||||
type: String, |
||||
default: () => defProps.actionSheet.description |
||||
}, |
||||
// 数据
|
||||
actions: { |
||||
type: Array, |
||||
default: () => defProps.actionSheet.actions |
||||
}, |
||||
// 取消按钮的文字,不为空时显示按钮
|
||||
cancelText: { |
||||
type: String, |
||||
default: () => defProps.actionSheet.cancelText |
||||
}, |
||||
// 点击某个菜单项时是否关闭弹窗
|
||||
closeOnClickAction: { |
||||
type: Boolean, |
||||
default: () => defProps.actionSheet.closeOnClickAction |
||||
}, |
||||
// 处理底部安全区(默认true)
|
||||
safeAreaInsetBottom: { |
||||
type: Boolean, |
||||
default: () => defProps.actionSheet.safeAreaInsetBottom |
||||
}, |
||||
// 小程序的打开方式
|
||||
openType: { |
||||
type: String, |
||||
default: () => defProps.actionSheet.openType |
||||
}, |
||||
// 点击遮罩是否允许关闭 (默认true)
|
||||
closeOnClickOverlay: { |
||||
type: Boolean, |
||||
default: () => defProps.actionSheet.closeOnClickOverlay |
||||
}, |
||||
// 圆角值
|
||||
round: { |
||||
type: [Boolean, String, Number], |
||||
default: () => defProps.actionSheet.round |
||||
}, |
||||
// 选项区域最大高度
|
||||
wrapMaxHeight: { |
||||
type: [String], |
||||
default: () => defProps.actionSheet.wrapMaxHeight |
||||
}, |
||||
} |
||||
}) |
@ -0,0 +1,282 @@ |
||||
|
||||
<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> |
||||
<scroll-view scroll-y class="u-action-sheet__item-wrap" :style="{maxHeight: wrapMaxHeight}"> |
||||
<view :key="index" v-for="(item, index) in actions"> |
||||
<!-- #ifdef MP --> |
||||
<button |
||||
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> |
||||
</view> |
||||
</scroll-view> |
||||
</slot> |
||||
<u-gap |
||||
bgColor="#eaeaec" |
||||
height="6" |
||||
v-if="cancelText" |
||||
></u-gap> |
||||
<view class="u-action-sheet__item-wrap__item u-action-sheet__cancel" |
||||
hover-class="u-action-sheet--hover" @tap="cancel" v-if="cancelText"> |
||||
<text |
||||
@touchmove.stop.prevent |
||||
:hover-stay-time="150" |
||||
class="u-action-sheet__cancel-text" |
||||
>{{cancelText}}</text> |
||||
</view> |
||||
</view> |
||||
</u-popup> |
||||
</template> |
||||
|
||||
<script> |
||||
import { openType } from '../../libs/mixin/openType' |
||||
import { buttonMixin } from '../../libs/mixin/button' |
||||
import { props } from './props'; |
||||
import { mpMixin } from '../../libs/mixin/mpMixin'; |
||||
import { mixin } from '../../libs/mixin/mixin'; |
||||
import { addUnit } from '../../libs/function/index'; |
||||
/** |
||||
* ActionSheet 操作菜单 |
||||
* @description 本组件用于从底部弹出一个操作菜单,供用户选择并返回结果。本组件功能类似于uni的uni.showActionSheetAPI,配置更加灵活,所有平台都表现一致。 |
||||
* @tutorial https://ijry.github.io/uview-plus/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, buttonMixin, 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 = addUnit(this.actions[index].fontSize) |
||||
// 选项被禁用的样式 |
||||
if (this.actions[index].disabled) style.color = '#c0c4cc' |
||||
return style; |
||||
} |
||||
}, |
||||
}, |
||||
emits: ["close", "select", "update:show"], |
||||
methods: { |
||||
closeHandler() { |
||||
// 允许点击遮罩关闭时,才发出close事件 |
||||
if(this.closeOnClickOverlay) { |
||||
this.$emit('update:show', false) |
||||
this.$emit('close') |
||||
} |
||||
}, |
||||
// 点击取消按钮 |
||||
cancel() { |
||||
this.$emit('update:show', false) |
||||
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('update:show', false) |
||||
this.$emit('close') |
||||
} |
||||
} |
||||
}, |
||||
} |
||||
} |
||||
</script> |
||||
|
||||
<style lang="scss" scoped> |
||||
$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:17px !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> |
@ -0,0 +1,28 @@ |
||||
/* |
||||
* @Author : LQ |
||||
* @Description : |
||||
* @version : 1.0 |
||||
* @Date : 2021-08-20 16:44:21 |
||||
* @LastAuthor : LQ |
||||
* @lastTime : 2021-08-20 16:47:24 |
||||
* @FilePath : /u-view2.0/uview-ui/libs/config/props/album.js |
||||
*/ |
||||
export default { |
||||
// album 组件
|
||||
album: { |
||||
urls: [], |
||||
keyName: '', |
||||
singleSize: 180, |
||||
multipleSize: 70, |
||||
space: 6, |
||||
singleMode: 'scaleToFill', |
||||
multipleMode: 'aspectFill', |
||||
maxCount: 9, |
||||
previewFullImage: true, |
||||
rowCount: 3, |
||||
showMore: true, |
||||
autoWrap: false, |
||||
unit: 'px', |
||||
stop: true, |
||||
} |
||||
} |
@ -0,0 +1,86 @@ |
||||
import { defineMixin } from '../../libs/vue' |
||||
import defProps from '../../libs/config/props.js' |
||||
export const props = defineMixin({ |
||||
props: { |
||||
// 图片地址,Array<String>|Array<Object>形式
|
||||
urls: { |
||||
type: Array, |
||||
default: () => defProps.album.urls |
||||
}, |
||||
// 指定从数组的对象元素中读取哪个属性作为图片地址
|
||||
keyName: { |
||||
type: String, |
||||
default: () => defProps.album.keyName |
||||
}, |
||||
// 单图时,图片长边的长度
|
||||
singleSize: { |
||||
type: [String, Number], |
||||
default: () => defProps.album.singleSize |
||||
}, |
||||
// 多图时,图片边长
|
||||
multipleSize: { |
||||
type: [String, Number], |
||||
default: () => defProps.album.multipleSize |
||||
}, |
||||
// 多图时,图片水平和垂直之间的间隔
|
||||
space: { |
||||
type: [String, Number], |
||||
default: () => defProps.album.space |
||||
}, |
||||
// 单图时,图片缩放裁剪的模式
|
||||
singleMode: { |
||||
type: String, |
||||
default: () => defProps.album.singleMode |
||||
}, |
||||
// 多图时,图片缩放裁剪的模式
|
||||
multipleMode: { |
||||
type: String, |
||||
default: () => defProps.album.multipleMode |
||||
}, |
||||
// 最多展示的图片数量,超出时最后一个位置将会显示剩余图片数量
|
||||
maxCount: { |
||||
type: [String, Number], |
||||
default: () => defProps.album.maxCount |
||||
}, |
||||
// 是否可以预览图片
|
||||
previewFullImage: { |
||||
type: Boolean, |
||||
default: () => defProps.album.previewFullImage |
||||
}, |
||||
// 每行展示图片数量,如设置,singleSize和multipleSize将会无效
|
||||
rowCount: { |
||||
type: [String, Number], |
||||
default: () => defProps.album.rowCount |
||||
}, |
||||
// 超出maxCount时是否显示查看更多的提示
|
||||
showMore: { |
||||
type: Boolean, |
||||
default: () => defProps.album.showMore |
||||
}, |
||||
// 图片形状,circle-圆形,square-方形
|
||||
shape: { |
||||
type: String, |
||||
default: () => defProps.image.shape |
||||
}, |
||||
// 圆角,单位任意
|
||||
radius: { |
||||
type: [String, Number], |
||||
default: () => defProps.image.radius |
||||
}, |
||||
// 自适应换行
|
||||
autoWrap: { |
||||
type: Boolean, |
||||
default: () => defProps.album.autoWrap |
||||
}, |
||||
// 单位
|
||||
unit: { |
||||
type: [String], |
||||
default: () => defProps.album.unit |
||||
}, |
||||
// 阻止点击冒泡
|
||||
stop: { |
||||
type: Boolean, |
||||
default: () => defProps.album.stop |
||||
} |
||||
} |
||||
}) |
@ -0,0 +1,300 @@ |
||||
<template> |
||||
<view class="u-album"> |
||||
<view |
||||
class="u-album__row" |
||||
ref="u-album__row" |
||||
v-for="(arr, index) in showUrls" |
||||
:forComputedUse="albumWidth" |
||||
:key="index" |
||||
:style="{flexWrap: autoWrap ? 'wrap' : 'nowrap'}" |
||||
> |
||||
<view |
||||
class="u-album__row__wrapper" |
||||
v-for="(item, index1) in arr" |
||||
:key="index1" |
||||
:style="[imageStyle(index + 1, index1 + 1)]" |
||||
@tap="onPreviewTap($event, getSrc(item))" |
||||
> |
||||
<image |
||||
:src="getSrc(item)" |
||||
:mode=" |
||||
urls.length === 1 |
||||
? imageHeight > 0 |
||||
? singleMode |
||||
: 'widthFix' |
||||
: multipleMode |
||||
" |
||||
:style="[ |
||||
{ |
||||
width: imageWidth, |
||||
height: imageHeight, |
||||
borderRadius: shape == 'circle' ? '10000px' : addUnit(radius) |
||||
} |
||||
]" |
||||
></image> |
||||
<view |
||||
v-if=" |
||||
showMore && |
||||
urls.length > rowCount * showUrls.length && |
||||
index === showUrls.length - 1 && |
||||
index1 === showUrls[showUrls.length - 1].length - 1 |
||||
" |
||||
class="u-album__row__wrapper__text" |
||||
:style="{ |
||||
borderRadius: shape == 'circle' ? '50%' : addUnit(radius), |
||||
}" |
||||
> |
||||
<up-text |
||||
:text="`+${urls.length - maxCount}`" |
||||
color="#fff" |
||||
:size="multipleSize * 0.3" |
||||
align="center" |
||||
customStyle="justify-content: center" |
||||
></up-text> |
||||
</view> |
||||
</view> |
||||
</view> |
||||
</view> |
||||
</template> |
||||
|
||||
<script> |
||||
import { props } from './props'; |
||||
import { mpMixin } from '../../libs/mixin/mpMixin'; |
||||
import { mixin } from '../../libs/mixin/mixin'; |
||||
import { addUnit, sleep } from '../../libs/function/index'; |
||||
import test from '../../libs/function/test'; |
||||
// #ifdef APP-NVUE |
||||
// 由于weex为阿里的KPI业绩考核的产物,所以不支持百分比单位,这里需要通过dom查询组件的宽度 |
||||
const dom = uni.requireNativePlugin('dom') |
||||
// #endif |
||||
|
||||
/** |
||||
* Album 相册 |
||||
* @description 本组件提供一个类似相册的功能,让开发者开发起来更加得心应手。减少重复的模板代码 |
||||
* @tutorial https://ijry.github.io/uview-plus/components/album.html |
||||
* |
||||
* @property {Array} urls 图片地址列表 Array<String>|Array<Object>形式 |
||||
* @property {String} keyName 指定从数组的对象元素中读取哪个属性作为图片地址 |
||||
* @property {String | Number} singleSize 单图时,图片长边的长度 (默认 180 ) |
||||
* @property {String | Number} multipleSize 多图时,图片边长 (默认 70 ) |
||||
* @property {String | Number} space 多图时,图片水平和垂直之间的间隔 (默认 6 ) |
||||
* @property {String} singleMode 单图时,图片缩放裁剪的模式 (默认 'scaleToFill' ) |
||||
* @property {String} multipleMode 多图时,图片缩放裁剪的模式 (默认 'aspectFill' ) |
||||
* @property {String | Number} maxCount 取消按钮的提示文字 (默认 9 ) |
||||
* @property {Boolean} previewFullImage 是否可以预览图片 (默认 true ) |
||||
* @property {String | Number} rowCount 每行展示图片数量,如设置,singleSize和multipleSize将会无效 (默认 3 ) |
||||
* @property {Boolean} showMore 超出maxCount时是否显示查看更多的提示 (默认 true ) |
||||
* @property {String} shape 图片形状,circle-圆形,square-方形 (默认 'square' ) |
||||
* @property {String | Number} radius 圆角值,单位任意,如果为数值,则为px单位 (默认 0 ) |
||||
* @property {Boolean} autoWrap 自适应换行模式,不受rowCount限制,图片会自动换行 (默认 false ) |
||||
* @property {String} unit 图片单位 (默认 px ) |
||||
* @event {Function} albumWidth 某些特殊的情况下,需要让文字与相册的宽度相等,这里事件的形式对外发送 (回调参数 width ) |
||||
* @example <u-album :urls="urls2" @albumWidth="width => albumWidth = width" multipleSize="68" ></u-album> |
||||
*/ |
||||
export default { |
||||
name: 'u-album', |
||||
mixins: [mpMixin, mixin, props], |
||||
data() { |
||||
return { |
||||
// 单图的宽度 |
||||
singleWidth: 0, |
||||
// 单图的高度 |
||||
singleHeight: 0, |
||||
// 单图时,如果无法获取图片的尺寸信息,让图片宽度默认为容器的一定百分比 |
||||
singlePercent: 0.6 |
||||
} |
||||
}, |
||||
watch: { |
||||
urls: { |
||||
immediate: true, |
||||
handler(newVal) { |
||||
if (newVal.length === 1) { |
||||
this.getImageRect() |
||||
} |
||||
} |
||||
} |
||||
}, |
||||
emits: ["albumWidth"], |
||||
computed: { |
||||
imageStyle() { |
||||
return (index1, index2) => { |
||||
const { space, rowCount, multipleSize, urls } = this, |
||||
rowLen = this.showUrls.length, |
||||
allLen = this.urls.length |
||||
const style = { |
||||
marginRight: addUnit(space), |
||||
marginBottom: addUnit(space) |
||||
} |
||||
// 如果为最后一行,则每个图片都无需下边框 |
||||
if (index1 === rowLen && !this.autoWrap) style.marginBottom = 0 |
||||
// 每行的最右边一张和总长度的最后一张无需右边框 |
||||
if (!this.autoWrap) { |
||||
if ( |
||||
index2 === rowCount || |
||||
(index1 === rowLen && |
||||
index2 === this.showUrls[index1 - 1].length) |
||||
) |
||||
style.marginRight = 0 |
||||
} |
||||
return style |
||||
} |
||||
}, |
||||
// 将数组划分为二维数组 |
||||
showUrls() { |
||||
if (this.autoWrap) { |
||||
return [ this.urls.slice(0, this.maxCount) ]; |
||||
} else { |
||||
const arr = [] |
||||
this.urls.map((item, index) => { |
||||
// 限制最大展示数量 |
||||
if (index + 1 <= this.maxCount) { |
||||
// 计算该元素为第几个素组内 |
||||
const itemIndex = Math.floor(index / this.rowCount) |
||||
// 判断对应的索引是否存在 |
||||
if (!arr[itemIndex]) { |
||||
arr[itemIndex] = [] |
||||
} |
||||
arr[itemIndex].push(item) |
||||
} |
||||
}) |
||||
return arr |
||||
} |
||||
}, |
||||
imageWidth() { |
||||
return addUnit( |
||||
this.urls.length === 1 ? this.singleWidth : this.multipleSize, this.unit |
||||
) |
||||
}, |
||||
imageHeight() { |
||||
return addUnit( |
||||
this.urls.length === 1 ? this.singleHeight : this.multipleSize, this.unit |
||||
) |
||||
}, |
||||
// 此变量无实际用途,仅仅是为了利用computed特性,让其在urls长度等变化时,重新计算图片的宽度 |
||||
// 因为用户在某些特殊的情况下,需要让文字与相册的宽度相等,所以这里事件的形式对外发送 |
||||
albumWidth() { |
||||
let width = 0 |
||||
if (this.urls.length === 1) { |
||||
width = this.singleWidth |
||||
} else { |
||||
width = |
||||
this.showUrls[0].length * this.multipleSize + |
||||
this.space * (this.showUrls[0].length - 1) |
||||
} |
||||
this.$emit('albumWidth', width) |
||||
return width |
||||
} |
||||
}, |
||||
emits: ['preview', 'albumWidth'], |
||||
methods: { |
||||
addUnit, |
||||
// 预览图片 |
||||
onPreviewTap(e, url) { |
||||
const urls = this.urls.map((item) => { |
||||
return this.getSrc(item) |
||||
}) |
||||
if (this.previewFullImage) { |
||||
uni.previewImage({ |
||||
current: url, |
||||
urls |
||||
}) |
||||
// 是否阻止事件传播 |
||||
this.stop && this.preventEvent(e) |
||||
} else { |
||||
this.$emit('preview', { |
||||
urls, |
||||
currentIndex: urls.indexOf(url) |
||||
}) |
||||
} |
||||
}, |
||||
// 获取图片的路径 |
||||
getSrc(item) { |
||||
return test.object(item) |
||||
? (this.keyName && item[this.keyName]) || item.src |
||||
: item |
||||
}, |
||||
// 单图时,获取图片的尺寸 |
||||
// 在小程序中,需要将网络图片的的域名添加到小程序的download域名才可能获取尺寸 |
||||
// 在没有添加的情况下,让单图宽度默认为盒子的一定宽度(singlePercent) |
||||
getImageRect() { |
||||
const src = this.getSrc(this.urls[0]) |
||||
uni.getImageInfo({ |
||||
src, |
||||
success: (res) => { |
||||
let singleSize = this.singleSize; |
||||
// 单位 |
||||
let unit = ''; |
||||
if (Number.isNaN(Number(this.singleSize))) { |
||||
// 大小中有字符 则记录字符 |
||||
unit = this.singleSize.replace(/\d+/g, ''); // 单位 |
||||
singleSize = Number(this.singleSize.replace(/\D+/g, ''), 10); // 具体值 |
||||
} |
||||
|
||||
// 判断图片横向还是竖向展示方式 |
||||
const isHorizotal = res.width >= res.height |
||||
this.singleWidth = isHorizotal |
||||
? singleSize |
||||
: (res.width / res.height) * singleSize |
||||
this.singleHeight = !isHorizotal |
||||
? singleSize |
||||
: (res.height / res.width) * this.singleWidth |
||||
|
||||
// 如果有单位统一设置单位 |
||||
if(unit != null && unit !== ''){ |
||||
this.singleWidth = this.singleWidth + unit |
||||
this.singleHeight = this.singleHeight + unit |
||||
} |
||||
}, |
||||
fail: () => { |
||||
this.getComponentWidth() |
||||
} |
||||
}) |
||||
}, |
||||
// 获取组件的宽度 |
||||
async getComponentWidth() { |
||||
// 延时一定时间,以获取dom尺寸 |
||||
await sleep(30) |
||||
// #ifndef APP-NVUE |
||||
this.$uGetRect('.u-album__row').then((size) => { |
||||
this.singleWidth = size.width * this.singlePercent |
||||
}) |
||||
// #endif |
||||
|
||||
// #ifdef APP-NVUE |
||||
// 这里ref="u-album__row"所在的标签为通过for循环出来,导致this.$refs['u-album__row']是一个数组 |
||||
const ref = this.$refs['u-album__row'][0] |
||||
ref && |
||||
dom.getComponentRect(ref, (res) => { |
||||
this.singleWidth = res.size.width * this.singlePercent |
||||
}) |
||||
// #endif |
||||
} |
||||
} |
||||
} |
||||
</script> |
||||
|
||||
<style lang="scss" scoped> |
||||
.u-album { |
||||
@include flex(column); |
||||
|
||||
&__row { |
||||
@include flex(row); |
||||
|
||||
&__wrapper { |
||||
position: relative; |
||||
|
||||
&__text { |
||||
position: absolute; |
||||
top: 0; |
||||
left: 0; |
||||
right: 0; |
||||
bottom: 0; |
||||
background-color: rgba(0, 0, 0, 0.3); |
||||
@include flex(row); |
||||
justify-content: center; |
||||
align-items: center; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
</style> |
@ -0,0 +1,22 @@ |
||||
/* |
||||
* @Author : LQ |
||||
* @Description : |
||||
* @version : 1.0 |
||||
* @Date : 2021-08-20 16:44:21 |
||||
* @LastAuthor : LQ |
||||
* @lastTime : 2021-08-20 16:48:53 |
||||
* @FilePath : /u-view2.0/uview-ui/libs/config/props/alert.js |
||||
*/ |
||||
export default { |
||||
// alert警告组件
|
||||
alert: { |
||||
title: '', |
||||
type: 'warning', |
||||
description: '', |
||||
closable: false, |
||||
showIcon: false, |
||||
effect: 'light', |
||||
center: false, |
||||
fontSize: 14 |
||||
} |
||||
} |
@ -0,0 +1,46 @@ |
||||
import { defineMixin } from '../../libs/vue' |
||||
import defProps from '../../libs/config/props.js' |
||||
export const props = defineMixin({ |
||||
props: { |
||||
// 显示文字
|
||||
title: { |
||||
type: String, |
||||
default: () => defProps.alert.title |
||||
}, |
||||
// 主题,success/warning/info/error
|
||||
type: { |
||||
type: String, |
||||
default: () => defProps.alert.type |
||||
}, |
||||
// 辅助性文字
|
||||
description: { |
||||
type: String, |
||||
default: () => defProps.alert.description |
||||
}, |
||||
// 是否可关闭
|
||||
closable: { |
||||
type: Boolean, |
||||
default: () => defProps.alert.closable |
||||
}, |
||||
// 是否显示图标
|
||||
showIcon: { |
||||
type: Boolean, |
||||
default: () => defProps.alert.showIcon |
||||
}, |
||||
// 浅或深色调,light-浅色,dark-深色
|
||||
effect: { |
||||
type: String, |
||||
default: () => defProps.alert.effect |
||||
}, |
||||
// 文字是否居中
|
||||
center: { |
||||
type: Boolean, |
||||
default: () => defProps.alert.center |
||||
}, |
||||
// 字体大小
|
||||
fontSize: { |
||||
type: [String, Number], |
||||
default: () => defProps.alert.fontSize |
||||
} |
||||
} |
||||
}) |
@ -0,0 +1,250 @@ |
||||
<template> |
||||
<u-transition |
||||
mode="fade" |
||||
:show="show" |
||||
> |
||||
<view |
||||
class="u-alert" |
||||
:class="[`u-alert--${type}--${effect}`]" |
||||
@tap.stop="clickHandler" |
||||
:style="[addStyle(customStyle)]" |
||||
> |
||||
<view |
||||
class="u-alert__icon" |
||||
v-if="showIcon" |
||||
> |
||||
<u-icon |
||||
:name="iconName" |
||||
size="18" |
||||
:color="iconColor" |
||||
></u-icon> |
||||
</view> |
||||
<view |
||||
class="u-alert__content" |
||||
:style="[{ |
||||
paddingRight: closable ? '20px' : 0 |
||||
}]" |
||||
> |
||||
<text |
||||
class="u-alert__content__title" |
||||
v-if="title" |
||||
:style="[{ |
||||
fontSize: addUnit(fontSize), |
||||
textAlign: center ? 'center' : 'left' |
||||
}]" |
||||
:class="[effect === 'dark' ? 'u-alert__text--dark' : `u-alert__text--${type}--light`]" |
||||
>{{ title }}</text> |
||||
<text |
||||
class="u-alert__content__desc" |
||||
v-if="description" |
||||
:style="[{ |
||||
fontSize: addUnit(fontSize), |
||||
textAlign: center ? 'center' : 'left' |
||||
}]" |
||||
:class="[effect === 'dark' ? 'u-alert__text--dark' : `u-alert__text--${type}--light`]" |
||||
>{{ description }}</text> |
||||
</view> |
||||
<view |
||||
class="u-alert__close" |
||||
v-if="closable" |
||||
@tap.stop="closeHandler" |
||||
> |
||||
<u-icon |
||||
name="close" |
||||
:color="iconColor" |
||||
size="15" |
||||
></u-icon> |
||||
</view> |
||||
</view> |
||||
</u-transition> |
||||
</template> |
||||
|
||||
<script> |
||||
import { props } from './props'; |
||||
import { mpMixin } from '../../libs/mixin/mpMixin'; |
||||
import { mixin } from '../../libs/mixin/mixin'; |
||||
import { addUnit, addStyle } from '../../libs/function/index'; |
||||
/** |
||||
* Alert 警告提示 |
||||
* @description 警告提示,展现需要关注的信息。 |
||||
* @tutorial https://ijry.github.io/uview-plus/components/alertTips.html |
||||
* |
||||
* @property {String} title 显示的文字 |
||||
* @property {String} type 使用预设的颜色 (默认 'warning' ) |
||||
* @property {String} description 辅助性文字,颜色比title浅一点,字号也小一点,可选 |
||||
* @property {Boolean} closable 关闭按钮(默认为叉号icon图标) (默认 false ) |
||||
* @property {Boolean} showIcon 是否显示左边的辅助图标 ( 默认 false ) |
||||
* @property {String} effect 多图时,图片缩放裁剪的模式 (默认 'light' ) |
||||
* @property {Boolean} center 文字是否居中 (默认 false ) |
||||
* @property {String | Number} fontSize 字体大小 (默认 14 ) |
||||
* @property {Object} customStyle 定义需要用到的外部样式 |
||||
* @event {Function} click 点击组件时触发 |
||||
* @event {Function} close 点击关闭按钮时触发 |
||||
* @example <u-alert :title="title" type = "warning" :closable="closable" :description = "description"></u-alert> |
||||
*/ |
||||
export default { |
||||
name: 'u-alert', |
||||
mixins: [mpMixin, mixin, props], |
||||
data() { |
||||
return { |
||||
show: true |
||||
} |
||||
}, |
||||
computed: { |
||||
iconColor() { |
||||
return this.effect === 'light' ? this.type : '#fff' |
||||
}, |
||||
// 不同主题对应不同的图标 |
||||
iconName() { |
||||
switch (this.type) { |
||||
case 'success': |
||||
return 'checkmark-circle-fill'; |
||||
break; |
||||
case 'error': |
||||
return 'close-circle-fill'; |
||||
break; |
||||
case 'warning': |
||||
return 'error-circle-fill'; |
||||
break; |
||||
case 'info': |
||||
return 'info-circle-fill'; |
||||
break; |
||||
case 'primary': |
||||
return 'more-circle-fill'; |
||||
break; |
||||
default: |
||||
return 'error-circle-fill'; |
||||
} |
||||
} |
||||
}, |
||||
emits: ["click","close"], |
||||
methods: { |
||||
addUnit, |
||||
addStyle, |
||||
// 点击内容 |
||||
clickHandler() { |
||||
this.$emit('click') |
||||
}, |
||||
// 点击关闭按钮 |
||||
closeHandler() { |
||||
this.show = false |
||||
this.$emit('close') |
||||
} |
||||
} |
||||
} |
||||
</script> |
||||
|
||||
<style lang="scss" scoped> |
||||
|
||||
.u-alert { |
||||
position: relative; |
||||
background-color: $u-primary; |
||||
padding: 8px 10px; |
||||
@include flex(row); |
||||
align-items: center; |
||||
border-top-left-radius: 4px; |
||||
border-top-right-radius: 4px; |
||||
border-bottom-left-radius: 4px; |
||||
border-bottom-right-radius: 4px; |
||||
|
||||
&--primary--dark { |
||||
background-color: $u-primary; |
||||
} |
||||
|
||||
&--primary--light { |
||||
background-color: #ecf5ff; |
||||
} |
||||
|
||||
&--error--dark { |
||||
background-color: $u-error; |
||||
} |
||||
|
||||
&--error--light { |
||||
background-color: #FEF0F0; |
||||
} |
||||
|
||||
&--success--dark { |
||||
background-color: $u-success; |
||||
} |
||||
|
||||
&--success--light { |
||||
background-color: #f5fff0; |
||||
} |
||||
|
||||
&--warning--dark { |
||||
background-color: $u-warning; |
||||
} |
||||
|
||||
&--warning--light { |
||||
background-color: #FDF6EC; |
||||
} |
||||
|
||||
&--info--dark { |
||||
background-color: $u-info; |
||||
} |
||||
|
||||
&--info--light { |
||||
background-color: #f4f4f5; |
||||
} |
||||
|
||||
&__icon { |
||||
margin-right: 5px; |
||||
} |
||||
|
||||
&__content { |
||||
@include flex(column); |
||||
flex: 1; |
||||
|
||||
&__title { |
||||
color: $u-main-color; |
||||
font-size: 14px; |
||||
font-weight: bold; |
||||
color: #fff; |
||||
margin-bottom: 2px; |
||||
} |
||||
|
||||
&__desc { |
||||
color: $u-main-color; |
||||
font-size: 14px; |
||||
flex-wrap: wrap; |
||||
color: #fff; |
||||
} |
||||
} |
||||
|
||||
&__title--dark, |
||||
&__desc--dark { |
||||
color: #FFFFFF; |
||||
} |
||||
|
||||
&__text--primary--light, |
||||
&__text--primary--light { |
||||
color: $u-primary; |
||||
} |
||||
|
||||
&__text--success--light, |
||||
&__text--success--light { |
||||
color: $u-success; |
||||
} |
||||
|
||||
&__text--warning--light, |
||||
&__text--warning--light { |
||||
color: $u-warning; |
||||
} |
||||
|
||||
&__text--error--light, |
||||
&__text--error--light { |
||||
color: $u-error; |
||||
} |
||||
|
||||
&__text--info--light, |
||||
&__text--info--light { |
||||
color: $u-info; |
||||
} |
||||
|
||||
&__close { |
||||
position: absolute; |
||||
top: 11px; |
||||
right: 10px; |
||||
} |
||||
} |
||||
</style> |
@ -0,0 +1,23 @@ |
||||
/* |
||||
* @Author : LQ |
||||
* @Description : |
||||
* @version : 1.0 |
||||
* @Date : 2021-08-20 16:44:21 |
||||
* @LastAuthor : LQ |
||||
* @lastTime : 2021-08-20 16:49:55 |
||||
* @FilePath : /u-view2.0/uview-ui/libs/config/props/avatarGroup.js |
||||
*/ |
||||
export default { |
||||
// avatarGroup 组件
|
||||
avatarGroup: { |
||||
urls: [], |
||||
maxCount: 5, |
||||
shape: 'circle', |
||||
mode: 'scaleToFill', |
||||
showMore: true, |
||||
size: 40, |
||||
keyName: '', |
||||
gap: 0.5, |
||||
extraValue: 0 |
||||
} |
||||
} |
@ -0,0 +1,54 @@ |
||||
import { defineMixin } from '../../libs/vue' |
||||
import defProps from '../../libs/config/props.js' |
||||
export const props = defineMixin({ |
||||
props: { |
||||
// 头像图片组
|
||||
urls: { |
||||
type: Array, |
||||
default: () => defProps.avatarGroup.urls |
||||
}, |
||||
// 最多展示的头像数量
|
||||
maxCount: { |
||||
type: [String, Number], |
||||
default: () => defProps.avatarGroup.maxCount |
||||
}, |
||||
// 头像形状
|
||||
shape: { |
||||
type: String, |
||||
default: () => defProps.avatarGroup.shape |
||||
}, |
||||
// 图片裁剪模式
|
||||
mode: { |
||||
type: String, |
||||
default: () => defProps.avatarGroup.mode |
||||
}, |
||||
// 超出maxCount时是否显示查看更多的提示
|
||||
showMore: { |
||||
type: Boolean, |
||||
default: () => defProps.avatarGroup.showMore |
||||
}, |
||||
// 头像大小
|
||||
size: { |
||||
type: [String, Number], |
||||
default: () => defProps.avatarGroup.size |
||||
}, |
||||
// 指定从数组的对象元素中读取哪个属性作为图片地址
|
||||
keyName: { |
||||
type: String, |
||||
default: () => defProps.avatarGroup.keyName |
||||
}, |
||||
// 头像之间的遮挡比例
|
||||
gap: { |
||||
type: [String, Number], |
||||
validator(value) { |
||||
return value >= 0 && value <= 1 |
||||
}, |
||||
default: () => defProps.avatarGroup.gap |
||||
}, |
||||
// 需额外显示的值
|
||||
extraValue: { |
||||
type: [Number, String], |
||||
default: () => defProps.avatarGroup.extraValue |
||||
} |
||||
} |
||||
}) |
@ -0,0 +1,109 @@ |
||||
<template> |
||||
<view class="u-avatar-group"> |
||||
<view |
||||
class="u-avatar-group__item" |
||||
v-for="(item, index) in showUrl" |
||||
:key="index" |
||||
:style="{ |
||||
marginLeft: index === 0 ? 0 : addUnit(-size * gap) |
||||
}" |
||||
> |
||||
<u-avatar |
||||
:size="size" |
||||
:shape="shape" |
||||
:mode="mode" |
||||
:src="testObject(item) ? keyName && item[keyName] || item.url : item" |
||||
></u-avatar> |
||||
<view |
||||
class="u-avatar-group__item__show-more" |
||||
v-if="showMore && index === showUrl.length - 1 && (urls.length > maxCount || extraValue > 0)" |
||||
@tap="clickHandler" |
||||
> |
||||
<up-text |
||||
color="#ffffff" |
||||
:size="size * 0.4" |
||||
:text="`+${extraValue || urls.length - showUrl.length}`" |
||||
align="center" |
||||
customStyle="justify-content: center" |
||||
></up-text> |
||||
</view> |
||||
</view> |
||||
</view> |
||||
</template> |
||||
|
||||
<script> |
||||
import { props } from './props'; |
||||
import { mpMixin } from '../../libs/mixin/mpMixin'; |
||||
import { mixin } from '../../libs/mixin/mixin'; |
||||
import { addUnit } from '../../libs/function/index'; |
||||
import test from '../../libs/function/test'; |
||||
/** |
||||
* AvatarGroup 头像组 |
||||
* @description 本组件一般用于展示头像的地方,如个人中心,或者评论列表页的用户头像展示等场所。 |
||||
* @tutorial https://ijry.github.io/uview-plus/components/avatar.html |
||||
* |
||||
* @property {Array} urls 头像图片组 (默认 [] ) |
||||
* @property {String | Number} maxCount 最多展示的头像数量 ( 默认 5 ) |
||||
* @property {String} shape 头像形状( 'circle' (默认) | 'square' ) |
||||
* @property {String} mode 图片裁剪模式(默认 'scaleToFill' ) |
||||
* @property {Boolean} showMore 超出maxCount时是否显示查看更多的提示 (默认 true ) |
||||
* @property {String | Number} size 头像大小 (默认 40 ) |
||||
* @property {String} keyName 指定从数组的对象元素中读取哪个属性作为图片地址 |
||||
* @property {String | Number} gap 头像之间的遮挡比例(0.4代表遮挡40%) (默认 0.5 ) |
||||
* @property {String | Number} extraValue 需额外显示的值 |
||||
* @event {Function} showMore 头像组更多点击 |
||||
* @example <u-avatar-group:urls="urls" size="35" gap="0.4" ></u-avatar-group:urls=> |
||||
*/ |
||||
export default { |
||||
name: 'u-avatar-group', |
||||
mixins: [mpMixin, mixin, props], |
||||
data() { |
||||
return { |
||||
|
||||
} |
||||
}, |
||||
computed: { |
||||
showUrl() { |
||||
return this.urls.slice(0, this.maxCount) |
||||
} |
||||
}, |
||||
emits: ["showMore"], |
||||
methods: { |
||||
addUnit, |
||||
testObject: test.object, |
||||
clickHandler() { |
||||
this.$emit('showMore') |
||||
} |
||||
}, |
||||
} |
||||
</script> |
||||
|
||||
<style lang="scss" scoped> |
||||
|
||||
.u-avatar-group { |
||||
@include flex; |
||||
|
||||
&__item { |
||||
margin-left: -10px; |
||||
position: relative; |
||||
|
||||
&--no-indent { |
||||
// 如果你想质疑作者不会使用:first-child,说明你太年轻,因为nvue不支持 |
||||
margin-left: 0; |
||||
} |
||||
|
||||
&__show-more { |
||||
position: absolute; |
||||
top: 0; |
||||
bottom: 0; |
||||
left: 0; |
||||
right: 0; |
||||
background-color: rgba(0, 0, 0, 0.3); |
||||
@include flex; |
||||
align-items: center; |
||||
justify-content: center; |
||||
border-radius: 100px; |
||||
} |
||||
} |
||||
} |
||||
</style> |
@ -0,0 +1,28 @@ |
||||
/* |
||||
* @Author : LQ |
||||
* @Description : |
||||
* @version : 1.0 |
||||
* @Date : 2021-08-20 16:44:21 |
||||
* @LastAuthor : LQ |
||||
* @lastTime : 2021-08-20 16:49:22 |
||||
* @FilePath : /u-view2.0/uview-ui/libs/config/props/avatar.js |
||||
*/ |
||||
export default { |
||||
// avatar 组件
|
||||
avatar: { |
||||
src: '', |
||||
shape: 'circle', |
||||
size: 40, |
||||
mode: 'scaleToFill', |
||||
text: '', |
||||
bgColor: '#c0c4cc', |
||||
color: '#ffffff', |
||||
fontSize: 18, |
||||
icon: '', |
||||
mpAvatar: false, |
||||
randomBgColor: false, |
||||
defaultUrl: '', |
||||
colorIndex: '', |
||||
name: '' |
||||
} |
||||
} |
@ -0,0 +1,81 @@ |
||||
import { defineMixin } from '../../libs/vue' |
||||
import defProps from '../../libs/config/props.js' |
||||
import test from '../../libs/function/test'; |
||||
export const props = defineMixin({ |
||||
props: { |
||||
// 头像图片路径(不能为相对路径)
|
||||
src: { |
||||
type: String, |
||||
default: () => defProps.avatar.src |
||||
}, |
||||
// 头像形状,circle-圆形,square-方形
|
||||
shape: { |
||||
type: String, |
||||
default: () => defProps.avatar.shape |
||||
}, |
||||
// 头像尺寸
|
||||
size: { |
||||
type: [String, Number], |
||||
default: () => defProps.avatar.size |
||||
}, |
||||
// 裁剪模式
|
||||
mode: { |
||||
type: String, |
||||
default: () => defProps.avatar.mode |
||||
}, |
||||
// 显示的文字
|
||||
text: { |
||||
type: String, |
||||
default: () => defProps.avatar.text |
||||
}, |
||||
// 背景色
|
||||
bgColor: { |
||||
type: String, |
||||
default: () => defProps.avatar.bgColor |
||||
}, |
||||
// 文字颜色
|
||||
color: { |
||||
type: String, |
||||
default: () => defProps.avatar.color |
||||
}, |
||||
// 文字大小
|
||||
fontSize: { |
||||
type: [String, Number], |
||||
default: () => defProps.avatar.fontSize |
||||
}, |
||||
// 显示的图标
|
||||
icon: { |
||||
type: String, |
||||
default: () => defProps.avatar.icon |
||||
}, |
||||
// 显示小程序头像,只对百度,微信,QQ小程序有效
|
||||
mpAvatar: { |
||||
type: Boolean, |
||||
default: () => defProps.avatar.mpAvatar |
||||
}, |
||||
// 是否使用随机背景色
|
||||
randomBgColor: { |
||||
type: Boolean, |
||||
default: () => defProps.avatar.randomBgColor |
||||
}, |
||||
// 加载失败的默认头像(组件有内置默认图片)
|
||||
defaultUrl: { |
||||
type: String, |
||||
default: () => defProps.avatar.defaultUrl |
||||
}, |
||||
// 如果配置了randomBgColor为true,且配置了此值,则从默认的背景色数组中取出对应索引的颜色值,取值0-19之间
|
||||
colorIndex: { |
||||
type: [String, Number], |
||||
// 校验参数规则,索引在0-19之间
|
||||
validator(n) { |
||||
return test.range(n, [0, 19]) || n === '' |
||||
}, |
||||
default: () => defProps.avatar.colorIndex |
||||
}, |
||||
// 组件标识符
|
||||
name: { |
||||
type: String, |
||||
default: () => defProps.avatar.name |
||||
} |
||||
} |
||||
}) |
@ -0,0 +1,179 @@ |
||||
<template> |
||||
<view |
||||
class="u-avatar" |
||||
:class="[`u-avatar--${shape}`]" |
||||
:style="[{ |
||||
backgroundColor: (text || icon) ? (randomBgColor ? colors[colorIndex !== '' ? colorIndex : random(0, 19)] : bgColor) : 'transparent', |
||||
width: addUnit(size), |
||||
height: addUnit(size), |
||||
}, addStyle(customStyle)]" |
||||
@tap="clickHandler" |
||||
> |
||||
<slot> |
||||
<!-- #ifdef MP-WEIXIN || MP-QQ || MP-BAIDU --> |
||||
<open-data |
||||
v-if="mpAvatar && allowMp" |
||||
type="userAvatarUrl" |
||||
:style="[{ |
||||
width: addUnit(size), |
||||
height: addUnit(size) |
||||
}]" |
||||
/> |
||||
<!-- #endif --> |
||||
<!-- #ifndef MP-WEIXIN && MP-QQ && MP-BAIDU --> |
||||
<template v-if="mpAvatar && allowMp"></template> |
||||
<!-- #endif --> |
||||
<u-icon |
||||
v-else-if="icon" |
||||
:name="icon" |
||||
:size="fontSize" |
||||
:color="color" |
||||
></u-icon> |
||||
<up-text |
||||
v-else-if="text" |
||||
:text="text" |
||||
:size="fontSize" |
||||
:color="color" |
||||
align="center" |
||||
customStyle="justify-content: center" |
||||
></up-text> |
||||
<image |
||||
class="u-avatar__image" |
||||
v-else |
||||
:class="[`u-avatar__image--${shape}`]" |
||||
:src="avatarUrl || defaultUrl" |
||||
:mode="mode" |
||||
@error="errorHandler" |
||||
:style="[{ |
||||
width: addUnit(size), |
||||
height: addUnit(size) |
||||
}]" |
||||
></image> |
||||
</slot> |
||||
</view> |
||||
</template> |
||||
|
||||
<script> |
||||
import { props } from './props'; |
||||
import { mpMixin } from '../../libs/mixin/mpMixin'; |
||||
import { mixin } from '../../libs/mixin/mixin'; |
||||
import { addStyle, addUnit, random } from '../../libs/function/index'; |
||||
const base64Avatar = |
||||
"data:image/jpg;base64,/9j/4QAYRXhpZgAASUkqAAgAAAAAAAAAAAAAAP/sABFEdWNreQABAAQAAAA8AAD/4QMraHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wLwA8P3hwYWNrZXQgYmVnaW49Iu+7vyIgaWQ9Ilc1TTBNcENlaGlIenJlU3pOVGN6a2M5ZCI/PiA8eDp4bXBtZXRhIHhtbG5zOng9ImFkb2JlOm5zOm1ldGEvIiB4OnhtcHRrPSJBZG9iZSBYTVAgQ29yZSA1LjMtYzAxMSA2Ni4xNDU2NjEsIDIwMTIvMDIvMDYtMTQ6NTY6MjcgICAgICAgICI+IDxyZGY6UkRGIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyI+IDxyZGY6RGVzY3JpcHRpb24gcmRmOmFib3V0PSIiIHhtbG5zOnhtcD0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wLyIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bXA6Q3JlYXRvclRvb2w9IkFkb2JlIFBob3Rvc2hvcCBDUzYgKFdpbmRvd3MpIiB4bXBNTTpJbnN0YW5jZUlEPSJ4bXAuaWlkOjREMEQwRkY0RjgwNDExRUE5OTY2RDgxODY3NkJFODMxIiB4bXBNTTpEb2N1bWVudElEPSJ4bXAuZGlkOjREMEQwRkY1RjgwNDExRUE5OTY2RDgxODY3NkJFODMxIj4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6NEQwRDBGRjJGODA0MTFFQTk5NjZEODE4Njc2QkU4MzEiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6NEQwRDBGRjNGODA0MTFFQTk5NjZEODE4Njc2QkU4MzEiLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz7/7gAOQWRvYmUAZMAAAAAB/9sAhAAGBAQEBQQGBQUGCQYFBgkLCAYGCAsMCgoLCgoMEAwMDAwMDBAMDg8QDw4MExMUFBMTHBsbGxwfHx8fHx8fHx8fAQcHBw0MDRgQEBgaFREVGh8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx//wAARCADIAMgDAREAAhEBAxEB/8QAcQABAQEAAwEBAAAAAAAAAAAAAAUEAQMGAgcBAQAAAAAAAAAAAAAAAAAAAAAQAAIBAwICBgkDBQAAAAAAAAABAhEDBCEFMVFBYXGREiKBscHRMkJSEyOh4XLxYjNDFBEBAAAAAAAAAAAAAAAAAAAAAP/aAAwDAQACEQMRAD8A/fAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHbHFyZ/Dam+yLA+Z2L0Pjtyj2poD4AAAAAAAAAAAAAAAAAAAAAAAAKWFs9y6lcvvwQeqj8z9wFaziY1n/HbUX9XF97A7QAGXI23EvJ1goyfzR0YEfN269jeZ+a03pNe0DIAAAAAAAAAAAAAAAAAAAACvtO3RcVkXlWutuL9YFYAAAAAOJRjKLjJVi9GmB5/csH/mu1h/in8PU+QGMAAAAAAAAAAAAAAAAAAaMDG/6MmMH8C80+xAelSSVFolwQAAAAAAAHVlWI37ErUulaPk+hgeYnCUJuElSUXRrrQHAAAAAAAAAAAAAAAAABa2Oz4bM7r4zdF2ICmAAAAAAAAAg7zZ8GX41wuJP0rRgYAAAAAAAAAAAAAAAAAD0m2R8ODaXU33tsDSAAAAAAAAAlb9HyWZcnJd9PcBHAAAAAAAAAAAAAAAAAPS7e64Vn+KA0AAAAAAAAAJm+v8Ftf3ewCKAAAAAAAAAAAAAAAAAX9muqeGo9NttP06+0DcAAAAAAAAAjb7dTu2ra+VOT9P8AQCWAAAAAAAAAAAAAAAAAUNmyPt5Ltv4bui/kuAF0AAAAAAADiUlGLlJ0SVW+oDzOXfd/Ind6JPRdS0QHSAAAAAAAAAAAAAAAAAE2nVaNcGB6Lbs6OTao9LsF51z60BrAAAAAABJ3jOVHjW3r/sa9QEgAAAAAAAAAAAAAAAAAAAPu1duWriuW34ZR4MC9hbnZyEoy8l36XwfYBsAAADaSq9EuLAlZ+7xSdrGdW9Hc5dgEdtt1erfFgAAAAAAAAAAAAAAAAADVjbblX6NR8MH80tEBRs7HYivyzlN8lovaBPzduvY0m6eK10TXtAyAarO55lpJK54orolr+4GqO/Xaea1FvqbXvA+Z77kNeW3GPbV+4DJfzcm/pcm3H6Vou5AdAFLC2ed2Pjv1txa8sV8T6wOL+yZEKu1JXFy4MDBOE4ScZxcZLinoB8gAAAAAAAAAAAB242LeyJ+C3GvN9C7QLmJtePYpKS+5c+p8F2IDYAANJqj1T4oCfk7Nj3G5Wn9qXJax7gJ93Z82D8sVNc4v30A6Xg5i42Z+iLfqARwcyT0sz9MWvWBps7LlTf5Grce9/oBTxdtxseklHxT+uWr9AGoAB138ezfj4bsFJdD6V2MCPm7RdtJzs1uW1xXzL3gTgAAAAAAAAADRhYc8q74I6RWs5ckB6GxYtWLat21SK731sDsAAAAAAAAAAAAAAAASt021NO/YjrxuQXT1oCOAAAAAAABzGLlJRSq26JAelwsWONYjbXxcZvmwO8AAAAAAAAAAAAAAAAAAef3TEWPkVivx3NY9T6UBiAAAAAABo2+VmGXblddIJ8eivRUD0oAAAAAAAAAAAAAAAAAAAYt4tKeFKVNYNSXfRgefAAAAAAAAr7VuSSWPedKaW5v1MCsAAAAAAAAAAAAAAAAAAIe6bj96Ts2n+JPzSXzP3ATgAAAAAAAAFbbt1UUrOQ9FpC4/UwK6aaqtU+DAAAAAAAAAAAAAAA4lKMIuUmoxWrb4ARNx3R3q2rLpa4Sl0y/YCcAAAAAAAAAAANmFud7G8r89r6X0dgFvGzLGRGtuWvTF6NAdwAAAAAAAAAAAy5W442PVN+K59EePp5ARMvOv5MvO6QXCC4AZwAAAAAAAAAAAAAcxlKLUotprg1owN+PvORborq+7Hnwl3gUbO74VzRydt8pKn68ANcJwmqwkpLmnUDkAAAAfNy9atqtyagut0AxXt5xIV8Fbj6lRd7Am5G65V6qUvtwfyx94GMAAAAAAAAAAAAAAAAAAAOU2nVOj5gdsc3LiqRvTpyqwOxbnnrhdfpSfrQB7pnv/AGvuS9gHXPMy5/Fem1yq0v0A6W29XqwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAf//Z"; |
||||
/** |
||||
* Avatar 头像 |
||||
* @description 本组件一般用于展示头像的地方,如个人中心,或者评论列表页的用户头像展示等场所。 |
||||
* @tutorial https://ijry.github.io/uview-plus/components/avatar.html |
||||
* |
||||
* @property {String} src 头像路径,如加载失败,将会显示默认头像(不能为相对路径) |
||||
* @property {String} shape 头像形状 ( circle (默认) | square) |
||||
* @property {String | Number} size 头像尺寸,可以为指定字符串(large, default, mini),或者数值 (默认 40 ) |
||||
* @property {String} mode 头像图片的裁剪类型,与uni的image组件的mode参数一致,如效果达不到需求,可尝试传widthFix值 (默认 'scaleToFill' ) |
||||
* @property {String} text 用文字替代图片,级别优先于src |
||||
* @property {String} bgColor 背景颜色,一般显示文字时用 (默认 '#c0c4cc' ) |
||||
* @property {String} color 文字颜色 (默认 '#ffffff' ) |
||||
* @property {String | Number} fontSize 文字大小 (默认 18 ) |
||||
* @property {String} icon 显示的图标 |
||||
* @property {Boolean} mpAvatar 显示小程序头像,只对百度,微信,QQ小程序有效 (默认 false ) |
||||
* @property {Boolean} randomBgColor 是否使用随机背景色 (默认 false ) |
||||
* @property {String} defaultUrl 加载失败的默认头像(组件有内置默认图片) |
||||
* @property {String | Number} colorIndex 如果配置了randomBgColor为true,且配置了此值,则从默认的背景色数组中取出对应索引的颜色值,取值0-19之间 |
||||
* @property {String} name 组件标识符 (默认 'level' ) |
||||
* @property {Object} customStyle 定义需要用到的外部样式 |
||||
* |
||||
* @event {Function} click 点击组件时触发 index: 用户传递的标识符 |
||||
* @example <u-avatar :src="src" mode="square"></u-avatar> |
||||
*/ |
||||
export default { |
||||
name: 'u-avatar', |
||||
mixins: [mpMixin, mixin, props], |
||||
data() { |
||||
return { |
||||
// 如果配置randomBgColor参数为true,在图标或者文字的模式下,会随机从中取出一个颜色值当做背景色 |
||||
colors: ['#ffb34b', '#f2bba9', '#f7a196', '#f18080', '#88a867', '#bfbf39', '#89c152', '#94d554', '#f19ec2', |
||||
'#afaae4', '#e1b0df', '#c38cc1', '#72dcdc', '#9acdcb', '#77b1cc', '#448aca', '#86cefa', '#98d1ee', |
||||
'#73d1f1', |
||||
'#80a7dc' |
||||
], |
||||
avatarUrl: this.src, |
||||
allowMp: false |
||||
} |
||||
}, |
||||
watch: { |
||||
// 监听头像src的变化,赋值给内部的avatarUrl变量,因为图片加载失败时,需要修改图片的src为默认值 |
||||
// 而组件内部不能直接修改props的值,所以需要一个中间变量 |
||||
src: { |
||||
immediate: true, |
||||
handler(newVal) { |
||||
this.avatarUrl = newVal |
||||
// 如果没有传src,则主动触发error事件,用于显示默认的头像,否则src为''空字符等的时候,会无内容展示 |
||||
if(!newVal) { |
||||
this.errorHandler() |
||||
} |
||||
} |
||||
} |
||||
}, |
||||
computed: { |
||||
imageStyle() { |
||||
const style = {} |
||||
return style |
||||
} |
||||
}, |
||||
created() { |
||||
this.init() |
||||
}, |
||||
emits: ["click"], |
||||
methods: { |
||||
addStyle, |
||||
addUnit, |
||||
random, |
||||
init() { |
||||
// 目前只有这几个小程序平台具有open-data标签 |
||||
// 其他平台可以通过uni.getUserInfo类似接口获取信息,但是需要弹窗授权(首次),不合符组件逻辑 |
||||
// 故目前自动获取小程序头像只支持这几个平台 |
||||
// #ifdef MP-WEIXIN || MP-QQ || MP-BAIDU |
||||
this.allowMp = true |
||||
// #endif |
||||
}, |
||||
// 判断传入的name属性,是否图片路径,只要带有"/"均认为是图片形式 |
||||
isImg() { |
||||
return this.src.indexOf('/') !== -1 |
||||
}, |
||||
// 图片加载时失败时触发 |
||||
errorHandler() { |
||||
this.avatarUrl = this.defaultUrl || base64Avatar |
||||
}, |
||||
clickHandler(e) { |
||||
this.$emit('click', this.name, e) |
||||
} |
||||
} |
||||
} |
||||
</script> |
||||
|
||||
<style lang="scss" scoped> |
||||
|
||||
.u-avatar { |
||||
@include flex; |
||||
align-items: center; |
||||
justify-content: center; |
||||
|
||||
&--circle { |
||||
border-radius: 100px; |
||||
} |
||||
|
||||
&--square { |
||||
border-radius: 4px; |
||||
} |
||||
|
||||
&__image { |
||||
&--circle { |
||||
border-radius: 100px; |
||||
overflow: hidden; |
||||
} |
||||
|
||||
&--square { |
||||
border-radius: 4px; |
||||
} |
||||
} |
||||
} |
||||
</style> |
@ -0,0 +1,27 @@ |
||||
/* |
||||
* @Author : LQ |
||||
* @Description : |
||||
* @version : 1.0 |
||||
* @Date : 2021-08-20 16:44:21 |
||||
* @LastAuthor : LQ |
||||
* @lastTime : 2021-08-20 16:50:18 |
||||
* @FilePath : /u-view2.0/uview-ui/libs/config/props/backtop.js |
||||
*/ |
||||
export default { |
||||
// backtop组件
|
||||
backtop: { |
||||
mode: 'circle', |
||||
icon: 'arrow-upward', |
||||
text: '', |
||||
duration: 100, |
||||
scrollTop: 0, |
||||
top: 400, |
||||
bottom: 100, |
||||
right: 20, |
||||
zIndex: 9, |
||||
iconStyle: { |
||||
color: '#909399', |
||||
fontSize: '19px' |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,56 @@ |
||||
import { defineMixin } from '../../libs/vue' |
||||
import defProps from '../../libs/config/props.js' |
||||
export const props = defineMixin({ |
||||
props: { |
||||
// 返回顶部的形状,circle-圆形,square-方形
|
||||
mode: { |
||||
type: String, |
||||
default: () => defProps.backtop.mode |
||||
}, |
||||
// 自定义图标
|
||||
icon: { |
||||
type: String, |
||||
default: () => defProps.backtop.icon |
||||
}, |
||||
// 提示文字
|
||||
text: { |
||||
type: String, |
||||
default: () => defProps.backtop.text |
||||
}, |
||||
// 返回顶部滚动时间
|
||||
duration: { |
||||
type: [String, Number], |
||||
default: () => defProps.backtop.duration |
||||
}, |
||||
// 滚动距离
|
||||
scrollTop: { |
||||
type: [String, Number], |
||||
default: () => defProps.backtop.scrollTop |
||||
}, |
||||
// 距离顶部多少距离显示,单位px
|
||||
top: { |
||||
type: [String, Number], |
||||
default: () => defProps.backtop.top |
||||
}, |
||||
// 返回顶部按钮到底部的距离,单位px
|
||||
bottom: { |
||||
type: [String, Number], |
||||
default: () => defProps.backtop.bottom |
||||
}, |
||||
// 返回顶部按钮到右边的距离,单位px
|
||||
right: { |
||||
type: [String, Number], |
||||
default: () => defProps.backtop.right |
||||
}, |
||||
// 层级
|
||||
zIndex: { |
||||
type: [String, Number], |
||||
default: () => defProps.backtop.zIndex |
||||
}, |
||||
// 图标的样式,对象形式
|
||||
iconStyle: { |
||||
type: Object, |
||||
default: () => defProps.backtop.iconStyle |
||||
} |
||||
} |
||||
}) |
@ -0,0 +1,132 @@ |
||||
<template> |
||||
<u-transition |
||||
mode="fade" |
||||
:customStyle="backTopStyle" |
||||
:show="show" |
||||
> |
||||
<view |
||||
class="u-back-top" |
||||
:style="[contentStyle]" |
||||
v-if="!$slots.default && !$slots.$default" |
||||
@click="backToTop" |
||||
> |
||||
<u-icon |
||||
:name="icon" |
||||
:custom-style="iconStyle" |
||||
></u-icon> |
||||
<text |
||||
v-if="text" |
||||
class="u-back-top__text" |
||||
>{{text}}</text> |
||||
</view> |
||||
<slot v-else /> |
||||
</u-transition> |
||||
</template> |
||||
|
||||
<script> |
||||
import { props } from './props'; |
||||
import { mpMixin } from '../../libs/mixin/mpMixin'; |
||||
import { mixin } from '../../libs/mixin/mixin'; |
||||
import { addUnit, addStyle, getPx, deepMerge, error } from '../../libs/function/index'; |
||||
// #ifdef APP-NVUE |
||||
const dom = weex.requireModule('dom') |
||||
// #endif |
||||
/** |
||||
* backTop 返回顶部 |
||||
* @description 本组件一个用于长页面,滑动一定距离后,出现返回顶部按钮,方便快速返回顶部的场景。 |
||||
* @tutorial https://uview-plus.jiangruyi.com/components/backTop.html |
||||
* |
||||
* @property {String} mode 返回顶部的形状,circle-圆形,square-方形 (默认 'circle' ) |
||||
* @property {String} icon 自定义图标 (默认 'arrow-upward' ) 见官方文档示例 |
||||
* @property {String} text 提示文字 |
||||
* @property {String | Number} duration 返回顶部滚动时间 (默认 100) |
||||
* @property {String | Number} scrollTop 滚动距离 (默认 0 ) |
||||
* @property {String | Number} top 距离顶部多少距离显示,单位px (默认 400 ) |
||||
* @property {String | Number} bottom 返回顶部按钮到底部的距离,单位px (默认 100 ) |
||||
* @property {String | Number} right 返回顶部按钮到右边的距离,单位px (默认 20 ) |
||||
* @property {String | Number} zIndex 层级 (默认 9 ) |
||||
* @property {Object<Object>} iconStyle 图标的样式,对象形式 (默认 {color: '#909399',fontSize: '19px'}) |
||||
* @property {Object} customStyle 定义需要用到的外部样式 |
||||
* |
||||
* @example <u-back-top :scrollTop="scrollTop"></u-back-top> |
||||
*/ |
||||
export default { |
||||
name: 'u-back-top', |
||||
mixins: [mpMixin, mixin, props], |
||||
computed: { |
||||
backTopStyle() { |
||||
// 动画组件样式 |
||||
const style = { |
||||
bottom: addUnit(this.bottom), |
||||
right: addUnit(this.right), |
||||
width: '40px', |
||||
height: '40px', |
||||
position: 'fixed', |
||||
zIndex: 10, |
||||
} |
||||
return style |
||||
}, |
||||
show() { |
||||
return getPx(this.scrollTop) > getPx(this.top) |
||||
}, |
||||
contentStyle() { |
||||
const style = {} |
||||
let radius = 0 |
||||
// 是否圆形 |
||||
if(this.mode === 'circle') { |
||||
radius = '100px' |
||||
} else { |
||||
radius = '4px' |
||||
} |
||||
// 为了兼容安卓nvue,只能这么分开写 |
||||
style.borderTopLeftRadius = radius |
||||
style.borderTopRightRadius = radius |
||||
style.borderBottomLeftRadius = radius |
||||
style.borderBottomRightRadius = radius |
||||
return deepMerge(style, addStyle(this.customStyle)) |
||||
} |
||||
}, |
||||
emits: ["click"], |
||||
methods: { |
||||
backToTop() { |
||||
// #ifdef APP-NVUE |
||||
if (!this.$parent.$refs['u-back-top']) { |
||||
error(`nvue页面需要给页面最外层元素设置"ref='u-back-top'`) |
||||
} |
||||
dom.scrollToElement(this.$parent.$refs['u-back-top'], { |
||||
offset: 0 |
||||
}) |
||||
// #endif |
||||
|
||||
// #ifndef APP-NVUE |
||||
uni.pageScrollTo({ |
||||
scrollTop: 0, |
||||
duration: this.duration |
||||
}); |
||||
// #endif |
||||
this.$emit('click') |
||||
} |
||||
} |
||||
} |
||||
</script> |
||||
|
||||
<style lang="scss" scoped> |
||||
$u-back-top-flex:1 !default; |
||||
$u-back-top-height:100% !default; |
||||
$u-back-top-background-color:#E1E1E1 !default; |
||||
$u-back-top-tips-font-size:12px !default; |
||||
.u-back-top { |
||||
@include flex; |
||||
flex-direction: column; |
||||
align-items: center; |
||||
flex:$u-back-top-flex; |
||||
height: $u-back-top-height; |
||||
justify-content: center; |
||||
background-color: $u-back-top-background-color; |
||||
|
||||
&__tips { |
||||
font-size:$u-back-top-tips-font-size; |
||||
transform: scale(0.8); |
||||
} |
||||
} |
||||
</style> |
@ -0,0 +1,27 @@ |
||||
/* |
||||
* @Author : LQ |
||||
* @Description : |
||||
* @version : 1.0 |
||||
* @Date : 2021-08-20 16:44:21 |
||||
* @LastAuthor : LQ |
||||
* @lastTime : 2021-08-23 19:51:50 |
||||
* @FilePath : /u-view2.0/uview-ui/libs/config/props/badge.js |
||||
*/ |
||||
export default { |
||||
// 徽标数组件
|
||||
badge: { |
||||
isDot: false, |
||||
value: '', |
||||
show: true, |
||||
max: 999, |
||||
type: 'error', |
||||
showZero: false, |
||||
bgColor: null, |
||||
color: null, |
||||
shape: 'circle', |
||||
numberType: 'overflow', |
||||
offset: [], |
||||
inverted: false, |
||||
absolute: false |
||||
} |
||||
} |
@ -0,0 +1,79 @@ |
||||
import { defineMixin } from '../../libs/vue' |
||||
import defProps from '../../libs/config/props.js' |
||||
export const props = defineMixin({ |
||||
props: { |
||||
// 是否显示圆点
|
||||
isDot: { |
||||
type: Boolean, |
||||
default: () => defProps.badge.isDot |
||||
}, |
||||
// 显示的内容
|
||||
value: { |
||||
type: [Number, String], |
||||
default: () => defProps.badge.value |
||||
}, |
||||
// 显示的内容
|
||||
modelValue: { |
||||
type: [Number, String], |
||||
default: () => defProps.badge.modelValue |
||||
}, |
||||
// 是否显示
|
||||
show: { |
||||
type: Boolean, |
||||
default: () => defProps.badge.show |
||||
}, |
||||
// 最大值,超过最大值会显示 '{max}+'
|
||||
max: { |
||||
type: [Number, String], |
||||
default: () => defProps.badge.max |
||||
}, |
||||
// 主题类型,error|warning|success|primary
|
||||
type: { |
||||
type: String, |
||||
default: () => defProps.badge.type |
||||
}, |
||||
// 当数值为 0 时,是否展示 Badge
|
||||
showZero: { |
||||
type: Boolean, |
||||
default: () => defProps.badge.showZero |
||||
}, |
||||
// 背景颜色,优先级比type高,如设置,type参数会失效
|
||||
bgColor: { |
||||
type: [String, null], |
||||
default: () => defProps.badge.bgColor |
||||
}, |
||||
// 字体颜色
|
||||
color: { |
||||
type: [String, null], |
||||
default: () => defProps.badge.color |
||||
}, |
||||
// 徽标形状,circle-四角均为圆角,horn-左下角为直角
|
||||
shape: { |
||||
type: String, |
||||
default: () => defProps.badge.shape |
||||
}, |
||||
// 设置数字的显示方式,overflow|ellipsis|limit
|
||||
// overflow会根据max字段判断,超出显示`${max}+`
|
||||
// ellipsis会根据max判断,超出显示`${max}...`
|
||||
// limit会依据1000作为判断条件,超出1000,显示`${value/1000}K`,比如2.2k、3.34w,最多保留2位小数
|
||||
numberType: { |
||||
type: String, |
||||
default: () => defProps.badge.numberType |
||||
}, |
||||
// 设置badge的位置偏移,格式为 [x, y],也即设置的为top和right的值,absolute为true时有效
|
||||
offset: { |
||||
type: Array, |
||||
default: () => defProps.badge.offset |
||||
}, |
||||
// 是否反转背景和字体颜色
|
||||
inverted: { |
||||
type: Boolean, |
||||
default: () => defProps.badge.inverted |
||||
}, |
||||
// 是否绝对定位
|
||||
absolute: { |
||||
type: Boolean, |
||||
default: () => defProps.badge.absolute |
||||
} |
||||
} |
||||
}) |
@ -0,0 +1,176 @@ |
||||
<template> |
||||
<text |
||||
v-if="show && ((Number(value) === 0 ? showZero : true) || isDot)" |
||||
:class="[isDot ? 'u-badge--dot' : 'u-badge--not-dot', inverted && 'u-badge--inverted', shape === 'horn' && 'u-badge--horn', `u-badge--${type}${inverted ? '--inverted' : ''}`]" |
||||
:style="[addStyle(customStyle), badgeStyle]" |
||||
class="u-badge" |
||||
>{{ isDot ? '' :showValue }}</text> |
||||
</template> |
||||
|
||||
<script> |
||||
import { props } from './props'; |
||||
import { mpMixin } from '../../libs/mixin/mpMixin'; |
||||
import { mixin } from '../../libs/mixin/mixin'; |
||||
import { addStyle, addUnit } from '../../libs/function/index'; |
||||
/** |
||||
* badge 徽标数 |
||||
* @description 该组件一般用于图标右上角显示未读的消息数量,提示用户点击,有圆点和圆包含文字两种形式。 |
||||
* @tutorial https://uview-plus.jiangruyi.com/components/badge.html |
||||
* |
||||
* @property {Boolean} isDot 是否显示圆点 (默认 false ) |
||||
* @property {String | Number} value 显示的内容 |
||||
* @property {Boolean} show 是否显示 (默认 true ) |
||||
* @property {String | Number} max 最大值,超过最大值会显示 '{max}+' (默认999) |
||||
* @property {String} type 主题类型,error|warning|success|primary (默认 'error' ) |
||||
* @property {Boolean} showZero 当数值为 0 时,是否展示 Badge (默认 false ) |
||||
* @property {String} bgColor 背景颜色,优先级比type高,如设置,type参数会失效 |
||||
* @property {String} color 字体颜色 (默认 '#ffffff' ) |
||||
* @property {String} shape 徽标形状,circle-四角均为圆角,horn-左下角为直角 (默认 'circle' ) |
||||
* @property {String} numberType 设置数字的显示方式,overflow|ellipsis|limit (默认 'overflow' ) |
||||
* @property {Array}} offset 设置badge的位置偏移,格式为 [x, y],也即设置的为top和right的值,absolute为true时有效 |
||||
* @property {Boolean} inverted 是否反转背景和字体颜色(默认 false ) |
||||
* @property {Boolean} absolute 是否绝对定位(默认 false ) |
||||
* @property {Object} customStyle 定义需要用到的外部样式 |
||||
* @example <u-badge :type="type" :count="count"></u-badge> |
||||
*/ |
||||
export default { |
||||
name: 'u-badge', |
||||
mixins: [mpMixin, props, mixin], |
||||
computed: { |
||||
// 是否将badge中心与父组件右上角重合 |
||||
boxStyle() { |
||||
let style = {}; |
||||
return style; |
||||
}, |
||||
// 整个组件的样式 |
||||
badgeStyle() { |
||||
const style = {} |
||||
if(this.color) { |
||||
style.color = this.color |
||||
} |
||||
if (this.bgColor && !this.inverted) { |
||||
style.backgroundColor = this.bgColor |
||||
} |
||||
if (this.absolute) { |
||||
style.position = 'absolute' |
||||
// 如果有设置offset参数 |
||||
if(this.offset.length) { |
||||
// top和right分为为offset的第一个和第二个值,如果没有第二个值,则right等于top |
||||
const top = this.offset[0] |
||||
const right = this.offset[1] || top |
||||
style.top = addUnit(top) |
||||
style.right = addUnit(right) |
||||
} |
||||
} |
||||
return style |
||||
}, |
||||
showValue() { |
||||
switch (this.numberType) { |
||||
case "overflow": |
||||
return Number(this.value) > Number(this.max) ? this.max + "+" : this.value |
||||
break; |
||||
case "ellipsis": |
||||
return Number(this.value) > Number(this.max) ? "..." : this.value |
||||
break; |
||||
case "limit": |
||||
return Number(this.value) > 999 ? Number(this.value) >= 9999 ? |
||||
Math.floor(this.value / 1e4 * 100) / 100 + "w" : Math.floor(this.value / |
||||
1e3 * 100) / 100 + "k" : this.value |
||||
break; |
||||
default: |
||||
return Number(this.value) |
||||
} |
||||
}, |
||||
}, |
||||
methods: { |
||||
addStyle |
||||
} |
||||
} |
||||
</script> |
||||
|
||||
<style lang="scss" scoped> |
||||
|
||||
$u-badge-primary: $u-primary !default; |
||||
$u-badge-error: $u-error !default; |
||||
$u-badge-success: $u-success !default; |
||||
$u-badge-info: $u-info !default; |
||||
$u-badge-warning: $u-warning !default; |
||||
$u-badge-dot-radius: 100px !default; |
||||
$u-badge-dot-size: 8px !default; |
||||
$u-badge-dot-right: 4px !default; |
||||
$u-badge-dot-top: 0 !default; |
||||
$u-badge-text-font-size: 11px !default; |
||||
$u-badge-text-right: 10px !default; |
||||
$u-badge-text-padding: 2px 5px !default; |
||||
$u-badge-text-align: center !default; |
||||
$u-badge-text-color: #FFFFFF !default; |
||||
|
||||
.u-badge { |
||||
border-top-right-radius: $u-badge-dot-radius; |
||||
border-top-left-radius: $u-badge-dot-radius; |
||||
border-bottom-left-radius: $u-badge-dot-radius; |
||||
border-bottom-right-radius: $u-badge-dot-radius; |
||||
@include flex; |
||||
line-height: $u-badge-text-font-size; |
||||
text-align: $u-badge-text-align; |
||||
font-size: $u-badge-text-font-size; |
||||
color: $u-badge-text-color; |
||||
|
||||
&--dot { |
||||
height: $u-badge-dot-size; |
||||
width: $u-badge-dot-size; |
||||
} |
||||
|
||||
&--inverted { |
||||
font-size: 13px; |
||||
} |
||||
|
||||
&--not-dot { |
||||
padding: $u-badge-text-padding; |
||||
} |
||||
|
||||
&--horn { |
||||
border-bottom-left-radius: 0; |
||||
} |
||||
|
||||
&--primary { |
||||
background-color: $u-badge-primary; |
||||
} |
||||
|
||||
&--primary--inverted { |
||||
color: $u-badge-primary; |
||||
} |
||||
|
||||
&--error { |
||||
background-color: $u-badge-error; |
||||
} |
||||
|
||||
&--error--inverted { |
||||
color: $u-badge-error; |
||||
} |
||||
|
||||
&--success { |
||||
background-color: $u-badge-success; |
||||
} |
||||
|
||||
&--success--inverted { |
||||
color: $u-badge-success; |
||||
} |
||||
|
||||
&--info { |
||||
background-color: $u-badge-info; |
||||
} |
||||
|
||||
&--info--inverted { |
||||
color: $u-badge-info; |
||||
} |
||||
|
||||
&--warning { |
||||
background-color: $u-badge-warning; |
||||
} |
||||
|
||||
&--warning--inverted { |
||||
color: $u-badge-warning; |
||||
} |
||||
} |
||||
</style> |
@ -0,0 +1,27 @@ |
||||
import { defineMixin } from '../../libs/vue' |
||||
import defProps from '../../libs/config/props.js' |
||||
|
||||
export const propsBox = defineMixin({ |
||||
props: { |
||||
// 背景色
|
||||
bgColors: { |
||||
type: [Array], |
||||
default: ['#EEFCFF', '#FCF8FF', '#FDF8F2'] |
||||
}, |
||||
// 高度
|
||||
height: { |
||||
type: [String], |
||||
default: "160px" |
||||
}, |
||||
// 圆角
|
||||
borderRadius: { |
||||
type: [String], |
||||
default: "6px" |
||||
}, |
||||
// 间隔
|
||||
gap: { |
||||
type: [String], |
||||
default: "15px" |
||||
}, |
||||
} |
||||
}) |
@ -0,0 +1,91 @@ |
||||
<template> |
||||
<view class="u-box" :style="[{height: height}, addStyle(customStyle)]"> |
||||
<view class="u-box__left" :style="{borderRadius: borderRadius, backgroundColor: bgColors[0]}"> |
||||
<slot name="left">左</slot> |
||||
</view> |
||||
<view class="u-box__gap" :style="{width: gap, height: height}"></view> |
||||
<view class="u-box__right"> |
||||
<view class="u-box__right-top" :style="{borderRadius: borderRadius, backgroundColor: bgColors[1]}"> |
||||
<slot name="rightTop">右上</slot> |
||||
</view> |
||||
<view class="u-box__right-gap" :style="{height: gap}"></view> |
||||
<view class="u-box__right-bottom" :style="{borderRadius: borderRadius, backgroundColor: bgColors[2]}"> |
||||
<slot name="rightBottom">右下</slot> |
||||
</view> |
||||
</view> |
||||
</view> |
||||
</template> |
||||
|
||||
<script> |
||||
import { propsBox } from './props'; |
||||
import { mpMixin } from '../../libs/mixin/mpMixin'; |
||||
import { mixin } from '../../libs/mixin/mixin'; |
||||
import { addStyle } from '../../libs/function/index'; |
||||
import test from '../../libs/function/test'; |
||||
/** |
||||
* box 盒子 |
||||
* @description box盒子一般为左边一个盒子,右侧两个等高的半盒组成,常用于App首页座位重点突出。 |
||||
* @tutorial https://uview-plus.jiangruyi.com/components/box.html |
||||
* @property {Array} bgColors 背景色 |
||||
* @property {String} height 高度 |
||||
* @property {String} borderRadius 圆角 |
||||
* @property {Object} customStyle 定义需要用到的外部样式 |
||||
* |
||||
* @event {Function} click 点击cell列表时触发 |
||||
* @example <up-box colors=['blue', 'red', 'yellow'] height="200px"></up-box> |
||||
*/ |
||||
export default { |
||||
name: 'up-box', |
||||
data() { |
||||
return { |
||||
} |
||||
}, |
||||
mixins: [mpMixin, mixin, propsBox], |
||||
computed: { |
||||
}, |
||||
emits: [], |
||||
methods: { |
||||
addStyle, |
||||
} |
||||
} |
||||
</script> |
||||
|
||||
<style lang="scss" scoped> |
||||
|
||||
.u-box { |
||||
/* #ifndef APP-NVUE */ |
||||
/* #endif */ |
||||
@include flex(); |
||||
flex: 1; |
||||
|
||||
&__left { |
||||
@include flex(); |
||||
justify-content: center; |
||||
align-items: center; |
||||
flex: 1; |
||||
} |
||||
&__gap { |
||||
@include flex(); |
||||
flex-direction: column; |
||||
} |
||||
&__right { |
||||
@include flex(); |
||||
flex-direction: column; |
||||
flex: 1; |
||||
} |
||||
|
||||
&__right-top { |
||||
@include flex(); |
||||
flex: 1; |
||||
justify-content: center; |
||||
align-items: center; |
||||
} |
||||
|
||||
&__right-bottom { |
||||
@include flex(); |
||||
flex: 1; |
||||
justify-content: center; |
||||
align-items: center; |
||||
} |
||||
} |
||||
</style> |
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue