longjieli 11 months ago
parent
commit
9737a378bb
31 changed files with 3337 additions and 293 deletions
  1. +10
    -1
      api/api.js
  2. +1
    -1
      api/http.js
  3. +132
    -0
      components/PrivacyAgreementPoup/PrivacyAgreementPoup.vue
  4. +47
    -0
      components/configPopup/configPopup.vue
  5. +1
    -1
      config.js
  6. +1
    -1
      manifest.json
  7. +8
    -2
      pages.json
  8. +167
    -0
      pages/center/center.vue
  9. +36
    -29
      pages/finish/finish.vue
  10. +142
    -188
      pages/login/login.vue
  11. +131
    -0
      pages/login/wxUserInfo.vue
  12. +14
    -7
      pages/reject/reject.vue
  13. +73
    -28
      pages/repair/repair.vue
  14. +67
    -30
      pages/repairList/repairList.vue
  15. BIN
      static/bar/3.png
  16. BIN
      static/bar/4.png
  17. +64
    -5
      store/store.js
  18. +33
    -0
      uni_modules/uni-badge/changelog.md
  19. +268
    -0
      uni_modules/uni-badge/components/uni-badge/uni-badge.vue
  20. +85
    -0
      uni_modules/uni-badge/package.json
  21. +10
    -0
      uni_modules/uni-badge/readme.md
  22. +46
    -0
      uni_modules/uni-list/changelog.md
  23. +107
    -0
      uni_modules/uni-list/components/uni-list-ad/uni-list-ad.vue
  24. +58
    -0
      uni_modules/uni-list/components/uni-list-chat/uni-list-chat.scss
  25. +593
    -0
      uni_modules/uni-list/components/uni-list-chat/uni-list-chat.vue
  26. +534
    -0
      uni_modules/uni-list/components/uni-list-item/uni-list-item.vue
  27. +123
    -0
      uni_modules/uni-list/components/uni-list/uni-list.vue
  28. +65
    -0
      uni_modules/uni-list/components/uni-list/uni-refresh.vue
  29. +87
    -0
      uni_modules/uni-list/components/uni-list/uni-refresh.wxs
  30. +88
    -0
      uni_modules/uni-list/package.json
  31. +346
    -0
      uni_modules/uni-list/readme.md

+ 10
- 1
api/api.js View File

@ -6,8 +6,17 @@ const config = {
// auth : false, showLoading : true, loadingTitle : '加载中...',
// limit : 1000
// },
getConfig : {url : '/api/getConfig', method : 'GET', limit : 500},
// 登录接口
loginLogin: { url: '/cheer/login/login', method: 'GET', },
//增加报修单
addSchoolOrder : {url : '/school-api/addSchoolOrder', method : 'GET', limit : 500},
//驳回
editSchoolOrderError : {url : '/school-api/editSchoolOrderError', method : 'GET', limit : 500},
//结单
editSchoolOrderSuccess : {url : '/school-api/editSchoolOrderSuccess', method : 'GET', limit : 500},
//报修列表
getSchoolOrderPage : {url : '/school-api/getSchoolOrderPage', method : 'GET', limit : 500},
}


+ 1
- 1
api/http.js View File

@ -15,7 +15,7 @@ function http(uri, data, callback, method = 'GET', showLoading, title) {
data: enhanceData(data),
method: method,
header: {
'X-Access-Token': localStorage.getItem('token'),
'X-Access-Token': uni.getStorageSync('token'),
'Content-Type' : method == 'POST' ? 'application/x-www-form-urlencoded' : 'application/json'
},
success: (res) => {


+ 132
- 0
components/PrivacyAgreementPoup/PrivacyAgreementPoup.vue View File

@ -0,0 +1,132 @@
<template>
<uv-popup ref="popup" z-index="99999" :closeOnClickOverlay="false" :customStyle="{ backgroundColor: 'transparent' }">
<view class="privacyPopup">
<view class="title">
<view>协议与隐私政策</view>
</view>
<view class="content_pri">
<view class="text">
欢迎来到xx报修!我们根据最新的法律法规监管政策要求更新了用户协议隐私政策,请您认真阅读
</view>
</view>
<view class="config">
<uv-checkbox-group v-model="checkboxValue" shape="circle">
<view class="content">
<view style="display: flex;">
<uv-checkbox size="30rpx" :name="1"></uv-checkbox>
同意<text>xx报修隐私政策</text>
</view>
<view class="">
以及<text>用户协议</text>
</view>
</view>
</uv-checkbox-group>
</view>
<view class="pri_btn">
<!-- <button class="confuse_btn" @click="confusePrivacy">拒绝</button> -->
<button class="confirm_btn" id="agree-btn" open-type="agreePrivacyAuthorization"
@agreeprivacyauthorization="handleAgreePrivacyAuthorization">同意</button>
</view>
</view>
</uv-popup>
</template>
<script>
export default {
name: 'PrivacyAgreementPoup',
data() {
return {
resolvePrivacyAuthorization: {},
checkboxValue : false
}
},
methods: {
//
init(resolve) {
this.$refs.popup.open('center')
this.resolvePrivacyAuthorization = resolve
},
//
goToPrivacy() {
wx.openPrivacyContract({
success: () => {
console.log('打开成功');
}, //
fail: () => {
uni.showToast({
title: '打开失败,稍后重试',
icon: 'none'
})
} //
})
},
//
confusePrivacy() {
this.$refs.popup.close()
this.resolvePrivacyAuthorization({
event: 'disagree'
})
},
//
handleAgreePrivacyAuthorization() {
// id
this.resolvePrivacyAuthorization({
buttonId: 'agree-btn',
event: 'agree'
})
this.$refs.popup.close()
}
}
}
</script>
<style lang="scss" scoped>
.privacyPopup {
width: 90%;
margin: 0rpx auto;
background: white;
border-radius: 20rpx;
box-sizing: border-box;
padding: 40rpx 30rpx;
.title {
text-align: center;
font-size: 36rpx;
}
.content_pri {
padding: 30rpx 0rpx;
font-size: 28rpx;
}
.config {
font-size: 28rpx;
text-align: center;
line-height: 40rpx;
margin-bottom: 30rpx;
text {
color: #00aaff;
}
.content{
display: flex;
}
}
.pri_btn {
button {
background: #00aaff;
outline: none;
color: white;
font-size: 30rpx;
}
}
}
</style>

+ 47
- 0
components/configPopup/configPopup.vue View File

@ -0,0 +1,47 @@
<template>
<view class="configPopup">
<uv-popup ref="popup" :round="30" :customStyle="{height: '50vh'}">
<view class="content">
<uv-parse :content="content"></uv-parse>
</view>
</uv-popup>
</view>
</template>
<script>
import { mapGetters } from 'vuex'
export default {
name: 'configPoup',
data() {
return {
content : ''
}
},
onShow(){
console.log(this.getConfig);
},
methods: {
//
open(key){
console.log(key);
this.content = this.getConfig[key]
this.$refs.popup.open('bottom');
}
},
computed : {
...mapGetters(['getConfig'])
}
}
</script>
<style lang="scss" scoped>
.configPopup {
.content{
padding: 30rpx 20rpx;
}
}
</style>

+ 1
- 1
config.js View File

@ -13,7 +13,7 @@ const type = 'dev'
// 环境配置
const config = {
dev : {
baseUrl : 'http://www.gcosc.fun:82',
baseUrl : 'http://8.138.162.67:8000/a-notice-api',
},
prod : {
baseUrl : 'http://xxx.xxx.xxx/xxx',


+ 1
- 1
manifest.json View File

@ -1,6 +1,6 @@
{
"name" : "unapp模板",
"appid" : "__UNI__5405C20",
"appid" : "__UNI__F370613",
"description" : "",
"versionName" : "1.0.0",
"versionCode" : "100",


+ 8
- 2
pages.json View File

@ -28,6 +28,12 @@
"style": {
"navigationBarTitleText": "结单"
}
},
{
"path": "pages/center/center",
"style": {
"navigationBarTitleText": "个人中心"
}
}
],
"globalStyle": {
@ -47,8 +53,8 @@
}, {
"selectedIconPath": "/static/bar/4.png",
"iconPath": "/static/bar/3.png",
"pagePath": "pages/repairList/repairList",
"text": "记录"
"pagePath": "pages/center/center",
"text": "用户中心"
}]
},
"uniIdRouter": {}

+ 167
- 0
pages/center/center.vue View File

@ -0,0 +1,167 @@
<template>
<view class="">
<uni-nav-bar dark :fixed="true" background-color="#00aaff" :border="false" status-bar title="个人中心" />
<view class="content">
<view class="topBox">
<view class="users">
<view class="u-top" v-if="userInfo.appletOpenid">
<image class="img" :src="userInfo.headImage" mode="widthFix"></image>
<view class="tit">
{{ userInfo.nickName }}
</view>
</view>
<view class="u-top" v-else>
<image class="img"
src="https://img2.baidu.com/it/u=2953585264,744730101&fm=253&fmt=auto&app=138&f=JPEG?w=360&h=360"
mode="widthFix"></image>
<view class="tit">
登录 / 注册
</view>
</view>
</view>
</view>
<view class="lists">
<uni-list>
<uni-list-item :show-extra-icon="true" :extra-icon="extraIcon1" showArrow title="我的报修" clickable
@click="clickList" />
</uni-list>
</view>
</view>
</view>
</template>
<script>
import {
mapState,
} from 'vuex'
export default {
name: 'Center',
computed: {
...mapState(['userInfo']),
},
data() {
return {
queryParams: {
pageNo: 1,
pageSize: 10
},
orderList: [],
extraIcon1: {
color: '#666666',
size: '22',
type: 'auth'
}
}
},
onShow() {
// if (uni.getStorageSync('token')) {
// this.$store.commit('getUserInfo')
// }
},
methods: {
clickList() {
uni.navigateTo({
url: '/pages/repairList/repairList'
})
}
}
}
</script>
<style scoped>
.content {
background: #F1F5F8;
min-height: 100vh;
}
/* 弧形背景 */
.topBox {
width: 100%;
position: relative;
z-index: 1;
overflow: hidden;
padding: 60rpx 20rpx 20rpx;
box-sizing: border-box;
}
.topBox::after {
content: "";
width: 140%;
height: 100px;
position: absolute;
left: -20%;
top: 0;
z-index: -1;
border-radius: 0 0 30% 50%;
background: #00aaff;
}
.txt {
color: #fff;
font-size: 30rpx;
}
.set-right .uni-icons {
margin-right: 10rpx;
}
.users {
display: flex;
align-items: center;
margin-top: 0rpx;
padding: 0rpx 30rpx;
box-sizing: border-box;
height: 200rpx;
background-color: #fff;
box-shadow: 1px 10rpx 20rpx #ececec;
border-radius: 12rpx;
}
.u-top {
display: flex;
justify-content: flex-start;
align-items: center;
}
.users .u-top .img {
width: 130rpx;
height: 130rpx;
border-radius: 50%;
margin-right: 20rpx;
}
.u-top .tit {
font-size: 30rpx;
font-weight: 700;
color: #333;
}
.u-item {
text-align: center;
}
.u-item .u-tit {
color: #757575;
font-size: 26rpx;
margin-top: 10rpx;
}
.u-item .num {
color: #000000;
font-size: 33rpx;
font-weight: 700;
}
.bottomBox {
padding: 20rpx;
box-sizing: border-box;
}
.listBox {
margin: -10rpx auto 0;
padding: 20rpx;
box-sizing: border-box;
border-radius: 20rpx;
}
</style>

+ 36
- 29
pages/finish/finish.vue View File

@ -4,27 +4,27 @@
<!-- <navbar title="结单" :leftClick="leftClick"></navbar> -->
<uv-form labelPosition="top" :model="form" :rules="rules" ref="form" labelWidth="140">
<uv-form-item label="处理结果" prop="form.processingResult">
<uv-input @focus="processingPickerOpen" placeholder="请选择处理结果" v-model="form.processingResult"
<uv-form-item label="处理结果" prop="form.successTitle">
<uv-input @focus="processingPickerOpen" placeholder="请选择处理结果" v-model="form.successTitle"
:fontSize="30"></uv-input>
</uv-form-item>
<uv-form-item label="收费金额" prop="form.money">
<uv-input placeholder="请输入收费金额" type="number" v-model="form.money" :fontSize="30"></uv-input>
<uv-form-item label="收费金额" prop="form.successPrice">
<uv-input placeholder="请输入收费金额" type="number" v-model="form.successPrice" :fontSize="30"></uv-input>
</uv-form-item>
<uv-form-item label="处理说明" prop="form.instructions">
<uv-textarea v-model="form.instructions" :maxlength="200" :height="120" count
<uv-form-item label="处理说明" prop="form.sucessText">
<uv-textarea v-model="form.sucessText" :maxlength="200" :height="120" count
placeholder="请输入处理说明"></uv-textarea>
</uv-form-item>
<uv-form-item label="照片" prop="form.images">
<uv-form-item label="照片" prop="form.successImage">
<view class="image-list">
<view @click="openImageMenu(index)" v-for="(item,index) in form.images" :key="index"
<view @click="openImageMenu(index)" v-for="(item,index) in form.successImage" :key="index"
class="image-item">
<image :src="item" mode="widthFix"></image>
</view>
<view v-if="form.images.length < maxUpload" @click="chooseImage" class="upload">
<view v-if="form.successImage.length < maxUpload" @click="uploadImage" class="upload">
<uv-icon name="camera-fill" color="#3c9cff" size="50"></uv-icon>
</view>
</view>
@ -55,10 +55,10 @@
data() {
return {
form: {
processingResult: '',
money: 0,
instructions: '',
images: []
successTitle: '',
successPrice: '',
sucessText: '',
successImage: []
},
rules: {
@ -88,6 +88,9 @@
],
}
},
onLoad: function(options) {
this.form.id = options.orderId || ''
},
methods: {
//
leftClick() {
@ -103,23 +106,16 @@
//
floorConfirm(floor) {
this.form.processingResult = floor.value[0].label
this.form.successTitle = floor.value[0].label
},
//
chooseImage() {
this.$utils.chooseImage(res => {
res.tempFiles.forEach(file => {
console.log(file);
this.aliUpload(file)
})
})
},
//oss
aliUpload(file) {
this.$uploadFileToOSS(file).then(filePath => {
this.form.images.push(filePath)
//
uploadImage() {
let self = this
this.$Oss.ossUploadImage({
success(res) {
self.form.successImage.push(res)
}
})
},
@ -155,6 +151,16 @@
return index != this.currentIndex
})
},
//
submit() {
this.form.successImage = this.form.successImage.join(',')
this.$api('editSchoolOrderSuccess', this.form, res => {
if (res.code == 200) {
console.log(res);
}
})
}
}
}
</script>
@ -183,7 +189,8 @@
margin-left: 1%;
border-radius: 15rpx;
overflow: hidden;
margin-bottom: 20rpx;;
margin-bottom: 20rpx;
;
}
.image-item image {


+ 142
- 188
pages/login/login.vue View File

@ -1,195 +1,149 @@
<template>
<view class="content">
<!-- app和小程序使用以下svg会报错 h5正常 -->
<!-- <svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="100%" height="100%" viewBox="0 0 1600 900" preserveAspectRatio="xMidYMax slice">
<defs>
<linearGradient id="bg">
<stop offset="0%" style="stop-color:rgba(130, 158, 249, 0.06)"></stop>
<stop offset="50%" style="stop-color:rgba(76, 190, 255, 0.6)"></stop>
<stop offset="100%" style="stop-color:rgba(115, 209, 72, 0.2)"></stop>
</linearGradient>
<path id="wave" fill="url(#bg)"
d="M-363.852,502.589c0,0,236.988-41.997,505.475,0
s371.981,38.998,575.971,0s293.985-39.278,505.474,5.859s493.475,48.368,716.963-4.995v560.106H-363.852V502.589z" />
</defs>
<g>
<use xlink:href='#wave' opacity=".3">
<animateTransform attributeName="transform" attributeType="XML" type="translate" dur="10s"
calcMode="spline" values="270 230; -334 180; 270 230" keyTimes="0; .5; 1"
keySplines="0.42, 0, 0.58, 1.0;0.42, 0, 0.58, 1.0" repeatCount="indefinite" />
</use>
<use xlink:href='#wave' opacity=".6">
<animateTransform attributeName="transform" attributeType="XML" type="translate" dur="8s"
calcMode="spline" values="-270 230;243 220;-270 230" keyTimes="0; .6; 1"
keySplines="0.42, 0, 0.58, 1.0;0.42, 0, 0.58, 1.0" repeatCount="indefinite" />
</use>
<use xlink:href='#wave' opacty=".9">
<animateTransform attributeName="transform" attributeType="XML" type="translate" dur="6s"
calcMode="spline" values="0 230;-140 200;0 230" keyTimes="0; .4; 1"
keySplines="0.42, 0, 0.58, 1.0;0.42, 0, 0.58, 1.0" repeatCount="indefinite" />
</use>
</g>
</svg> -->
<view class="loginBox">
<h3 style="text-align: center;margin-bottom:120rpx;">欢迎登录</h3>
<view class="inputBox">
<view class="ipt">
<uni-icons type="contact" size="24" color="rgb(66,157,250)"></uni-icons>
<input type="text" value="" placeholder="请输入手机号"/>
</view>
<view class="ipt">
<uni-icons type="eye" size="24" color="rgb(66,157,250)"></uni-icons>
<input type="passsword" value="" placeholder="请输入密码"/>
</view>
<view class="ipt">
<uni-icons type="checkmarkempty" size="24" color="rgb(66,157,250)"></uni-icons>
<input type="text" value="" placeholder="请输入验证码"/>
<view class="yzm">
验证码
</view>
</view>
<button @click="login">登录</button>
<view class="forgetPwd">
<!-- <span>忘记密码</span> -->
<!-- <span>没有账号去注册</span> -->
</view>
</view>
<view class="tipbox">
<view class="txt">
其他账号登录
</view>
<view class="otherUser">
<uni-icons type="weixin" size="40" color="rgb(2,187,17)"></uni-icons>
</view>
</view>
</view>
</view>
<view class="login">
<view class="logo">
<!-- <image src="/static/image/login/logo.png" mode=""></image> -->
</view>
<view class="title">
欢迎使用xx报修
</view>
<view class="btn mt">
<view class="icon">
<!-- <image src="/static/image/login/wx.png" mode=""></image> -->
</view>
<view class=""
@click="wxLogin">
微信授权登录
</view>
</view>
<!-- <view class="btn b2">
使用短信验证登录
</view> -->
<view class="config">
<uv-checkbox-group
v-model="checkboxValue"
shape="circle">
<view class="content">
<view
style="display: flex;">
<uv-checkbox
size="30rpx"
:name="1"
></uv-checkbox>
阅读并同意我们的<text @click="openConfigDetail('privacyAgreement')">服务协议与隐私条款</text>
</view>
<view class="">
以及<text @click="openConfigDetail('userAgreement')">个人信息保护指引</text>
</view>
</view>
</uv-checkbox-group>
</view>
<configPopup ref="popup"></configPopup>
</view>
</template>
<script>
export default {
data() {
return {
}
},
methods: {
//
login(){
uni.switchTab({
url: '/pages/repair/repair'
})
import configPopup from '../../components/config/configPopup.vue';
export default {
name : 'Login',
data() {
return {
checkboxValue : []
}
},
methods: {
wxLogin(){
// this.$store.commit('login')
uni.switchTab({
url: '/pages/repair/repair'
})
},
//
openConfigDetail(key){
this.$refs.popup.open(key)
}
}
}
}
}
</script>
<style scoped>
svg {
position: absolute;
bottom: 0;
left: 0;
width: 100%;
height:40%;
box-sizing: border-box;
display: block;
background-color: #ffffff;
}
.loginBox{
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%,-60%);
width: 90%;
border-radius: 20rpx;
padding: 60rpx;
box-sizing: border-box;
}
h3{
color:rgb(66,157,250);
font-size: 40rpx;
letter-spacing: 10rpx;
margin-bottom: 40rpx;
}
.inputBox{
}
.ipt{
height: 86rpx;
display: flex;
justify-content: flex-start;
align-items: center;
margin-bottom: 40rpx;
background-color: #f5f5f5;
border-radius: 10rpx;
padding-left: 10rpx;
}
.ipt input{
margin-left: 20rpx;
font-size: 28rpx;
}
.ipt input{
margin-left: 20rpx;
}
.forgetPwd{
margin-top: 30rpx;
font-size: 26rpx;
color: #b5b5b5;
text-align: end;
padding:0 10rpx;
display: flex;
justify-content: space-between;
}
button{
margin-top: 20rpx;
line-height: 85rpx;
text-align: center;
background: rgb(66,157,250);
border-radius: 40rpx;
color: #fff;
margin-top: 40rpx;
}
.tip{
text-align: center;
font-size: 28rpx;
position: fixed;
bottom: 50rpx;
left: 50%;
transform: translate(-50%,-50%);
color: #f4f4f4;
}
.tipbox {
text-align: center;
margin-top: 100rpx;
}
.otherUser {
margin-top: 30rpx;
display: flex;
justify-content: center;
}
.txt {
font-size: 28rpx;
color: #cbcbcb;
}
.otherUser .uni-icons {
margin-left: 20rpx;
}
.yzm{
text-align: end;
font-size: 24rpx;
background: linear-gradient(to right,rgb(66,157,250),rgb(0, 170, 127));
height: 60rpx;
width: 150rpx;
line-height: 60rpx;
text-align: center;
border-radius: 10rpx;
color: #fff;
}
</style>
<style scoped lang="scss">
.login{
display: flex;
justify-content: center;
align-items: center;
height: 80vh;
flex-direction: column;
position: relative;
.logo{
height: 80rpx;
width: 80rpx;
padding: 40rpx 30rpx;
background-color: #ddd;
border-radius: 70rpx;
image{
width: 80rpx;
height: 80rpx;
}
margin-bottom: 20rpx;
}
.title{
position: relative;
font-weight: 900;
font-size: 45rpx;
&::after{
content: '';
position: absolute;
left: 0;
top: 100%;
display: block;
height: 8rpx;
width: 210rpx;
background: linear-gradient(to right,#00aaff, #fff);
}
}
.btn{
width: 80%;
height: 100rpx;
background-color: #00aaff;
color: #fff;
display: flex;
justify-content: center;
align-items: center;
margin: 20rpx 0;
border-radius: 20rpx;
.icon{
margin-right: 10rpx;
image{
width: 40rpx;
height: 35rpx;
}
}
}
.b2{
background-color: #3c69f122;
color: #3c69f1;
}
.mt{
margin-top: 200rpx;
}
.config{
position: absolute;
bottom: 0;
font-size: 22rpx;
text-align: center;
line-height: 40rpx;
text{
color: #00aaff;
}
}
}
</style>

+ 131
- 0
pages/login/wxUserInfo.vue View File

@ -0,0 +1,131 @@
<template>
<view class="login">
<view class="title">
帧视界
</view>
<view class="title">
申请获取你的头像昵称
</view>
<button class="chooseAvatar" open-type="chooseAvatar" @chooseavatar="onChooseAvatar">
<view class="line">
<view class="">
头像
</view>
<view class="">
<image :src="userInfo.headImage" v-if="userInfo.headImage" style="width: 60rpx;height: 60rpx;"
mode=""></image>
<image src="/static/login/6.png" v-else style="width: 50rpx;height: 50rpx;" mode=""></image>
</view>
</view>
</button>
<view class="line">
<view class="">
昵称
</view>
<view class="">
<input type="nickname" placeholder="请输入昵称" style="text-align: right;" id="nickName"
v-model="userInfo.nickName" />
</view>
</view>
<view class="btn" @click="submit">
确认
</view>
</view>
</template>
<script>
export default {
data() {
return {
userInfo: {
headImage: '',
nickName: '',
}
};
},
onShow() {},
computed: {},
methods: {
onChooseAvatar(res) {
let self = this
self.$Oss.ossUpload(res.target.avatarUrl)
.then(url => {
self.userInfo.headImage = url
})
},
submit() {
let self = this
uni.createSelectorQuery().in(this)
.select("#nickName")
.fields({
properties: ["value"],
})
.exec((res) => {
const nickName = res?.[0]?.value
self.userInfo.nickName = nickName
if (self.$utils.verificationAll(self.userInfo, {
headImage: '请选择头像',
nickName: '请填写昵称',
})) {
return
}
self.$api('infoUpdateInfo', self.userInfo, res => {
if (res.code == 200) {
uni.navigateBack(-1)
}
})
})
},
}
}
</script>
<style lang="scss" scoped>
.login {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
height: 80vh;
.title {
line-height: 45rpx;
font-weight: 900;
}
.line {
display: flex;
justify-content: space-between;
align-items: center;
width: 80%;
border-bottom: 1px solid #00000023;
padding: 30rpx 0;
margin: 0 auto;
}
.chooseAvatar {
width: 100%;
padding: 0;
margin: 0;
margin-top: 10vh;
border: none;
}
.btn {
// background: $uni-linear-gradient-btn-color;
background: #00aaff;
color: #fff;
width: 80%;
padding: 20rpx 0;
text-align: center;
border-radius: 15rpx;
margin-top: 10vh;
}
}
</style>

+ 14
- 7
pages/reject/reject.vue View File

@ -4,8 +4,8 @@
<!-- <navbar title="驳回" :leftClick="leftClick"></navbar> -->
<uv-form labelPosition="left" :model="form" :rules="rules" errorType="toast" ref="form" labelWidth="0">
<uv-form-item label="" prop="reason">
<uv-textarea v-model="form.reason" :maxlength="200" :height="120" count
<uv-form-item label="" prop="returnValue">
<uv-textarea v-model="form.returnValue" :maxlength="200" :height="120" count
placeholder="请输入驳回原因"></uv-textarea>
</uv-form-item>
@ -26,30 +26,37 @@
data() {
return {
form: {
reason: ''
returnValue: ''
},
rules: {
'reason': {
'returnValue': {
type: 'string',
required: true,
message: '请填写姓名',
message: '请填写驳回原因',
trigger: ['blur', 'change']
}
},
}
},
onLoad: function(options) {
this.form.id = options.orderId || ''
},
methods: {
//
submit() {
this.$refs.form.validate().then(res => {
}).catch(errors => {
uni.showToast({
icon: 'none',
title: '请填写驳回原因'
})
})
this.$api('editSchoolOrderError', this.form, res => {
if (res.code == 200) {
console.log(res);
}
})
},
//


+ 73
- 28
pages/repair/repair.vue View File

@ -1,28 +1,26 @@
<!-- 报修 -->
<template>
<view class="repair bx reserveSpace">
<!-- <view class="repair-title">
<text>申请报修</text>
</view> -->
<uv-form :model="form" :rules="rules" :useBeforeRead="true" ref="form" labelPosition="left" labelWidth="100">
<uv-form-item label="楼栋" prop="form.building" borderBottom>
<uv-input @focus="floorPickerOpen" placeholder="请选择楼层" v-model="form.building" border="none" :fontSize="30"></uv-input>
<uv-input @focus="floorPickerOpen" placeholder="请选择楼层" v-model="form.building" border="none"
:fontSize="30"></uv-input>
<template v-slot:right>
<uv-icon name="arrow-right"></uv-icon>
</template>
</uv-form-item>
<uv-form-item label="室号" prop="form.room" borderBottom>
<uv-input @focus="roomPickerOpen" placeholder="请选择室号" v-model="form.room" border="none" :fontSize="30"></uv-input>
<uv-input @focus="roomPickerOpen" placeholder="请选择室号" v-model="form.room" border="none"
:fontSize="30"></uv-input>
<template v-slot:right>
<uv-icon name="arrow-right"></uv-icon>
</template>
</uv-form-item>
<uv-form-item label="项目" prop="form.project" borderBottom>
<uv-input v-model="form.project" placeholder="请填写项目" :fontSize="30" border="none"></uv-input>
<uv-input v-model="form.project" placeholder="请填写维修物品名称" :fontSize="30" border="none"></uv-input>
</uv-form-item>
@ -30,22 +28,22 @@
<uv-input v-model="form.name" placeholder="请填写姓名" :fontSize="30" border="none"></uv-input>
</uv-form-item>
<uv-form-item label="简介" prop="form.intro" borderBottom>
<uv-textarea v-model="form.intro" :height="140" :maxlength="200" textStyle="font-size : 30rpx" count
placeholder="请输入内容"></uv-textarea>
</uv-form-item>
<uv-form-item label="电话号" prop="form.name" borderBottom>
<uv-input v-model="form.phone" placeholder="请填写电话号" border="none" :fontSize="30"></uv-input>
</uv-form-item>
<uv-form-item label="照片" prop="form.images" labelPosition="top">
<uv-form-item label="简介" prop="form.context" borderBottom>
<uv-textarea v-model="form.context" :height="140" :maxlength="200" textStyle="font-size : 30rpx" count
placeholder="请输入描述说明"></uv-textarea>
</uv-form-item>
<uv-form-item label="照片" prop="form.image" labelPosition="top">
<view class="image-list">
<view @click="openImageMenu(index)" v-for="(item,index) in form.images" :key="index"
<view @click="openImageMenu(index)" v-for="(item,index) in form.image" :key="index"
class="image-item">
<image :src="item" mode="widthFix"></image>
</view>
<view v-if="form.images.length < maxUpload" @click="uploadImage" class="upload">
<view v-if="form.image.length < maxUpload" @click="uploadImage" class="upload">
<uv-icon name="camera-fill" color="#3c9cff" size="50"></uv-icon>
</view>
</view>
@ -59,6 +57,7 @@
<!-- 报修地址选择(楼栋) -->
<uv-picker ref="floorPicker" :columns="floorList" :itemHeight="100" :round="20" keyName="label" title="选择楼栋"
@confirm="floorConfirm"></uv-picker>
<!-- 报修地址选择(室号) -->
<uv-picker ref="roomPicker" :columns="roomNumberList" :itemHeight="100" :round="20" keyName="label" title="选择室号"
@confirm="roomConfirm"></uv-picker>
@ -66,12 +65,19 @@
<!-- 图片操作菜单 -->
<uv-action-sheet ref="actionSheet" :actions="list" :round="20" cancelText="取消" title="图片操作"
@select="selectImageSheet"> </uv-action-sheet>
<!-- 隐私政策 -->
<PrivacyAgreementPoup ref="showPrivacy"></PrivacyAgreementPoup>
</view>
</template>
<script>
import PrivacyAgreementPoup from "@/components/PrivacyAgreementPoup/PrivacyAgreementPoup.vue";
export default {
name: 'Repair',
components: {
PrivacyAgreementPoup
},
data() {
return {
form: {
@ -80,16 +86,16 @@
project: '', //
phone: '', //
name: '', //
intro: '', //
images: []
context: '', //
image: []
},
rules: { //
'form.name': {
type: 'string',
required: true,
message: '请填写姓名',
trigger: ['blur', 'change']
}
// 'form.name': {
// type: 'string',
// required: true,
// message: '',
// trigger: ['blur', 'change']
// }
},
maxUpload: 4, //
list: [ //
@ -127,13 +133,23 @@
], //
}
},
onShow(){
if (wx.onNeedPrivacyAuthorization) {
console.log('onNeedPrivacyAuthorization');
wx.onNeedPrivacyAuthorization(resolve => {
console.log('onNeedPrivacyAuthorization');
this.resolvePrivacyAuthorization = resolve
this.$refs.showPrivacy.init(resolve)
})
}
},
methods: {
//
uploadImage(){
uploadImage() {
let self = this
this.$Oss.ossUploadImage({
success(res){
self.form.images.push(res)
success(res) {
self.form.image.push(res)
}
})
},
@ -193,9 +209,38 @@
//
submitRepair() {
console.log(this.form);
this.form.image = this.form.image.join()
this.$api('addSchoolOrder', this.form, res => {
if (res.code == 200) {
uni.showToast({
icon: 'none',
title: '提交成功'
});
this.cleanForm()
this.toRepairList()
}
})
},
//
cleanForm() {
this.form = {
building: '', //
room: '', //
project: '', //
phone: '', //
name: '', //
context: '', //
image: [] //
}
},
//
toRepairList(){
uni.switchTab({
url: '/pages/repairList/repairList'
})
}
}
}
</script>


+ 67
- 30
pages/repairList/repairList.vue View File

@ -5,27 +5,31 @@
</view>
<view class="repairList-main">
<view v-for="item in 10" class="repairItem">
<view v-for="item in repairList" :key="item.id" class="repairItem">
<view class="repairMain">
<!-- <view class="userName">用户名</view> -->
<view class="build">
<view>
<text style="margin-right: 10rpx;">楼栋:楼栋1</text>
<text>室号:A1001</text>
<text style="margin-right: 10rpx;">{{ item.building }}</text>
<text> {{ item.room }}</text>
</view>
<text style="font-size: 26rpx;">2024-12-12</text>
<text style="font-size: 26rpx;">{{ item.createTime }}</text>
</view>
<view class="desc">
近期我所在的学生宿舍楼X栋XXX室遇到了一个亟需解决的问题特此提交报修申请具体故障为宿舍内卫生间水龙头出现持续滴漏现象已持续多日不仅造成了水资源的浪费还影响了寝室的日常使用和休息环境夜间滴水声尤为明显干扰了同学们的睡眠质量我们初步检查未能自行解决判断可能是内部密封件老化或松动所致为尽快恢复宿舍正常生活环境恳请学校后勤部门能尽快安排专业维修人员前来检查并修复我们将积极配合维修工作确保宿舍设施尽快恢复正常使用感谢学校对我们学习生活环境的关心与支持
<uv-read-more :shadowStyle="shadowStyle" show-height="80rpx" fontSize="30rpx" :toggle="true">
<view>
{{ item.context }}
</view>
</uv-read-more>
</view>
<view class="repairImages">
<view v-for="(item,index) in urls" :key="index" class="image-item">
<image @click="viewImageAsList(index)" :src="item" mode="widthFix"></image>
<view v-for="(image,index) in item.image" :key="index" class="image-item">
<image @click="viewImageAsList(index,item.image)" :src="image" mode="widthFix"></image>
</view>
</view>
<view class="btns">
<view @click="toReject" class="btn">驳回</view>
<view @click="toFinish" class="btn">结单</view>
<view @click="toReject(item.id)" class="btn">驳回</view>
<view @click="toFinish(item.id)" class="btn">结单</view>
</view>
</view>
</view>
@ -37,65 +41,91 @@
export default {
data() {
return {
urls: [
'http://www.mxqih.top:666/logo.png',
'http://www.mxqih.top:666/logo.png',
'http://www.mxqih.top:666/logo.png'
],
list: [{
name: '待完成',
}, {
name: '已完成',
}],
current: 0,
currentIndex : 0
currentIndex: 0,
repairList: [], //
}
},
onShow() {
this.getRepairList()
},
methods: {
//
toReject() {
toReject(id) {
uni.navigateTo({
url: '/pages/reject/reject'
url: `/pages/reject/reject?orderId=${id}`
})
},
//
toFinish() {
toFinish(id) {
uni.navigateTo({
url: '/pages/finish/finish'
url: `/pages/finish/finish?orderId=${id}`
})
},
//
viewImageAsList(index) {
viewImageAsList(index, imgArr) {
this.currentIndex = index
this.$utils.previewImage({
current: this.currentIndex,
urls: this.urls
urls: imgArr
})
},
//
selectTag(tag){
selectTag(tag) {
console.log(tag);
},
//
getRepairList() {
this.$api('getSchoolOrderPage', this.form, res => {
if (res.code == 200) {
res.result.records.forEach(item => {
item.image ? item.image = item.image.split(',') : item.image = []
})
this.repairList = res.result.records
}
})
}
},
computed: {
shadowStyle() {
return {
// #ifndef APP-NVUE
backgroundImage: "linear-gradient(-180deg, rgba(255, 255, 255, 0) 0%, #fff 80%)",
// #endif
// #ifdef APP-NVUE
// nvuebackgroundImage
backgroundImage: "linear-gradient(to top, #fff, rgba(255, 255, 255, 0.5))",
// #endif
paddingTop: "50px",
marginTop: "-50px",
}
}
}
}
</script>
<style scoped>
.repairList{
.repairList {
background: #f8f8f8;
}
.tab{
.tab {
display: flex;
align-items: center;
height: 80rpx;
background: white;
margin-bottom: 20rpx;
}
.repairList-main {
min-height: 100vh;
}
@ -114,7 +144,8 @@
box-sizing: border-box;
padding-left: 20rpx;
}
/*
/*
.userName {
font-size: 32rpx;
margin: 10rpx 0rpx;
@ -128,7 +159,7 @@
}
.desc {
height: 200rpx;
height: 120rpx;
overflow-y: scroll;
margin-bottom: 20rpx;
}
@ -144,6 +175,12 @@
margin-left: 1%;
height: 180rpx;
overflow: hidden;
display: flex;
align-items: center;
justify-content: center;
padding: 20rpx;
background: #f5f5f5;
border-radius: 20rpx;
}
.image-item image {


BIN
static/bar/3.png View File

Before After
Width: 64  |  Height: 64  |  Size: 906 B Width: 256  |  Height: 256  |  Size: 10 KiB

BIN
static/bar/4.png View File

Before After
Width: 64  |  Height: 64  |  Size: 930 B Width: 256  |  Height: 256  |  Size: 10 KiB

+ 64
- 5
store/store.js View File

@ -8,15 +8,74 @@ import api from '@/api/api.js'
//Vuex.Store 构造器选项
const store = new Vuex.Store({
state: {
configList: [], //配置列表
configList: {}, //配置对象
userInfo : {},
},
getters: {
getConfig(state){
return state.configList
}
},
getters: {},
mutations: {
// 初始化配置
initConfig(state){
api('getConfig', res => {
initConfig(state) {
let config = ['preferential', 'wx']
config.forEach(k => {
api('getConfig', {
keyValue : k
}, res => {
if (res.code == 200) {
state.configList[k] = res.result
}
})
})
let apiConfig = [ 'getPrivacyPolicy' , 'getUserAgreement' ] //需要访问不同接口才能得到的配置数据
let key = ['privacyAgreement','userAgreement']
apiConfig.forEach((item,index) => {
api(item,res => {
state.configList[key[index]] = res.result
})
})
},
login(state) {
uni.login({
success(res) {
console.log(res);
if (res.errMsg != "login:ok") {
return
}
api('loginLogin', {
code: res.code
}, res => {
if (res.code != 200) {
return
}
state.userInfo = res.result.userInfo
uni.setStorageSync('token', res.result.token)
if (!state.userInfo.nickName || !state.userInfo.headImage) {
uni.navigateTo({
url: '/pages/login/wxUserInfo'
})
}else{
uni.switchTab({
url: '/pages/repair/repair'
})
}
})
},
fail(err) {
console.error(err)
}
})
},
getUserInfo(state) {
api('infoGetInfo', res => {
if(res.code == 200){
state.configList = res.result
state.userInfo = res.result
}
})
},


+ 33
- 0
uni_modules/uni-badge/changelog.md View File

@ -0,0 +1,33 @@
## 1.2.2(2023-01-28)
- 修复 运行/打包 控制台警告问题
## 1.2.1(2022-09-05)
- 修复 当 text 超过 max-num 时,badge 的宽度计算是根据 text 的长度计算,更改为 css 计算实际展示宽度,详见:[https://ask.dcloud.net.cn/question/150473](https://ask.dcloud.net.cn/question/150473)
## 1.2.0(2021-11-19)
- 优化 组件UI,并提供设计资源,详见:[https://uniapp.dcloud.io/component/uniui/resource](https://uniapp.dcloud.io/component/uniui/resource)
- 文档迁移,详见:[https://uniapp.dcloud.io/component/uniui/uni-badge](https://uniapp.dcloud.io/component/uniui/uni-badge)
## 1.1.7(2021-11-08)
- 优化 升级ui
- 修改 size 属性默认值调整为 small
- 修改 type 属性,默认值调整为 error,info 替换 default
## 1.1.6(2021-09-22)
- 修复 在字节小程序上样式不生效的 bug
## 1.1.5(2021-07-30)
- 组件兼容 vue3,如何创建vue3项目,详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834)
## 1.1.4(2021-07-29)
- 修复 去掉 nvue 不支持css 的 align-self 属性,nvue 下不暂支持 absolute 属性
## 1.1.3(2021-06-24)
- 优化 示例项目
## 1.1.1(2021-05-12)
- 新增 组件示例地址
## 1.1.0(2021-05-12)
- 新增 uni-badge 的 absolute 属性,支持定位
- 新增 uni-badge 的 offset 属性,支持定位偏移
- 新增 uni-badge 的 is-dot 属性,支持仅显示有一个小点
- 新增 uni-badge 的 max-num 属性,支持自定义封顶的数字值,超过 99 显示99+
- 优化 uni-badge 属性 custom-style, 支持以对象形式自定义样式
## 1.0.7(2021-05-07)
- 修复 uni-badge 在 App 端,数字小于10时不是圆形的bug
- 修复 uni-badge 在父元素不是 flex 布局时,宽度缩小的bug
- 新增 uni-badge 属性 custom-style, 支持自定义样式
## 1.0.6(2021-02-04)
- 调整为uni_modules目录规范

+ 268
- 0
uni_modules/uni-badge/components/uni-badge/uni-badge.vue View File

@ -0,0 +1,268 @@
<template>
<view class="uni-badge--x">
<slot />
<text v-if="text" :class="classNames" :style="[positionStyle, customStyle, dotStyle]"
class="uni-badge" @click="onClick()">{{displayValue}}</text>
</view>
</template>
<script>
/**
* Badge 数字角标
* @description 数字角标一般和其它控件列表9宫格等配合使用用于进行数量提示默认为实心灰色背景
* @tutorial https://ext.dcloud.net.cn/plugin?id=21
* @property {String} text 角标内容
* @property {String} size = [normal|small] 角标内容
* @property {String} type = [info|primary|success|warning|error] 颜色类型
* @value info 灰色
* @value primary 蓝色
* @value success 绿色
* @value warning 黄色
* @value error 红色
* @property {String} inverted = [true|false] 是否无需背景颜色
* @property {Number} maxNum 展示封顶的数字值超过 99 显示 99+
* @property {String} absolute = [rightTop|rightBottom|leftBottom|leftTop] 开启绝对定位, 角标将定位到其包裹的标签的四角上
* @value rightTop 右上
* @value rightBottom 右下
* @value leftTop 左上
* @value leftBottom 左下
* @property {Array[number]} offset 距定位角中心点的偏移量只有存在 absolute 属性时有效例如[-10, -10] 表示向外偏移 10px[10, 10] 表示向 absolute 指定的内偏移 10px
* @property {String} isDot = [true|false] 是否显示为一个小点
* @event {Function} click 点击 Badge 触发事件
* @example <uni-badge text="1"></uni-badge>
*/
export default {
name: 'UniBadge',
emits: ['click'],
props: {
type: {
type: String,
default: 'error'
},
inverted: {
type: Boolean,
default: false
},
isDot: {
type: Boolean,
default: false
},
maxNum: {
type: Number,
default: 99
},
absolute: {
type: String,
default: ''
},
offset: {
type: Array,
default () {
return [0, 0]
}
},
text: {
type: [String, Number],
default: ''
},
size: {
type: String,
default: 'small'
},
customStyle: {
type: Object,
default () {
return {}
}
}
},
data() {
return {};
},
computed: {
width() {
return String(this.text).length * 8 + 12
},
classNames() {
const {
inverted,
type,
size,
absolute
} = this
return [
inverted ? 'uni-badge--' + type + '-inverted' : '',
'uni-badge--' + type,
'uni-badge--' + size,
absolute ? 'uni-badge--absolute' : ''
].join(' ')
},
positionStyle() {
if (!this.absolute) return {}
let w = this.width / 2,
h = 10
if (this.isDot) {
w = 5
h = 5
}
const x = `${- w + this.offset[0]}px`
const y = `${- h + this.offset[1]}px`
const whiteList = {
rightTop: {
right: x,
top: y
},
rightBottom: {
right: x,
bottom: y
},
leftBottom: {
left: x,
bottom: y
},
leftTop: {
left: x,
top: y
}
}
const match = whiteList[this.absolute]
return match ? match : whiteList['rightTop']
},
dotStyle() {
if (!this.isDot) return {}
return {
width: '10px',
minWidth: '0',
height: '10px',
padding: '0',
borderRadius: '10px'
}
},
displayValue() {
const {
isDot,
text,
maxNum
} = this
return isDot ? '' : (Number(text) > maxNum ? `${maxNum}+` : text)
}
},
methods: {
onClick() {
this.$emit('click');
}
}
};
</script>
<style lang="scss" >
$uni-primary: #2979ff !default;
$uni-success: #4cd964 !default;
$uni-warning: #f0ad4e !default;
$uni-error: #dd524d !default;
$uni-info: #909399 !default;
$bage-size: 12px;
$bage-small: scale(0.8);
.uni-badge--x {
/* #ifdef APP-NVUE */
// align-self: flex-start;
/* #endif */
/* #ifndef APP-NVUE */
display: inline-block;
/* #endif */
position: relative;
}
.uni-badge--absolute {
position: absolute;
}
.uni-badge--small {
transform: $bage-small;
transform-origin: center center;
}
.uni-badge {
/* #ifndef APP-NVUE */
display: flex;
overflow: hidden;
box-sizing: border-box;
font-feature-settings: "tnum";
min-width: 20px;
/* #endif */
justify-content: center;
flex-direction: row;
height: 20px;
padding: 0 4px;
line-height: 18px;
color: #fff;
border-radius: 100px;
background-color: $uni-info;
background-color: transparent;
border: 1px solid #fff;
text-align: center;
font-family: 'Helvetica Neue', Helvetica, sans-serif;
font-size: $bage-size;
/* #ifdef H5 */
z-index: 999;
cursor: pointer;
/* #endif */
&--info {
color: #fff;
background-color: $uni-info;
}
&--primary {
background-color: $uni-primary;
}
&--success {
background-color: $uni-success;
}
&--warning {
background-color: $uni-warning;
}
&--error {
background-color: $uni-error;
}
&--inverted {
padding: 0 5px 0 0;
color: $uni-info;
}
&--info-inverted {
color: $uni-info;
background-color: transparent;
}
&--primary-inverted {
color: $uni-primary;
background-color: transparent;
}
&--success-inverted {
color: $uni-success;
background-color: transparent;
}
&--warning-inverted {
color: $uni-warning;
background-color: transparent;
}
&--error-inverted {
color: $uni-error;
background-color: transparent;
}
}
</style>

+ 85
- 0
uni_modules/uni-badge/package.json View File

@ -0,0 +1,85 @@
{
"id": "uni-badge",
"displayName": "uni-badge 数字角标",
"version": "1.2.2",
"description": "数字角标(徽章)组件,在元素周围展示消息提醒,一般用于列表、九宫格、按钮等地方。",
"keywords": [
"",
"badge",
"uni-ui",
"uniui",
"数字角标",
"徽章"
],
"repository": "https://github.com/dcloudio/uni-ui",
"engines": {
"HBuilderX": ""
},
"directories": {
"example": "../../temps/example_temps"
},
"dcloudext": {
"sale": {
"regular": {
"price": "0.00"
},
"sourcecode": {
"price": "0.00"
}
},
"contact": {
"qq": ""
},
"declaration": {
"ads": "无",
"data": "无",
"permissions": "无"
},
"npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui",
"type": "component-vue"
},
"uni_modules": {
"dependencies": ["uni-scss"],
"encrypt": [],
"platforms": {
"cloud": {
"tcb": "y",
"aliyun": "y"
},
"client": {
"App": {
"app-vue": "y",
"app-nvue": "y"
},
"H5-mobile": {
"Safari": "y",
"Android Browser": "y",
"微信浏览器(Android)": "y",
"QQ浏览器(Android)": "y"
},
"H5-pc": {
"Chrome": "y",
"IE": "y",
"Edge": "y",
"Firefox": "y",
"Safari": "y"
},
"小程序": {
"微信": "y",
"阿里": "y",
"百度": "y",
"字节跳动": "y",
"QQ": "y"
},
"快应用": {
"华为": "y",
"联盟": "y"
},
"Vue": {
"vue2": "y",
"vue3": "y"
}
}
}
}
}

+ 10
- 0
uni_modules/uni-badge/readme.md View File

@ -0,0 +1,10 @@
## Badge 数字角标
> **组件名:uni-badge**
> 代码块: `uBadge`
数字角标一般和其它控件(列表、9宫格等)配合使用,用于进行数量提示,默认为实心灰色背景,
### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-badge)
#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839

+ 46
- 0
uni_modules/uni-list/changelog.md View File

@ -0,0 +1,46 @@
## 1.2.14(2023-04-14)
- 优化 uni-list-chat 具名插槽`header` 非app端套一层元素,方便使用时通过外层元素定位实现样式修改
## 1.2.13(2023-03-03)
- uni-list-chat 新增 支持具名插槽`header`
## 1.2.12(2023-02-01)
- 新增 列表图标新增 customPrefix 属性 ,用法 [详见](https://uniapp.dcloud.net.cn/component/uniui/uni-icons.html#icons-props)
## 1.2.11(2023-01-31)
- 修复 无反馈效果呈现的bug
## 1.2.9(2022-11-22)
- 修复 uni-list-chat 在vue3下跳转报错的bug
## 1.2.8(2022-11-21)
- 修复 uni-list-chat avatar属性 值为本地路径时错误的问题
## 1.2.7(2022-11-21)
- 修复 uni-list-chat avatar属性 在腾讯云版uniCloud下错误的问题
## 1.2.6(2022-11-18)
- 修复 uni-list-chat note属性 支持:“草稿”字样功能 文本少1位的问题
## 1.2.5(2022-11-15)
- 修复 uni-list-item 的 customStyle 属性 padding值在 H5端 无效的bug
## 1.2.4(2022-11-15)
- 修复 uni-list-item 的 customStyle 属性 padding值在nvue(vue2)下无效的bug
## 1.2.3(2022-11-14)
- uni-list-chat 新增 avatar 支持 fileId
## 1.2.2(2022-11-11)
- uni-list 新增属性 render-reverse 详情参考:[https://uniapp.dcloud.net.cn/component/list.html](https://uniapp.dcloud.net.cn/component/list.html)
- uni-list-chat note属性 支持:“草稿”字样 加红显示 详情参考uni-im:[https://ext.dcloud.net.cn/plugin?name=uni-im](https://ext.dcloud.net.cn/plugin?name=uni-im)
- uni-list-item 新增属性 customStyle 支持设置padding、backgroundColor
## 1.2.1(2022-03-30)
- 删除无用文件
## 1.2.0(2021-11-23)
- 优化 组件UI,并提供设计资源,详见:[https://uniapp.dcloud.io/component/uniui/resource](https://uniapp.dcloud.io/component/uniui/resource)
- 文档迁移,详见:[https://uniapp.dcloud.io/component/uniui/uni-list](https://uniapp.dcloud.io/component/uniui/uni-list)
## 1.1.3(2021-08-30)
- 修复 在vue3中to属性在发行应用的时候报错的bug
## 1.1.2(2021-07-30)
- 优化 vue3下事件警告的问题
## 1.1.1(2021-07-21)
- 修复 与其他组件嵌套使用时,点击失效的Bug
## 1.1.0(2021-07-13)
- 组件兼容 vue3,如何创建vue3项目,详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834)
## 1.0.17(2021-05-12)
- 新增 组件示例地址
## 1.0.16(2021-02-05)
- 优化 组件引用关系,通过uni_modules引用组件
## 1.0.15(2021-02-05)
- 调整为uni_modules目录规范
- 修复 uni-list-chat 角标显示不正常的问题

+ 107
- 0
uni_modules/uni-list/components/uni-list-ad/uni-list-ad.vue View File

@ -0,0 +1,107 @@
<template>
<!-- #ifdef APP-NVUE -->
<cell>
<!-- #endif -->
<view class="uni-list-ad">
<view v-if="borderShow" :class="{'uni-list--border':border,'uni-list-item--first':isFirstChild}"></view>
<ad style="width: 200px;height: 300px;border-width: 1px;border-color: red;border-style: solid;" adpid="1111111111"
unit-id="" appid="" apid="" type="feed" @error="aderror" @close="closeAd"></ad>
</view>
<!-- #ifdef APP-NVUE -->
</cell>
<!-- #endif -->
</template>
<script>
// #ifdef APP-NVUE
const dom = uni.requireNativePlugin('dom');
// #endif
export default {
name: 'UniListAd',
props: {
title: {
type: String,
default: '',
}
},
// inject: ['list'],
data() {
return {
isFirstChild: false,
border: false,
borderShow: true,
}
},
mounted() {
this.list = this.getForm()
if (this.list) {
if (!this.list.firstChildAppend) {
this.list.firstChildAppend = true
this.isFirstChild = true
}
this.border = this.list.border
}
},
methods: {
/**
* 获取父元素实例
*/
getForm(name = 'uniList') {
let parent = this.$parent;
let parentName = parent.$options.name;
while (parentName !== name) {
parent = parent.$parent;
if (!parent) return false
parentName = parent.$options.name;
}
return parent;
},
aderror(e) {
console.log("aderror: " + JSON.stringify(e.detail));
},
closeAd(e) {
this.borderShow = false
}
}
}
</script>
<style lang="scss" >
.uni-list-ad {
position: relative;
border: 1px red solid;
}
.uni-list--border {
position: relative;
padding-bottom: 1px;
/* #ifdef APP-PLUS */
border-top-color: $uni-border-color;
border-top-style: solid;
border-top-width: 0.5px;
/* #endif */
margin-left: $uni-spacing-row-lg;
}
/* #ifndef APP-NVUE */
.uni-list--border:after {
position: absolute;
top: 0;
right: 0;
left: 0;
height: 1px;
content: '';
-webkit-transform: scaleY(.5);
transform: scaleY(.5);
background-color: $uni-border-color;
}
.uni-list-item--first:after {
height: 0px;
}
/* #endif */
</style>

+ 58
- 0
uni_modules/uni-list/components/uni-list-chat/uni-list-chat.scss View File

@ -0,0 +1,58 @@
/**
* 这里是 uni-list 组件内置的常用样式变量
* 如果需要覆盖样式这里提供了基本的组件样式变量您可以尝试修改这里的变量去完成样式替换而不用去修改源码
*
*/
// 背景色
$background-color : #fff;
// 分割线颜色
$divide-line-color : #e5e5e5;
// 默认头像大小如需要修改此值注意同步修改 js 中的值 const avatarWidth = xx 目前只支持方形头像
// nvue 页面不支持修改头像大小
$avatar-width : 45px ;
// 头像边框
$avatar-border-radius: 5px;
$avatar-border-color: #eee;
$avatar-border-width: 1px;
// 标题文字样式
$title-size : 16px;
$title-color : #3b4144;
$title-weight : normal;
// 描述文字样式
$note-size : 12px;
$note-color : #999;
$note-weight : normal;
// 右侧额外内容默认样式
$right-text-size : 12px;
$right-text-color : #999;
$right-text-weight : normal;
// 角标样式
// nvue 页面不支持修改圆点位置以及大小
// 角标在左侧时角标的位置默认为 0 负数左/下移动正数右/上移动
$badge-left: 0px;
$badge-top: 0px;
// 显示圆点时圆点大小
$dot-width: 10px;
$dot-height: 10px;
// 显示角标时角标大小和字体大小
$badge-size : 18px;
$badge-font : 12px;
// 显示角标时角标前景色
$badge-color : #fff;
// 显示角标时角标背景色
$badge-background-color : #ff5a5f;
// 显示角标时角标左右间距
$badge-space : 6px;
// 状态样式
// 选中颜色
$hover : #f5f5f5;

+ 593
- 0
uni_modules/uni-list/components/uni-list-chat/uni-list-chat.vue View File

@ -0,0 +1,593 @@
<template>
<!-- #ifdef APP-NVUE -->
<cell>
<!-- #endif -->
<view :hover-class="!clickable && !link ? '' : 'uni-list-chat--hover'" class="uni-list-chat" @click.stop="onClick">
<view :class="{ 'uni-list--border': border, 'uni-list-chat--first': isFirstChild }"></view>
<view class="uni-list-chat__container">
<view class="uni-list-chat__header-warp">
<view v-if="avatarCircle || avatarList.length === 0" class="uni-list-chat__header" :class="{ 'header--circle': avatarCircle }">
<image class="uni-list-chat__header-image" :class="{ 'header--circle': avatarCircle }" :src="avatarUrl" mode="aspectFill"></image>
</view>
<!-- 头像组 -->
<view v-else class="uni-list-chat__header">
<view v-for="(item, index) in avatarList" :key="index" class="uni-list-chat__header-box" :class="computedAvatar"
:style="{ width: imageWidth + 'px', height: imageWidth + 'px' }">
<image class="uni-list-chat__header-image" :style="{ width: imageWidth + 'px', height: imageWidth + 'px' }" :src="item.url"
mode="aspectFill"></image>
</view>
</view>
</view>
<!-- #ifndef APP -->
<view class="slot-header">
<!-- #endif -->
<slot name="header"></slot>
<!-- #ifndef APP -->
</view>
<!-- #endif -->
<view v-if="badgeText && badgePositon === 'left'" class="uni-list-chat__badge uni-list-chat__badge-pos" :class="[isSingle]">
<text class="uni-list-chat__badge-text">{{ badgeText === 'dot' ? '' : badgeText }}</text>
</view>
<view class="uni-list-chat__content">
<view class="uni-list-chat__content-main">
<text class="uni-list-chat__content-title uni-ellipsis">{{ title }}</text>
<view style="flex-direction: row;">
<text class="draft" v-if="isDraft">[草稿]</text>
<text class="uni-list-chat__content-note uni-ellipsis">{{isDraft?note.slice(14):note}}</text>
</view>
</view>
<view class="uni-list-chat__content-extra">
<slot>
<text class="uni-list-chat__content-extra-text">{{ time }}</text>
<view v-if="badgeText && badgePositon === 'right'" class="uni-list-chat__badge" :class="[isSingle, badgePositon === 'right' ? 'uni-list-chat--right' : '']">
<text class="uni-list-chat__badge-text">{{ badgeText === 'dot' ? '' : badgeText }}</text>
</view>
</slot>
</view>
</view>
</view>
</view>
<!-- #ifdef APP-NVUE -->
</cell>
<!-- #endif -->
</template>
<script>
//
const avatarWidth = 45;
/**
* ListChat 聊天列表
* @description 聊天列表,用于创建聊天类列表
* @tutorial https://ext.dcloud.net.cn/plugin?id=24
* @property {String} title 标题
* @property {String} note 描述
* @property {Boolean} clickable = [true|false] 是否开启点击反馈默认为false
* @property {String} badgeText 数字角标内容
* @property {String} badgePositon = [left|right] 角标位置默认为 right
* @property {String} link = [falsenavigateTo|redirectTo|reLaunch|switchTab] 是否展示右侧箭头并开启点击反馈默认为false
* @value false 不开启
* @value navigateTo uni.navigateTo()
* @value redirectTo uni.redirectTo()
* @value reLaunch uni.reLaunch()
* @value switchTab uni.switchTab()
* @property {String | PageURIString} to 跳转目标页面
* @property {String} time 右侧时间显示
* @property {Boolean} avatarCircle = [true|false] 是否显示圆形头像默认为false
* @property {String} avatar 头像地址avatarCircle 不填时生效
* @property {Array} avatarList 头像组格式为 [{url:''}]
* @event {Function} click 点击 uniListChat 触发事件
*/
export default {
name: 'UniListChat',
emits:['click'],
props: {
title: {
type: String,
default: ''
},
note: {
type: String,
default: ''
},
clickable: {
type: Boolean,
default: false
},
link: {
type: [Boolean, String],
default: false
},
to: {
type: String,
default: ''
},
badgeText: {
type: [String, Number],
default: ''
},
badgePositon: {
type: String,
default: 'right'
},
time: {
type: String,
default: ''
},
avatarCircle: {
type: Boolean,
default: false
},
avatar: {
type: String,
default: ''
},
avatarList: {
type: Array,
default () {
return [];
}
}
},
// inject: ['list'],
computed: {
isDraft(){
return this.note.slice(0,14) == '[uni-im-draft]'
},
isSingle() {
if (this.badgeText === 'dot') {
return 'uni-badge--dot';
} else {
const badgeText = this.badgeText.toString();
if (badgeText.length > 1) {
return 'uni-badge--complex';
} else {
return 'uni-badge--single';
}
}
},
computedAvatar() {
if (this.avatarList.length > 4) {
this.imageWidth = avatarWidth * 0.31;
return 'avatarItem--3';
} else if (this.avatarList.length > 1) {
this.imageWidth = avatarWidth * 0.47;
return 'avatarItem--2';
} else {
this.imageWidth = avatarWidth;
return 'avatarItem--1';
}
}
},
watch: {
avatar:{
handler(avatar) {
if(avatar.substr(0,8) == 'cloud://'){
uniCloud.getTempFileURL({
fileList: [avatar]
}).then(res=>{
// console.log(res);
// uniCloud
let fileList = res.fileList || res.result.fileList
this.avatarUrl = fileList[0].tempFileURL
})
}else{
this.avatarUrl = avatar
}
},
immediate: true
}
},
data() {
return {
isFirstChild: false,
border: true,
// avatarList: 3,
imageWidth: 50,
avatarUrl:''
};
},
mounted() {
this.list = this.getForm()
if (this.list) {
if (!this.list.firstChildAppend) {
this.list.firstChildAppend = true;
this.isFirstChild = true;
}
this.border = this.list.border;
}
},
methods: {
/**
* 获取父元素实例
*/
getForm(name = 'uniList') {
let parent = this.$parent;
let parentName = parent.$options.name;
while (parentName !== name) {
parent = parent.$parent;
if (!parent) return false
parentName = parent.$options.name;
}
return parent;
},
onClick() {
if (this.to !== '') {
this.openPage();
return;
}
if (this.clickable || this.link) {
this.$emit('click', {
data: {}
});
}
},
openPage() {
if (['navigateTo', 'redirectTo', 'reLaunch', 'switchTab'].indexOf(this.link) !== -1) {
this.pageApi(this.link);
} else {
this.pageApi('navigateTo');
}
},
pageApi(api) {
let callback = {
url: this.to,
success: res => {
this.$emit('click', {
data: res
});
},
fail: err => {
this.$emit('click', {
data: err
});
}
}
switch (api) {
case 'navigateTo':
uni.navigateTo(callback)
break
case 'redirectTo':
uni.redirectTo(callback)
break
case 'reLaunch':
uni.reLaunch(callback)
break
case 'switchTab':
uni.switchTab(callback)
break
default:
uni.navigateTo(callback)
}
}
}
};
</script>
<style lang="scss" >
$uni-font-size-lg:16px;
$uni-spacing-row-sm: 5px;
$uni-spacing-row-base: 10px;
$uni-spacing-row-lg: 15px;
$background-color: #fff;
$divide-line-color: #e5e5e5;
$avatar-width: 45px;
$avatar-border-radius: 5px;
$avatar-border-color: #eee;
$avatar-border-width: 1px;
$title-size: 16px;
$title-color: #3b4144;
$title-weight: normal;
$note-size: 12px;
$note-color: #999;
$note-weight: normal;
$right-text-size: 12px;
$right-text-color: #999;
$right-text-weight: normal;
$badge-left: 0px;
$badge-top: 0px;
$dot-width: 10px;
$dot-height: 10px;
$badge-size: 18px;
$badge-font: 12px;
$badge-color: #fff;
$badge-background-color: #ff5a5f;
$badge-space: 6px;
$hover: #f5f5f5;
.uni-list-chat {
font-size: $uni-font-size-lg;
position: relative;
flex-direction: column;
justify-content: space-between;
background-color: $background-color;
}
// .uni-list-chat--disabled {
// opacity: 0.3;
// }
.uni-list-chat--hover {
background-color: $hover;
}
.uni-list--border {
position: relative;
margin-left: $uni-spacing-row-lg;
/* #ifdef APP-PLUS */
border-top-color: $divide-line-color;
border-top-style: solid;
border-top-width: 0.5px;
/* #endif */
}
/* #ifndef APP-NVUE */
.uni-list--border:after {
position: absolute;
top: 0;
right: 0;
left: 0;
height: 1px;
content: '';
-webkit-transform: scaleY(0.5);
transform: scaleY(0.5);
background-color: $divide-line-color;
}
.uni-list-item--first:after {
height: 0px;
}
/* #endif */
.uni-list-chat--first {
border-top-width: 0px;
}
.uni-ellipsis {
/* #ifndef APP-NVUE */
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
/* #endif */
/* #ifdef APP-NVUE */
lines: 1;
/* #endif */
}
.uni-ellipsis-2 {
/* #ifndef APP-NVUE */
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
/* #endif */
/* #ifdef APP-NVUE */
lines: 2;
/* #endif */
}
.uni-list-chat__container {
position: relative;
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: row;
flex: 1;
padding: $uni-spacing-row-base $uni-spacing-row-lg;
position: relative;
overflow: hidden;
}
.uni-list-chat__header-warp {
position: relative;
}
.uni-list-chat__header {
/* #ifndef APP-NVUE */
display: flex;
align-content: center;
/* #endif */
flex-direction: row;
justify-content: center;
align-items: center;
flex-wrap: wrap-reverse;
/* #ifdef APP-NVUE */
width: 50px;
height: 50px;
/* #endif */
/* #ifndef APP-NVUE */
width: $avatar-width;
height: $avatar-width;
/* #endif */
border-radius: $avatar-border-radius;
border-color: $avatar-border-color;
border-width: $avatar-border-width;
border-style: solid;
overflow: hidden;
}
.uni-list-chat__header-box {
/* #ifndef APP-PLUS */
box-sizing: border-box;
display: flex;
width: $avatar-width;
height: $avatar-width;
/* #endif */
/* #ifdef APP-NVUE */
width: 50px;
height: 50px;
/* #endif */
overflow: hidden;
border-radius: 2px;
}
.uni-list-chat__header-image {
margin: 1px;
/* #ifdef APP-NVUE */
width: 50px;
height: 50px;
/* #endif */
/* #ifndef APP-NVUE */
width: $avatar-width;
height: $avatar-width;
/* #endif */
}
/* #ifndef APP-NVUE */
.uni-list-chat__header-image {
display: block;
width: 100%;
height: 100%;
}
.avatarItem--1 {
width: 100%;
height: 100%;
}
.avatarItem--2 {
width: 47%;
height: 47%;
}
.avatarItem--3 {
width: 32%;
height: 32%;
}
/* #endif */
.header--circle {
border-radius: 50%;
}
.uni-list-chat__content {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: row;
flex: 1;
overflow: hidden;
padding: 2px 0;
}
.uni-list-chat__content-main {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: column;
justify-content: space-between;
padding-left: $uni-spacing-row-base;
flex: 1;
overflow: hidden;
}
.uni-list-chat__content-title {
font-size: $title-size;
color: $title-color;
font-weight: $title-weight;
overflow: hidden;
}
.draft ,.uni-list-chat__content-note {
margin-top: 3px;
color: $note-color;
font-size: $note-size;
font-weight: $title-weight;
overflow: hidden;
}
.draft{
color: #eb3a41;
/* #ifndef APP-NVUE */
flex-shrink: 0;
/* #endif */
padding-right: 3px;
}
.uni-list-chat__content-extra {
/* #ifndef APP-NVUE */
flex-shrink: 0;
display: flex;
/* #endif */
flex-direction: column;
justify-content: space-between;
align-items: flex-end;
margin-left: 5px;
}
.uni-list-chat__content-extra-text {
color: $right-text-color;
font-size: $right-text-size;
font-weight: $right-text-weight;
overflow: hidden;
}
.uni-list-chat__badge-pos {
position: absolute;
/* #ifdef APP-NVUE */
left: 55px;
top: 3px;
/* #endif */
/* #ifndef APP-NVUE */
left: calc(#{$avatar-width} + 10px - #{$badge-space} + #{$badge-left});
top: calc(#{$uni-spacing-row-base}/ 2 + 1px + #{$badge-top});
/* #endif */
}
.uni-list-chat__badge {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
justify-content: center;
align-items: center;
border-radius: 100px;
background-color: $badge-background-color;
}
.uni-list-chat__badge-text {
color: $badge-color;
font-size: $badge-font;
}
.uni-badge--single {
/* #ifndef APP-NVUE */
// left: calc(#{$avatar-width} + 7px + #{$badge-left});
/* #endif */
width: $badge-size;
height: $badge-size;
}
.uni-badge--complex {
/* #ifdef APP-NVUE */
left: 50px;
/* #endif */
/* #ifndef APP-NVUE */
width: auto;
/* #endif */
height: $badge-size;
padding: 0 $badge-space;
}
.uni-badge--dot {
/* #ifdef APP-NVUE */
left: 60px;
top: 6px;
/* #endif */
/* #ifndef APP-NVUE */
left: calc(#{$avatar-width} + 15px - #{$dot-width}/ 2 + 1px + #{$badge-left});
/* #endif */
width: $dot-width;
height: $dot-height;
padding: 0;
}
.uni-list-chat--right {
/* #ifdef APP-NVUE */
left: 0;
/* #endif */
}
</style>

+ 534
- 0
uni_modules/uni-list/components/uni-list-item/uni-list-item.vue View File

@ -0,0 +1,534 @@
<template>
<!-- #ifdef APP-NVUE -->
<cell :keep-scroll-position="keepScrollPosition">
<!-- #endif -->
<view :class="{ 'uni-list-item--disabled': disabled }" :style="{'background-color':customStyle.backgroundColor}"
:hover-class="(!clickable && !link) || disabled || showSwitch ? '' : 'uni-list-item--hover'"
class="uni-list-item" @click="onClick">
<view v-if="!isFirstChild" class="border--left" :class="{ 'uni-list--border': border }"></view>
<view class="uni-list-item__container"
:class="{ 'container--right': showArrow || link, 'flex--direction': direction === 'column'}"
:style="{paddingTop:padding.top,paddingLeft:padding.left,paddingRight:padding.right,paddingBottom:padding.bottom}">
<slot name="header">
<view class="uni-list-item__header">
<view v-if="thumb" class="uni-list-item__icon">
<image :src="thumb" class="uni-list-item__icon-img" :class="['uni-list--' + thumbSize]" />
</view>
<view v-else-if="showExtraIcon" class="uni-list-item__icon">
<uni-icons :customPrefix="extraIcon.customPrefix" :color="extraIcon.color" :size="extraIcon.size" :type="extraIcon.type" />
</view>
</view>
</slot>
<slot name="body">
<view class="uni-list-item__content"
:class="{ 'uni-list-item__content--center': thumb || showExtraIcon || showBadge || showSwitch }">
<text v-if="title" class="uni-list-item__content-title"
:class="[ellipsis !== 0 && ellipsis <= 2 ? 'uni-ellipsis-' + ellipsis : '']">{{ title }}</text>
<text v-if="note" class="uni-list-item__content-note">{{ note }}</text>
</view>
</slot>
<slot name="footer">
<view v-if="rightText || showBadge || showSwitch" class="uni-list-item__extra"
:class="{ 'flex--justify': direction === 'column' }">
<text v-if="rightText" class="uni-list-item__extra-text">{{ rightText }}</text>
<uni-badge v-if="showBadge" :type="badgeType" :text="badgeText" :custom-style="badgeStyle" />
<switch v-if="showSwitch" :disabled="disabled" :checked="switchChecked"
@change="onSwitchChange" />
</view>
</slot>
</view>
<uni-icons v-if="showArrow || link" :size="16" class="uni-icon-wrapper" color="#bbb" type="arrowright" />
</view>
<!-- #ifdef APP-NVUE -->
</cell>
<!-- #endif -->
</template>
<script>
/**
* ListItem 列表子组件
* @description 列表子组件
* @tutorial https://ext.dcloud.net.cn/plugin?id=24
* @property {String} title 标题
* @property {String} note 描述
* @property {String} thumb 左侧缩略图若thumb有值则不会显示扩展图标
* @property {String} thumbSize = [lg|base|sm] 略缩图大小
* @value lg 大图
* @value base 一般
* @value sm 小图
* @property {String} badgeText 数字角标内容
* @property {String} badgeType 数字角标类型参考[uni-icons](https://ext.dcloud.net.cn/plugin?id=21)
* @property {Object} badgeStyle 数字角标样式
* @property {String} rightText 右侧文字内容
* @property {Boolean} disabled = [true|false] 是否禁用
* @property {Boolean} clickable = [true|false] 是否开启点击反馈
* @property {String} link = [navigateTo|redirectTo|reLaunch|switchTab] 是否展示右侧箭头并开启点击反馈
* @value navigateTo uni.navigateTo()
* @value redirectTo uni.redirectTo()
* @value reLaunch uni.reLaunch()
* @value switchTab uni.switchTab()
* @property {String | PageURIString} to 跳转目标页面
* @property {Boolean} showBadge = [true|false] 是否显示数字角标
* @property {Boolean} showSwitch = [true|false] 是否显示Switch
* @property {Boolean} switchChecked = [true|false] Switch是否被选中
* @property {Boolean} showExtraIcon = [true|false] 左侧是否显示扩展图标
* @property {Object} extraIcon 扩展图标参数格式为 {color: '#4cd964',size: '22',type: 'spinner'}
* @property {String} direction = [row|column] 排版方向
* @value row 水平排列
* @value column 垂直排列
* @event {Function} click 点击 uniListItem 触发事件
* @event {Function} switchChange 点击切换 Switch 时触发
*/
export default {
name: 'UniListItem',
emits: ['click', 'switchChange'],
props: {
direction: {
type: String,
default: 'row'
},
title: {
type: String,
default: ''
},
note: {
type: String,
default: ''
},
ellipsis: {
type: [Number, String],
default: 0
},
disabled: {
type: [Boolean, String],
default: false
},
clickable: {
type: Boolean,
default: false
},
showArrow: {
type: [Boolean, String],
default: false
},
link: {
type: [Boolean, String],
default: false
},
to: {
type: String,
default: ''
},
showBadge: {
type: [Boolean, String],
default: false
},
showSwitch: {
type: [Boolean, String],
default: false
},
switchChecked: {
type: [Boolean, String],
default: false
},
badgeText: {
type: String,
default: ''
},
badgeType: {
type: String,
default: 'success'
},
badgeStyle: {
type: Object,
default () {
return {}
}
},
rightText: {
type: String,
default: ''
},
thumb: {
type: String,
default: ''
},
thumbSize: {
type: String,
default: 'base'
},
showExtraIcon: {
type: [Boolean, String],
default: false
},
extraIcon: {
type: Object,
default () {
return {
type: '',
color: '#000000',
size: 20,
customPrefix: ''
};
}
},
border: {
type: Boolean,
default: true
},
customStyle: {
type: Object,
default () {
return {
padding: '',
backgroundColor: '#FFFFFF'
}
}
},
keepScrollPosition: {
type: Boolean,
default: false
}
},
watch: {
'customStyle.padding': {
handler(padding) {
if(typeof padding == 'number'){
padding += ''
}
let paddingArr = padding.split(' ')
if (paddingArr.length === 1) {
const allPadding = paddingArr[0]
this.padding = {
"top": allPadding,
"right": allPadding,
"bottom": allPadding,
"left": allPadding
}
} else if (paddingArr.length === 2) {
const [verticalPadding, horizontalPadding] = paddingArr;
this.padding = {
"top": verticalPadding,
"right": horizontalPadding,
"bottom": verticalPadding,
"left": horizontalPadding
}
} else if (paddingArr.length === 4) {
const [topPadding, rightPadding, bottomPadding, leftPadding] = paddingArr;
this.padding = {
"top": topPadding,
"right": rightPadding,
"bottom": bottomPadding,
"left": leftPadding
}
}
},
immediate: true
}
},
// inject: ['list'],
data() {
return {
isFirstChild: false,
padding: {
top: "",
right: "",
bottom: "",
left: ""
}
};
},
mounted() {
this.list = this.getForm()
// uni-list
if (this.list) {
if (!this.list.firstChildAppend) {
this.list.firstChildAppend = true;
this.isFirstChild = true;
}
}
},
methods: {
/**
* 获取父元素实例
*/
getForm(name = 'uniList') {
let parent = this.$parent;
let parentName = parent.$options.name;
while (parentName !== name) {
parent = parent.$parent;
if (!parent) return false
parentName = parent.$options.name;
}
return parent;
},
onClick() {
if (this.to !== '') {
this.openPage();
return;
}
if (this.clickable || this.link) {
this.$emit('click', {
data: {}
});
}
},
onSwitchChange(e) {
this.$emit('switchChange', e.detail);
},
openPage() {
if (['navigateTo', 'redirectTo', 'reLaunch', 'switchTab'].indexOf(this.link) !== -1) {
this.pageApi(this.link);
} else {
this.pageApi('navigateTo');
}
},
pageApi(api) {
let callback = {
url: this.to,
success: res => {
this.$emit('click', {
data: res
});
},
fail: err => {
this.$emit('click', {
data: err
});
}
}
switch (api) {
case 'navigateTo':
uni.navigateTo(callback)
break
case 'redirectTo':
uni.redirectTo(callback)
break
case 'reLaunch':
uni.reLaunch(callback)
break
case 'switchTab':
uni.switchTab(callback)
break
default:
uni.navigateTo(callback)
}
}
}
};
</script>
<style lang="scss">
$uni-font-size-sm:12px;
$uni-font-size-base:14px;
$uni-font-size-lg:16px;
$uni-spacing-col-lg: 12px;
$uni-spacing-row-lg: 15px;
$uni-img-size-sm:20px;
$uni-img-size-base:26px;
$uni-img-size-lg:40px;
$uni-border-color:#e5e5e5;
$uni-bg-color-hover:#f1f1f1;
$uni-text-color-grey:#999;
$list-item-pd: $uni-spacing-col-lg $uni-spacing-row-lg;
.uni-list-item {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
font-size: $uni-font-size-lg;
position: relative;
justify-content: space-between;
align-items: center;
background-color: #fff;
flex-direction: row;
/* #ifdef H5 */
cursor: pointer;
/* #endif */
}
.uni-list-item--disabled {
opacity: 0.3;
}
.uni-list-item--hover {
background-color: $uni-bg-color-hover !important;
}
.uni-list-item__container {
position: relative;
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: row;
padding: $list-item-pd;
padding-left: $uni-spacing-row-lg;
flex: 1;
overflow: hidden;
// align-items: center;
}
.container--right {
padding-right: 0;
}
// .border--left {
// margin-left: $uni-spacing-row-lg;
// }
.uni-list--border {
position: absolute;
top: 0;
right: 0;
left: 0;
/* #ifdef APP-NVUE */
border-top-color: $uni-border-color;
border-top-style: solid;
border-top-width: 0.5px;
/* #endif */
}
/* #ifndef APP-NVUE */
.uni-list--border:after {
position: absolute;
top: 0;
right: 0;
left: 0;
height: 1px;
content: '';
-webkit-transform: scaleY(0.5);
transform: scaleY(0.5);
background-color: $uni-border-color;
}
/* #endif */
.uni-list-item__content {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
padding-right: 8px;
flex: 1;
color: #3b4144;
// overflow: hidden;
flex-direction: column;
justify-content: space-between;
overflow: hidden;
}
.uni-list-item__content--center {
justify-content: center;
}
.uni-list-item__content-title {
font-size: $uni-font-size-base;
color: #3b4144;
overflow: hidden;
}
.uni-list-item__content-note {
margin-top: 6rpx;
color: $uni-text-color-grey;
font-size: $uni-font-size-sm;
overflow: hidden;
}
.uni-list-item__extra {
// width: 25%;
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: row;
justify-content: flex-end;
align-items: center;
}
.uni-list-item__header {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: row;
align-items: center;
}
.uni-list-item__icon {
margin-right: 18rpx;
flex-direction: row;
justify-content: center;
align-items: center;
}
.uni-list-item__icon-img {
/* #ifndef APP-NVUE */
display: block;
/* #endif */
height: $uni-img-size-base;
width: $uni-img-size-base;
margin-right: 10px;
}
.uni-icon-wrapper {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
align-items: center;
padding: 0 10px;
}
.flex--direction {
flex-direction: column;
/* #ifndef APP-NVUE */
align-items: initial;
/* #endif */
}
.flex--justify {
/* #ifndef APP-NVUE */
justify-content: initial;
/* #endif */
}
.uni-list--lg {
height: $uni-img-size-lg;
width: $uni-img-size-lg;
}
.uni-list--base {
height: $uni-img-size-base;
width: $uni-img-size-base;
}
.uni-list--sm {
height: $uni-img-size-sm;
width: $uni-img-size-sm;
}
.uni-list-item__extra-text {
color: $uni-text-color-grey;
font-size: $uni-font-size-sm;
}
.uni-ellipsis-1 {
/* #ifndef APP-NVUE */
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
/* #endif */
/* #ifdef APP-NVUE */
lines: 1;
text-overflow: ellipsis;
/* #endif */
}
.uni-ellipsis-2 {
/* #ifndef APP-NVUE */
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
/* #endif */
/* #ifdef APP-NVUE */
lines: 2;
text-overflow: ellipsis;
/* #endif */
}
</style>

+ 123
- 0
uni_modules/uni-list/components/uni-list/uni-list.vue View File

@ -0,0 +1,123 @@
<template>
<!-- #ifndef APP-NVUE -->
<view class="uni-list uni-border-top-bottom">
<view v-if="border" class="uni-list--border-top"></view>
<slot />
<view v-if="border" class="uni-list--border-bottom"></view>
</view>
<!-- #endif -->
<!-- #ifdef APP-NVUE -->
<list :bounce="false" :scrollable="true" show-scrollbar :render-reverse="renderReverse" @scroll="scroll" class="uni-list" :class="{ 'uni-list--border': border }" :enableBackToTop="enableBackToTop"
loadmoreoffset="15">
<slot />
</list>
<!-- #endif -->
</template>
<script>
/**
* List 列表
* @description 列表组件
* @tutorial https://ext.dcloud.net.cn/plugin?id=24
* @property {String} border = [true|false] 标题
*/
export default {
name: 'uniList',
'mp-weixin': {
options: {
multipleSlots: false
}
},
props: {
stackFromEnd:{
type: Boolean,
default:false
},
enableBackToTop: {
type: [Boolean, String],
default: false
},
scrollY: {
type: [Boolean, String],
default: false
},
border: {
type: Boolean,
default: true
},
renderReverse:{
type: Boolean,
default: false
}
},
// provide() {
// return {
// list: this
// };
// },
created() {
this.firstChildAppend = false;
},
methods: {
loadMore(e) {
this.$emit('scrolltolower');
},
scroll(e) {
this.$emit('scroll', e);
}
}
};
</script>
<style lang="scss">
$uni-bg-color:#ffffff;
$uni-border-color:#e5e5e5;
.uni-list {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
background-color: $uni-bg-color;
position: relative;
flex-direction: column;
}
.uni-list--border {
position: relative;
/* #ifdef APP-NVUE */
border-top-color: $uni-border-color;
border-top-style: solid;
border-top-width: 0.5px;
border-bottom-color: $uni-border-color;
border-bottom-style: solid;
border-bottom-width: 0.5px;
/* #endif */
z-index: -1;
}
/* #ifndef APP-NVUE */
.uni-list--border-top {
position: absolute;
top: 0;
right: 0;
left: 0;
height: 1px;
-webkit-transform: scaleY(0.5);
transform: scaleY(0.5);
background-color: $uni-border-color;
z-index: 1;
}
.uni-list--border-bottom {
position: absolute;
bottom: 0;
right: 0;
left: 0;
height: 1px;
-webkit-transform: scaleY(0.5);
transform: scaleY(0.5);
background-color: $uni-border-color;
}
/* #endif */
</style>

+ 65
- 0
uni_modules/uni-list/components/uni-list/uni-refresh.vue View File

@ -0,0 +1,65 @@
<template>
<!-- #ifdef APP-NVUE -->
<refresh :display="display" @refresh="onrefresh" @pullingdown="onpullingdown">
<slot />
</refresh>
<!-- #endif -->
<!-- #ifndef APP-NVUE -->
<view ref="uni-refresh" class="uni-refresh" v-show="isShow">
<slot />
</view>
<!-- #endif -->
</template>
<script>
export default {
name: 'UniRefresh',
props: {
display: {
type: [String],
default: "hide"
}
},
data() {
return {
pulling: false
}
},
computed: {
isShow() {
if (this.display === "show" || this.pulling === true) {
return true;
}
return false;
}
},
created() {},
methods: {
onchange(value) {
this.pulling = value;
},
onrefresh(e) {
this.$emit("refresh", e);
},
onpullingdown(e) {
// #ifdef APP-NVUE
this.$emit("pullingdown", e);
// #endif
// #ifndef APP-NVUE
var detail = {
viewHeight: 90,
pullingDistance: e.height
}
this.$emit("pullingdown", detail);
// #endif
}
}
}
</script>
<style>
.uni-refresh {
height: 0;
overflow: hidden;
}
</style>

+ 87
- 0
uni_modules/uni-list/components/uni-list/uni-refresh.wxs View File

@ -0,0 +1,87 @@
var pullDown = {
threshold: 95,
maxHeight: 200,
callRefresh: 'onrefresh',
callPullingDown: 'onpullingdown',
refreshSelector: '.uni-refresh'
};
function ready(newValue, oldValue, ownerInstance, instance) {
var state = instance.getState()
state.canPullDown = newValue;
// console.log(newValue);
}
function touchStart(e, instance) {
var state = instance.getState();
state.refreshInstance = instance.selectComponent(pullDown.refreshSelector);
state.canPullDown = (state.refreshInstance != null && state.refreshInstance != undefined);
if (!state.canPullDown) {
return
}
// console.log("touchStart");
state.height = 0;
state.touchStartY = e.touches[0].pageY || e.changedTouches[0].pageY;
state.refreshInstance.setStyle({
'height': 0
});
state.refreshInstance.callMethod("onchange", true);
}
function touchMove(e, ownerInstance) {
var instance = e.instance;
var state = instance.getState();
if (!state.canPullDown) {
return
}
var oldHeight = state.height;
var endY = e.touches[0].pageY || e.changedTouches[0].pageY;
var height = endY - state.touchStartY;
if (height > pullDown.maxHeight) {
return;
}
var refreshInstance = state.refreshInstance;
refreshInstance.setStyle({
'height': height + 'px'
});
height = height < pullDown.maxHeight ? height : pullDown.maxHeight;
state.height = height;
refreshInstance.callMethod(pullDown.callPullingDown, {
height: height
});
}
function touchEnd(e, ownerInstance) {
var state = e.instance.getState();
if (!state.canPullDown) {
return
}
state.refreshInstance.callMethod("onchange", false);
var refreshInstance = state.refreshInstance;
if (state.height > pullDown.threshold) {
refreshInstance.callMethod(pullDown.callRefresh);
return;
}
refreshInstance.setStyle({
'height': 0
});
}
function propObserver(newValue, oldValue, instance) {
pullDown = newValue;
}
module.exports = {
touchmove: touchMove,
touchstart: touchStart,
touchend: touchEnd,
propObserver: propObserver
}

+ 88
- 0
uni_modules/uni-list/package.json View File

@ -0,0 +1,88 @@
{
"id": "uni-list",
"displayName": "uni-list 列表",
"version": "1.2.14",
"description": "List 组件 ,帮助使用者快速构建列表。",
"keywords": [
"",
"uni-ui",
"uniui",
"列表",
"",
"list"
],
"repository": "https://github.com/dcloudio/uni-ui",
"engines": {
"HBuilderX": ""
},
"directories": {
"example": "../../temps/example_temps"
},
"dcloudext": {
"sale": {
"regular": {
"price": "0.00"
},
"sourcecode": {
"price": "0.00"
}
},
"contact": {
"qq": ""
},
"declaration": {
"ads": "无",
"data": "无",
"permissions": "无"
},
"npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui",
"type": "component-vue"
},
"uni_modules": {
"dependencies": [
"uni-badge",
"uni-icons"
],
"encrypt": [],
"platforms": {
"cloud": {
"tcb": "y",
"aliyun": "y"
},
"client": {
"App": {
"app-vue": "y",
"app-nvue": "y"
},
"H5-mobile": {
"Safari": "y",
"Android Browser": "y",
"微信浏览器(Android)": "y",
"QQ浏览器(Android)": "y"
},
"H5-pc": {
"Chrome": "y",
"IE": "y",
"Edge": "y",
"Firefox": "y",
"Safari": "y"
},
"小程序": {
"微信": "y",
"阿里": "y",
"百度": "y",
"字节跳动": "y",
"QQ": "y"
},
"快应用": {
"华为": "u",
"联盟": "u"
},
"Vue": {
"vue2": "y",
"vue3": "y"
}
}
}
}
}

+ 346
- 0
uni_modules/uni-list/readme.md View File

@ -0,0 +1,346 @@
## List 列表
> **组件名:uni-list**
> 代码块: `uList`、`uListItem`
> 关联组件:`uni-list-item`、`uni-badge`、`uni-icons`、`uni-list-chat`、`uni-list-ad`
List 列表组件,包含基本列表样式、可扩展插槽机制、长列表性能优化、多端兼容。
在vue页面里,它默认使用页面级滚动。在app-nvue页面里,它默认使用原生list组件滚动。这样的长列表,在滚动出屏幕外后,系统会回收不可见区域的渲染内存资源,不会造成滚动越长手机越卡的问题。
uni-list组件是父容器,里面的核心是uni-list-item子组件,它代表列表中的一个可重复行,子组件可以无限循环。
uni-list-item有很多风格,uni-list-item组件通过内置的属性,满足一些常用的场景。当内置属性不满足需求时,可以通过扩展插槽来自定义列表内容。
内置属性可以覆盖的场景包括:导航列表、设置列表、小图标列表、通信录列表、聊天记录列表。
涉及很多大图或丰富内容的列表,比如类今日头条的新闻列表、类淘宝的电商列表,需要通过扩展插槽实现。
下文均有样例给出。
uni-list不包含下拉刷新和上拉翻页。上拉翻页另见组件:[uni-load-more](https://ext.dcloud.net.cn/plugin?id=29)
### 安装方式
本组件符合[easycom](https://uniapp.dcloud.io/collocation/pages?id=easycom)规范,`HBuilderX 2.5.5`起,只需将本组件导入项目,在页面`template`中即可直接使用,无需在页面中`import`和注册`components`。
如需通过`npm`方式使用`uni-ui`组件,另见文档:[https://ext.dcloud.net.cn/plugin?id=55](https://ext.dcloud.net.cn/plugin?id=55)
> **注意事项**
> 为了避免错误使用,给大家带来不好的开发体验,请在使用组件前仔细阅读下面的注意事项,可以帮你避免一些错误。
> - 组件需要依赖 `sass` 插件 ,请自行手动安装
> - 组件内部依赖 `'uni-icons'` 、`uni-badge` 组件
> - `uni-list``uni-list-item` 需要配套使用,暂不支持单独使用 `uni-list-item`
> - 只有开启点击反馈后,会有点击选中效果
> - 使用插槽时,可以完全自定义内容
> - note 、rightText 属性暂时没做限制,不支持文字溢出隐藏,使用时应该控制长度显示或通过默认插槽自行扩展
> - 支付宝小程序平台需要在支付宝小程序开发者工具里开启 component2 编译模式,开启方式: 详情 --> 项目配置 --> 启用 component2 编译
> - 如果需要修改 `switch`、`badge` 样式,请使用插槽自定义
> - 在 `HBuilderX` 低版本中,可能会出现组件显示 `undefined` 的问题,请升级最新的 `HBuilderX` 或者 `cli`
> - 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839
### 基本用法
- 设置 `title` 属性,可以显示列表标题
- 设置 `disabled` 属性,可以禁用当前项
```html
<uni-list>
<uni-list-item title="列表文字" ></uni-list-item>
<uni-list-item :disabled="true" title="列表禁用状态" ></uni-list-item>
</uni-list>
```
### 多行内容显示
- 设置 `note` 属性 ,可以在第二行显示描述文本信息
```html
<uni-list>
<uni-list-item title="列表文字" note="列表描述信息"></uni-list-item>
<uni-list-item :disabled="true" title="列表文字" note="列表禁用状态"></uni-list-item>
</uni-list>
```
### 右侧显示角标、switch
- 设置 `show-badge` 属性 ,可以显示角标内容
- 设置 `show-switch` 属性,可以显示 switch 开关
```html
<uni-list>
<uni-list-item title="列表右侧显示角标" :show-badge="true" badge-text="12" ></uni-list-item>
<uni-list-item title="列表右侧显示 switch" :show-switch="true" @switchChange="switchChange" ></uni-list-item>
</uni-list>
```
### 左侧显示略缩图、图标
- 设置 `thumb` 属性 ,可以在列表左侧显示略缩图
- 设置 `show-extra-icon` 属性,并指定 `extra-icon` 可以在左侧显示图标
```html
<uni-list>
<uni-list-item title="列表左侧带略缩图" note="列表描述信息" thumb="https://vkceyugu.cdn.bspapp.com/VKCEYUGU-dc-site/460d46d0-4fcc-11eb-8ff1-d5dcf8779628.png"
thumb-size="lg" rightText="右侧文字"></uni-list-item>
<uni-list-item :show-extra-icon="true" :extra-icon="extraIcon1" title="列表左侧带扩展图标" ></uni-list-item>
</uni-list>
```
### 开启点击反馈和右侧箭头
- 设置 `clickable``true` ,则表示这是一个可点击的列表,会默认给一个点击效果,并可以监听 `click` 事件
- 设置 `link` 属性,会自动开启点击反馈,并给列表右侧添加一个箭头
- 设置 `to` 属性,可以跳转页面,`link` 的值表示跳转方式,如果不指定,默认为 `navigateTo`
```html
<uni-list>
<uni-list-item title="开启点击反馈" clickable @click="onClick" ></uni-list-item>
<uni-list-item title="默认 navigateTo 方式跳转页面" link to="/pages/vue/index/index" @click="onClick($event,1)" ></uni-list-item>
<uni-list-item title="reLaunch 方式跳转页面" link="reLaunch" to="/pages/vue/index/index" @click="onClick($event,1)" ></uni-list-item>
</uni-list>
```
### 聊天列表示例
- 设置 `clickable``true` ,则表示这是一个可点击的列表,会默认给一个点击效果,并可以监听 `click` 事件
- 设置 `link` 属性,会自动开启点击反馈,`link` 的值表示跳转方式,如果不指定,默认为 `navigateTo`
- 设置 `to` 属性,可以跳转页面
- `time` 属性,通常会设置成时间显示,但是这个属性不仅仅可以设置时间,你可以传入任何文本,注意文本长度可能会影响显示
- `avatar``avatarList` 属性同时只会有一个生效,同时设置的话,`avatarList` 属性的长度大于1 ,`avatar` 属性将失效
- 可以通过默认插槽自定义列表右侧内容
```html
<uni-list>
<uni-list :border="true">
<!-- 显示圆形头像 -->
<uni-list-chat :avatar-circle="true" title="uni-app" avatar="https://vkceyugu.cdn.bspapp.com/VKCEYUGU-dc-site/460d46d0-4fcc-11eb-8ff1-d5dcf8779628.png" note="您收到一条新的消息" time="2020-02-02 20:20" ></uni-list-chat>
<!-- 右侧带角标 -->
<uni-list-chat title="uni-app" avatar="https://vkceyugu.cdn.bspapp.com/VKCEYUGU-dc-site/460d46d0-4fcc-11eb-8ff1-d5dcf8779628.png" note="您收到一条新的消息" time="2020-02-02 20:20" badge-text="12" :badge-style="{backgroundColor:'#FF80AB'}"></uni-list-chat>
<!-- 头像显示圆点 -->
<uni-list-chat title="uni-app" avatar="https://vkceyugu.cdn.bspapp.com/VKCEYUGU-dc-site/460d46d0-4fcc-11eb-8ff1-d5dcf8779628.png" note="您收到一条新的消息" time="2020-02-02 20:20" badge-positon="left" badge-text="dot"></uni-list-chat>
<!-- 头像显示角标 -->
<uni-list-chat title="uni-app" avatar="https://vkceyugu.cdn.bspapp.com/VKCEYUGU-dc-site/460d46d0-4fcc-11eb-8ff1-d5dcf8779628.png" note="您收到一条新的消息" time="2020-02-02 20:20" badge-positon="left" badge-text="99"></uni-list-chat>
<!-- 显示多头像 -->
<uni-list-chat title="uni-app" :avatar-list="avatarList" note="您收到一条新的消息" time="2020-02-02 20:20" badge-positon="left" badge-text="dot"></uni-list-chat>
<!-- 自定义右侧内容 -->
<uni-list-chat title="uni-app" :avatar-list="avatarList" note="您收到一条新的消息" time="2020-02-02 20:20" badge-positon="left" badge-text="dot">
<view class="chat-custom-right">
<text class="chat-custom-text">刚刚</text>
<!-- 需要使用 uni-icons 请自行引入 -->
<uni-icons type="star-filled" color="#999" size="18"></uni-icons>
</view>
</uni-list-chat>
</uni-list>
</uni-list>
```
```javascript
export default {
components: {},
data() {
return {
avatarList: [{
url: 'https://vkceyugu.cdn.bspapp.com/VKCEYUGU-dc-site/460d46d0-4fcc-11eb-8ff1-d5dcf8779628.png'
}, {
url: 'https://vkceyugu.cdn.bspapp.com/VKCEYUGU-dc-site/460d46d0-4fcc-11eb-8ff1-d5dcf8779628.png'
}, {
url: 'https://vkceyugu.cdn.bspapp.com/VKCEYUGU-dc-site/460d46d0-4fcc-11eb-8ff1-d5dcf8779628.png'
}]
}
}
}
```
```css
.chat-custom-right {
flex: 1;
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: column;
justify-content: space-between;
align-items: flex-end;
}
.chat-custom-text {
font-size: 12px;
color: #999;
}
```
## API
### List Props
属性名 |类型 |默认值 | 说明
:-: |:-: |:-: | :-:
border |Boolean |true | 是否显示边框
### ListItem Props
属性名 |类型 |默认值 | 说明
:-: |:-: |:-: | :-:
title |String |- | 标题
note |String |- | 描述
ellipsis |Number |0 | title 是否溢出隐藏,可选值,0:默认; 1:显示一行; 2:显示两行;【nvue 暂不支持】
thumb |String |- | 左侧缩略图,若thumb有值,则不会显示扩展图标
thumbSize |String |medium | 略缩图尺寸,可选值,lg:大图; medium:一般; sm:小图;
showBadge |Boolean |false | 是否显示数字角标
badgeText |String |- | 数字角标内容
badgeType |String |- | 数字角标类型,参考[uni-icons](https://ext.dcloud.net.cn/plugin?id=21)
badgeStyle |Object |- | 数字角标样式,使用uni-badge的custom-style参数
rightText |String |- | 右侧文字内容
disabled |Boolean |false | 是否禁用
showArrow |Boolean |true | 是否显示箭头图标
link |String |navigateTo | 新页面跳转方式,可选值见下表
to |String |- | 新页面跳转地址,如填写此属性,click 会返回页面是否跳转成功
clickable |Boolean |false | 是否开启点击反馈
showSwitch |Boolean |false | 是否显示Switch
switchChecked |Boolean |false | Switch是否被选中
showExtraIcon |Boolean |false | 左侧是否显示扩展图标
extraIcon |Object |- | 扩展图标参数,格式为 ``{color: '#4cd964',size: '22',type: 'spinner'}``,参考 [uni-icons](https://ext.dcloud.net.cn/plugin?id=28)
direction | String |row | 排版方向,可选值,row:水平排列; column:垂直排列; 3个插槽是水平排还是垂直排,也受此属性控制
#### Link Options
属性名 | 说明
:-: | :-:
navigateTo | 同 uni.navigateTo()
redirectTo | 同 uni.reLaunch()
reLaunch | 同 uni.reLaunch()
switchTab | 同 uni.switchTab()
### ListItem Events
事件称名 |说明 |返回参数
:-: |:-: |:-:
click |点击 uniListItem 触发事件,需开启点击反馈 |-
switchChange |点击切换 Switch 时触发,需显示 switch |e={value:checked}
### ListItem Slots
名称 | 说明
:-: | :-:
header | 左/上内容插槽,可完全自定义默认显示
body | 中间内容插槽,可完全自定义中间内容
footer | 右/下内容插槽,可完全自定义右侧内容
> **通过插槽扩展**
> 需要注意的是当使用插槽时,内置样式将会失效,只保留排版样式,此时的样式需要开发者自己实现
> 如果 `uni-list-item` 组件内置属性样式无法满足需求,可以使用插槽来自定义uni-list-item里的内容。
> uni-list-item提供了3个可扩展的插槽:`header`、`body`、`footer`
> - 当 `direction` 属性为 `row` 时表示水平排列,此时 `header` 表示列表的左边部分,`body` 表示列表的中间部分,`footer` 表示列表的右边部分
> - 当 `direction` 属性为 `column` 时表示垂直排列,此时 `header` 表示列表的上边部分,`body` 表示列表的中间部分,`footer` 表示列表的下边部分
> 开发者可以只用1个插槽,也可以3个一起使用。在插槽中可自主编写view标签,实现自己所需的效果。
**示例**
```html
<uni-list>
<uni-list-item title="自定义右侧插槽" note="列表描述信息" link>
<template slot="header">
<image class="slot-image" src="/static/logo.png" mode="widthFix"></image>
</template>
</uni-list-item>
<uni-list-item>
<!-- 自定义 header -->
<view slot="header" class="slot-box"><image class="slot-image" src="/static/logo.png" mode="widthFix"></image></view>
<!-- 自定义 body -->
<text slot="body" class="slot-box slot-text">自定义插槽</text>
<!-- 自定义 footer-->
<template slot="footer">
<image class="slot-image" src="/static/logo.png" mode="widthFix"></image>
</template>
</uni-list-item>
</uni-list>
```
### ListItemChat Props
属性名 |类型 |默认值 | 说明
:-: |:-: |:-: | :-:
title |String |- | 标题
note |String |- | 描述
clickable |Boolean |false | 是否开启点击反馈
badgeText |String |- | 数字角标内容,设置为 `dot` 将显示圆点
badgePositon |String |right | 角标位置
link |String |navigateTo | 是否展示右侧箭头并开启点击反馈,可选值见下表
clickable |Boolean |false | 是否开启点击反馈
to |String |- | 跳转页面地址,如填写此属性,click 会返回页面是否跳转成功
time |String |- | 右侧时间显示
avatarCircle |Boolean |false | 是否显示圆形头像
avatar |String |- | 头像地址,avatarCircle 不填时生效
avatarList |Array |- | 头像组,格式为 [{url:''}]
#### Link Options
属性名 | 说明
:-: | :-:
navigateTo | 同 uni.navigateTo()
redirectTo | 同 uni.reLaunch()
reLaunch | 同 uni.reLaunch()
switchTab | 同 uni.switchTab()
### ListItemChat Slots
名称 | 说明
:- | :-
default | 自定义列表右侧内容(包括时间和角标显示)
### ListItemChat Events
事件称名 | 说明 | 返回参数
:-: | :-: | :-:
@click | 点击 uniListChat 触发事件 | {data:{}} ,如有 to 属性,会返回页面跳转信息
## 基于uni-list扩展的页面模板
通过扩展插槽,可实现多种常见样式的列表
**新闻列表类**
1. 云端一体混合布局:[https://ext.dcloud.net.cn/plugin?id=2546](https://ext.dcloud.net.cn/plugin?id=2546)
2. 云端一体垂直布局,大图模式:[https://ext.dcloud.net.cn/plugin?id=2583](https://ext.dcloud.net.cn/plugin?id=2583)
3. 云端一体垂直布局,多行图文混排:[https://ext.dcloud.net.cn/plugin?id=2584](https://ext.dcloud.net.cn/plugin?id=2584)
4. 云端一体垂直布局,多图模式:[https://ext.dcloud.net.cn/plugin?id=2585](https://ext.dcloud.net.cn/plugin?id=2585)
5. 云端一体水平布局,左图右文:[https://ext.dcloud.net.cn/plugin?id=2586](https://ext.dcloud.net.cn/plugin?id=2586)
6. 云端一体水平布局,左文右图:[https://ext.dcloud.net.cn/plugin?id=2587](https://ext.dcloud.net.cn/plugin?id=2587)
7. 云端一体垂直布局,无图模式,主标题+副标题:[https://ext.dcloud.net.cn/plugin?id=2588](https://ext.dcloud.net.cn/plugin?id=2588)
**商品列表类**
1. 云端一体列表/宫格视图互切:[https://ext.dcloud.net.cn/plugin?id=2651](https://ext.dcloud.net.cn/plugin?id=2651)
2. 云端一体列表(宫格模式):[https://ext.dcloud.net.cn/plugin?id=2671](https://ext.dcloud.net.cn/plugin?id=2671)
3. 云端一体列表(列表模式):[https://ext.dcloud.net.cn/plugin?id=2672](https://ext.dcloud.net.cn/plugin?id=2672)
## 组件示例
点击查看:[https://hellouniapp.dcloud.net.cn/pages/extUI/list/list](https://hellouniapp.dcloud.net.cn/pages/extUI/list/list)

Loading…
Cancel
Save