Commit d338e511 by yuzhenWang

解决冲突,合并我的名片代码

parents 5ee59865 db0b6afa
...@@ -443,5 +443,21 @@ export default { ...@@ -443,5 +443,21 @@ export default {
// 持牌人佣金查询 // 持牌人佣金查询
queryRate(params){ queryRate(params){
return request(`${apiURL}/insurance_product/query/rate?planBizId=${params.planBizId}&userId=${params.userId}`, "GET") return request(`${apiURL}/insurance_product/query/rate?planBizId=${params.planBizId}&userId=${params.userId}`, "GET")
} },
//申请名片
saveApplyCard(params) {
return request(`${apiURL}/business-card/add`, 'POST', params)
},
//获取非分享名片信息
getBusinessCard(userId) {
return request(`${apiURL}/business-card/my?userId=${userId}`, 'GET')
},
//获取分享状态名片信息
getShareBusinessCard(cardId) {
return request(`${apiURL}/business-card/view/${cardId}`, 'GET')
},
//获取分享名片统计
getCardStats(data) {
return request(`${apiURL}/business-card/stats/${data.cardId}?userId=${data.userId}`, 'GET')
},
} }
...@@ -174,6 +174,13 @@ export default { ...@@ -174,6 +174,13 @@ export default {
const EMAIL_REGEXP = /^(\w-*\.*)+@(\w-?)+(\.\w{2,})+$/; const EMAIL_REGEXP = /^(\w-*\.*)+@(\w-?)+(\.\w{2,})+$/;
return EMAIL_REGEXP.test(email); return EMAIL_REGEXP.test(email);
}, },
/**
* 手机号正则
*/
phoneValid(phone) {
const mobileReg = /^1[3-9]\d{9}$/;
return mobileReg.test(phone)
},
//检测字符串是否只有中文、英文、数字 //检测字符串是否只有中文、英文、数字
checkCEN(val) { checkCEN(val) {
const cen_reg = /^[A-Za-z0-9\u4e00-\u9fa5]+$/; const cen_reg = /^[A-Za-z0-9\u4e00-\u9fa5]+$/;
......
<template>
<view class="segmented-control">
<view
v-for="(item, index) in values"
:key="index"
class="segmented-control-item"
:class="{ active: current === index }"
:style="getItemStyle(index)"
@tap="onItemTap(index)"
>
<text class="segmented-control-text" :style="getTextStyle(index)">
{{ item }}
</text>
</view>
</view>
</template>
<script>
export default {
name: "CustomSegmentedControl",
props: {
values: {
type: Array,
default: () => []
},
current: {
type: Number,
default: 0
},
fontSize: {
type: Number,
default: 16
},
activeColor: {
type: String,
default: "#20269B"
},
inactiveColor: {
type: String,
default: "#f5f5f5"
},
activeTextColor: {
type: String,
default: "#ffffff"
},
inactiveTextColor: {
type: String,
default: "#666666"
},
tabBg: {
type: Boolean,
default: false
},
// 添加下划线相关属性
underlineHeight: {
type: String,
default: "4rpx"
},
underlineColor: {
type: String,
default: "#20269B"
},
underlineWidth: {
type: String,
default: "60%"
}
},
methods: {
onItemTap(index) {
this.$emit('clickItem', index);
},
getItemStyle(index) {
if (this.tabBg) {
return {
backgroundColor: this.current === index ? this.activeColor : this.inactiveColor,
flex: 1
};
} else {
return {
// backgroundColor: this.current === index ? this.activeColor : this.inactiveColor,
flex: 1
};
}
},
getTextStyle(index) {
return {
fontSize: `${this.fontSize}px`,
color: this.current === index ? this.activeTextColor : this.inactiveTextColor
};
}
}
}
</script>
<style scoped>
.segmented-control {
display: flex;
height: 70rpx;
/* border-radius: 35rpx; */
overflow: hidden;
/* box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.1); */
}
.segmented-control-item {
display: flex;
align-items: center;
justify-content: center;
transition: all 0.3s;
position: relative; /* 为下划线添加定位 */
}
.segmented-control-text {
font-weight: 500;
transition: all 0.3s;
}
/* 为激活项添加下划线 */
.segmented-control-item.active::after {
content: '';
position: absolute;
bottom: 0;
left: 50%;
transform: translateX(-50%);
width: v-bind(underlineWidth);
height: v-bind(underlineHeight);
background-color: v-bind(underlineColor);
border-radius: 2rpx;
}
</style>
\ No newline at end of file
<template>
<view class="list-item" :class="{ 'border-bottom': showBorder }" @click="handleClick">
<!-- 左侧文本 -->
<view class="left-content">
<text class="left-text" :style="getLeftTextStyle()">{{ leftText }}</text>
</view>
<!-- 右侧内容 -->
<view class="right-content">
<!-- 右侧文本 -->
<text v-if="rightText" class="right-text" :style="getRightTextStyle()">{{ rightText }}</text>
<!-- 右侧图片 -->
<image
v-if="rightImage"
:src="rightImage"
class="right-image"
mode="aspectFit"
></image>
<!-- 右侧自定义内容插槽 -->
<slot name="right"></slot>
<!-- 右箭头 -->
<view v-if="showArrow" class="arrow">
<view class="iconfont icon-jiantou2" :style="getArrowRightStyle()">
</view>
</view>
</view>
</view>
</template>
<script>
export default {
name: 'ListItem',
props: {
// 左侧文本
leftText: {
type: String,
default: ''
},
// 左侧颜色
leftTextColor: {
type: String,
default: '#6C6A66'
},
// 左侧文本大小
leftTextSize: {
type: String,
default: '28rpx'
},
// 右侧文本
rightText: {
type: String,
default: ''
},
// 左侧颜色
rightTextColor: {
type: String,
default: '#333333'
},
// 左侧文本大小
rightTextSize: {
type: String,
default: '30rpx'
},
// 右侧图片
rightImage: {
type: String,
default: ''
},
// 是否显示右箭头
showArrow: {
type: Boolean,
default: true
},
// 右箭头的大小
arrowRightSize:{
type:String,
default:'32rpx'
},
// 右箭头的颜色
arrowRighColor:{
type:String,
default:'#000'
},
// 是否显示底部边框
showBorder: {
type: Boolean,
default: true
}
},
methods: {
handleClick() {
this.$emit('click')
},
getArrowRightStyle() {
return {
fontSize: this.arrowRightSize,
color:this.arrowRighColor
};
},
getLeftTextStyle() {
return {
fontSize: this.leftTextSize,
color:this.leftTextColor
};
},
getRightTextStyle() {
return {
fontSize: this.rightTextSize,
color:this.rightTextColor
};
}
}
}
</script>
<style scoped>
.list-item {
display: flex;
align-items: center;
justify-content: space-between;
padding: 24rpx 0rpx;
background-color: #ffffff;
min-height: 100rpx;
box-sizing: border-box;
}
.border-bottom {
border-bottom: 1rpx solid #E8E7E7;
}
.left-content {
flex: 1;
}
.left-text {
font-size: 32rpx;
color: #333333;
line-height: 1.5;
}
.right-content {
display: flex;
align-items: center;
/* justify-content: flex-end; */
}
.right-text {
font-size: 28rpx;
color: #666666;
margin-right: 16rpx;
}
.right-image {
width: 60rpx;
height: 60rpx;
margin-right: 16rpx;
border-radius: 8rpx;
}
.arrow {
display: flex;
align-items: center;
justify-content: center;
}
.arrow-icon {
font-size: 30rpx;
color: #cccccc;
}
</style>
\ No newline at end of file
// share_url 在发布生产和测试得时候记得把cffp换为appYdhomeoffice,本地开发得时候要用cffp
// 发布测试和生产得时候,manifest.json->Web配置->运行得基础路径要改为appYdhomeoffice,本地开发得时候要用cffp
const dev = { const dev = {
// api_url:'http://10.0.10.26:8888/cffpApi',
// cffp_url:'http://10.0.10.26:8888/cffpApi/cffp',
base_url:'https://mdev.anjibao.cn', base_url:'https://mdev.anjibao.cn',
api_url:'https://mdev.anjibao.cn/cffpApi', api_url:'https://mdev.anjibao.cn/cffpApi',
cffp_url:'https://mdev.anjibao.cn/cffpApi/cffp', cffp_url:'https://mdev.anjibao.cn/cffpApi/cffp',
share_url:'https://mdev.anjibao.cn/appYdhomeoffice', share_url:'https://mdev.anjibao.cn/cffp',
sfp_url:'https://mdev.anjibao.cn/sfpApi', sfp_url:'https://mdev.anjibao.cn/sfpApi',
img_url:'https://mdev.zuihuibi.cn', img_url:'https://mdev.zuihuibi.cn',
scrm_url:'https://mdev.zuihuibi.cn' scrm_url:'https://mdev.zuihuibi.cn'
...@@ -13,7 +14,7 @@ const stage = { ...@@ -13,7 +14,7 @@ const stage = {
base_url:'https://mstage.zuihuibi.cn', base_url:'https://mstage.zuihuibi.cn',
api_url:'https://mstage.zuihuibi.cn/cffpApi', api_url:'https://mstage.zuihuibi.cn/cffpApi',
cffp_url:'https://mstage.zuihuibi.cn/cffpApi/cffp', cffp_url:'https://mstage.zuihuibi.cn/cffpApi/cffp',
share_url:'https://mstage.zuihuibi.cn/appYdhomeoffice', share_url:'https://mstage.zuihuibi.cn/cffp',
sfp_url:'https://mstage.zuihuibi.cn/sfpApi', sfp_url:'https://mstage.zuihuibi.cn/sfpApi',
scrm_url:'https://mstage.zuihuibi.cn' scrm_url:'https://mstage.zuihuibi.cn'
...@@ -42,14 +43,14 @@ let companyInfo = { ...@@ -42,14 +43,14 @@ let companyInfo = {
companyFullName: '银盾家办(广州)企业管理咨询有限公司', companyFullName: '银盾家办(广州)企业管理咨询有限公司',
companyLogo:'../../static/logo2.png', companyLogo:'../../static/logo2.png',
systemType: 'NoIOS', systemType: 'NoIOS',
imgType:'appYdhomeoffice' //因为测试环境用的cffp,生产环境要改成appYdhomeoffice imgType:'cffp' //因为测试环境用的cffp,生产环境要改成appYdhomeoffice
} }
const config = { const config = {
dev, dev,
stage, stage,
prod prod
} }
let env = 'prod'; let env = 'dev';
let baseURL = config[env].base_url; let baseURL = config[env].base_url;
let apiURL = config[env].api_url; let apiURL = config[env].api_url;
......
...@@ -169,7 +169,7 @@ ...@@ -169,7 +169,7 @@
"vueVersion" : "3", "vueVersion" : "3",
"h5" : { "h5" : {
"router" : { "router" : {
"base" : "/appYdhomeoffice/", "base" : "/cffp/",
"mode" : "history" "mode" : "history"
}, },
"devServer" : { "devServer" : {
......
<template>
<view class="container" >
<!-- v-if="isLogin" -->
<view class="" >
<view class="cardHeader" >
<view class="introduct">
<view class="introductHeader">
<view class="left">
<view
class="avatar"
:style="{backgroundImage: 'url(' + (cardInfo.avatarUrl || companyLogo) + ')'}"
>
</view>
</view>
<view class="right">
<view class="top">
{{cardInfo.userName || '--'}}
</view>
<view class="bottom" v-if="cardInfo.companyInfoList&&cardInfo.companyInfoList.length>0">
<view class="bottomCon" v-for="(item,index) in cardInfo.companyInfoList" :key="index">
<view class="bottomL">
{{item.companyName}}
</view>
<view class="bottomR">
{{item.position}}
</view>
</view>
</view>
</view>
</view>
<view class="introductContent">
<view v-for="item in infoList" :key="item.id" class="infoCon" >
<view class="iconfont infoIcon" :class="`${item.icon}`"></view>
<view class="">
{{item.value}}
</view>
</view>
</view>
</view>
<view class="optionBtn">
<view class="btnCon" v-for="item in btnList" :key="item.id" @click="handleBtnClick(item)">
<view :class="{'shareStyle':item.id=='1','commonBtn':item.id!=='1'}">
<view class="iconfont btnIcon" :class="`${item.icon}`" ></view>
</view>
<view class="btnTxt">
{{item.name}}
</view>
</view>
</view>
</view>
<view class="tabs">
<customSegmentedControl
:values="items"
:current="current"
:fontSize="16"
activeTextColor="#20269B"
inactiveTextColor="#000"
@clickItem="onClickItem"
:underlineHeight="'4rpx'"
:underlineColor="'#20269B'"
:underlineWidth="'30%'"
:tabBg="false"
/>
<view class="content">
<view v-show="current === 0">
关于我们的内容
</view>
<view v-show="current === 1">
企业荣誉的内容
</view>
<view v-show="current === 2">
关注官微的内容
</view>
</view>
</view>
</view>
<!-- <view v-if="!isLogin" class="loginTip" @click="sharelogin=true">
<text style="color: #20269B;">登录</text>之后才能看到名片
</view> -->
<uni-popup ref="popup" type="center" background-color="#fff">
<view class="descriptionBox">
<view class="popupClose">
<text class="iconfont icon-guanbi" @click="$refs.popup.close()"></text>
<!-- <view class="popupTit">
{{popupTitle}}
</view> -->
</view>
<view class="" v-if="optionType=='shareData'">
<view class="" v-for="item in staticData" :key="item.name">
<view class="staticItem">
<text class="iconfont staticIcon" :class="item.icon" ></text>
{{item.name}}{{item.value}}{{item.unit}}
</view>
</view>
</view>
<view class="" v-if="optionType=='focus' || (optionType=='shareCard'&&runEnv=='browser')">
<view class="codeBox">
<image v-if="cardInfo.qwQrcode" :src="cardInfo.qwQrcode" mode="widthFix" style="width:250rpx !important;"></image>
<image v-else src="@/static/cffpCode.jpg" mode="widthFix" style="width:250rpx !important;"></image>
</view>
<view class="description">
长按识别二维码 保存或分享图片
</view>
</view>
</view>
</uni-popup>
<view class="markBox" @click="shareTipsFlag=false" v-if="shareTipsFlag">
<view class="guideImgBox">
<image src="../../static/Group132.png" mode="widthFix"></image>
<view class="tips">
<view style="margin-bottom:30rpx">请点击右上角菜单</view>
<view>分享给朋友</view>
</view>
</view>
</view>
<boot-page
loginSource="我的名片"
v-if="sharelogin"
ref="sharelogin"
@close="loginClose()"
@afterLogin="afterLogin()"
></boot-page>
</view>
</template>
<script>
import { initJssdkShare, setWechatShare,hshare } from '@/util/fiveshare';
import {shareURL,companyInfo} from "@/environments/environment";
import api from "@/api/api";
import BootPage from "@/components/bootpage/bootpage.vue";
import dataHandling from "@/util/dataHandling";
import customSegmentedControl from '@/components/customSegmentedControl/customSegmentedControl.vue';
export default{
name:'businessCard',
components:{
BootPage,
},
data(){
return{
sharelogin:false,//是否需要登录
isLogin:true,//登录状态
shareTipsFlag:false,
runEnv:dataHandling.getRuntimeEnv(), //运行的环境
companyType : companyInfo.companyType,
companyLogo : '../../static/logo2.png',
sharePictrue:'../static/images/cardLogo.png',
infoList:[
{value:'暂无',icon:'icon-dianhua',id:'1'},
{value:'暂无',icon:'icon-youxiang',id:'2'},
{value:'暂无',icon:'icon-dingwei',id:'3'},
],
items: ["关于我们", "企业荣誉", "关注官微"],
current: 0,
systemInfo:{},
cardInfo:{},//名片信息
isShare:false,//是否通过分享链接进来的
userId:uni.getStorageSync('cffp_userId'),
cardId:'',
staticData:[
{name:'总访问人数',value:0,unit:'人',icon:'icon-zhongdianrenquntongji',color:'#3639A9'},
{name:'总访问量',value:0,unit:'次',icon:'icon-zongfangwenliang',color:'#3639A9'},
],
optionType:'',
popupTitle:''
}
},
computed: {
btnList() {
if(this.isShare){
return [
{name:'分享名片',icon:'icon-fenxiang',id:'1',color:'#20269B',type:'shareCard'},
{name:'拨打电话',icon:'icon-daohang',id:'2',color:'#fff',phoneNumber:'18918485032',type:'phone'},
{name:'关注我',icon:'icon-guanzhuwode',id:'3',color:'#fff',type:'focus'},
]
}else {
return [
{name:'分享名片',icon:'icon-fenxiang',id:'1',color:'#20269B',type:'shareCard'},
{name:'拨打电话',icon:'icon-daohang',id:'2',color:'#fff',phoneNumber:'18918485032',type:'phone'},
{name:'关注我',icon:'icon-guanzhuwode',id:'3',color:'#fff',type:'focus'},
{name:'分享数据',icon:'icon-fenxiangshuju',id:'4',color:'#fff',type:'shareData'},
]
}
}
},
onLoad(options) {
if(options.isShareCard){
this.isShare = true
this.userId = options.userId
this.cardId = options.cardId
}
this.systemInfo = uni.getSystemInfoSync();
const { platform, deviceType, screenWidth, screenHeight } = this.systemInfo;
},
onShow() {
// 是通过分享进来的但未登录
// if(this.isShare&&(!uni.getStorageSync('loginType') ||uni.getStorageSync('loginType') == 'visitor')){
// this.sharelogin = true
// this.isLogin = false
// }else {
// this.isLogin = true
// this.getCard()
// }
if(this.companyType == '1'){
this.companyLogo='../../static/myteam/Group1633.png';
}else if(this.companyType == '2'){
this.companyLogo='../../static/logo2.png';
}
if(this.isShare){
this.getShareCard()
}else {
this.getCard()
}
},
onUnload(){
// #ifdef H5
initJssdkShare(() => {
setWechatShare();
}, window.location.href);
// #endif
},
methods:{
afterLogin(){
this.sharelogin = false
this.isLogin = true
this.getCard()
},
// H5 自定义分享
getshareData() {
let data = {
title: this.cardInfo.userName?`我是${this.cardInfo.userName}的电子名片`:'电子名片',
// desc: '加入我们开启学习之旅',
desc:'专注为家庭提供全资产、全成员、全生命周期的复合型家庭事务治理方案',
link: `${shareURL}/myPackageA/businessCard/businessCard?userId=${this.userId}&cardId=${this.cardId}&isShareCard=1`, //分享链接
imgUrl: `${shareURL}/myPackageA/static/images/cardLogo.png`, //图片
}
var url = window.location.href.split('#')[0]
hshare(data, url)
},
// 分享状态下获取名片信息
getShareCard(){
api.getShareBusinessCard(
this.cardId
).then(res =>{
if(res['success']){
this.cardInfo = res.data.data
this.cardId = res.data.data.id
this.infoList[0].value = this.cardInfo.phone || '暂无'
this.btnList[1].phoneNumber = this.cardInfo.phone || null
this.infoList[1].value = this.cardInfo.email || '暂无'
this.infoList[2].value = this.cardInfo.address || '暂无'
this.getshareData()
}else {
uni.showToast({
title: res['message'],
duration: 2000,
icon: 'none'
})
}
})
},
// 不是分享状态下获取名片信息
getCard(){
api.getBusinessCard(
this.userId
).then(res =>{
if(res['success']){
this.cardInfo = res.data.data
this.cardId = res.data.data.id
this.infoList[0].value = this.cardInfo.phone || '暂无'
this.btnList[1].phoneNumber = this.cardInfo.phone || null
this.infoList[1].value = this.cardInfo.email || '暂无'
this.infoList[2].value = this.cardInfo.address || '暂无'
// this.cardInfo.avatarUrl = 'https://dev-yindun-store.oss-cn-shanghai-finance-1-pub.aliyuncs.com/dealerEmployee/4eaf5af32e9c4589aa01c28d0e74e1e8/8fa37642f20a49d5beae7a8002c46c57/registerBg.png'
this.getshareData()
this.getCardStatic()
}else {
uni.showToast({
title: res['message'],
duration: 2000,
icon: 'none'
})
}
})
},
// 获取名片统计数据
getCardStatic(){
api.getCardStats(
{userId:this.userId,cardId:this.cardId}
).then(res =>{
if(res['success']){
if(res.data.data){
this.staticData[0].value = res.data.data.uvNum
this.staticData[1].value = res.data.data.pvNum
}
}else {
uni.showToast({
title: res['message'],
duration: 2000,
icon: 'none'
})
}
})
},
onClickItem(index) {
if (this.current !== index) {
this.current = index;
}
},
// 按钮点击事件
handleBtnClick(item) {
// // 拨打电话按钮
if (item.id === '2') {
if(item.phoneNumber){
uni.makePhoneCall({
phoneNumber: item.phoneNumber.replace(/\s+/g, ''),
success: () => {
console.log('拨打电话成功');
},
fail: (err) => {
uni.showToast({
title: '拨打电话失败',
icon: 'none'
});
}
});
}else {
uni.showToast({
title: '暂无电话',
duration: 2000,
icon: 'none'
})
}
} else {
// 其他按钮的处理逻辑
if(item.type!=='shareCard' || (item.type=='shareCard'&&this.runEnv=='browser')){
this.optionType = item.type
this.popupTitle = item.name
this.$refs.popup.open()
return
}
// 如果是移动端
this.shareTipsFlag = true;
this.getshareData()
}
},
//关闭登录
loginClose(val,loginTypeSync,type) {
// 直接点击了关闭登录的叉号
if(type){
this.sharelogin = false
this.isLogin = false
return
}
if (val) {
this.sharelogin = false
} else {
this.sharelogin = false
}
},
},
}
</script>
<style lang="scss" scoped>
.container{
position: relative;
background-color: rgba(235, 239, 247, 1);
display: flex;
flex-direction: column;
width: 100%;
height: auto;
box-sizing: border-box;
padding: 20rpx;
.loginTip{
width: 100%;
height: 50vh;
font-size: 30rpx;
display: flex;
justify-content: center;
align-items: center;
}
.cardHeader{
box-sizing: border-box;
border-radius: 20rpx ;
background-color: #fff;
.introduct{
box-sizing: border-box;
background-image: url('/myPackageA/static/images/cardBg.png');
background-repeat: no-repeat;
background-position: center center;
background-size: cover;
padding: 10rpx 15rpx;
width: 100%;
border-radius: 20rpx;
.introductHeader{
display: flex;
align-items: center;
width: 100%;
box-sizing: border-box;
margin-bottom: 50rpx;
.left{
flex: 1;
display: flex;
background-color: #fff;
border-radius: 50%;
align-items: center;
justify-content: center;
border: 8rpx solid #fff;
.avatar{
margin-top: -5rpx;
flex-grow: 0;
width: 120rpx;
height: 120rpx;
border-radius: 50%;
overflow: hidden;
// margin-right: 15rpx;
/* 背景图设置 */
background-size: cover;
background-position: center;
background-repeat: no-repeat;
/* 添加以下属性强制硬件加速 */
transform: translateZ(0);
-webkit-transform: translateZ(0);
backface-visibility: hidden;
-webkit-backface-visibility: hidden;
image{
width: 100%;
border-radius: 50%;
object-fit: cover;
/* 同样为图片添加硬件加速 */
transform: translateZ(0);
-webkit-transform: translateZ(0);
border-radius: none !important;
}
}
}
.right{
width:100% ;
margin-left: 10rpx;
box-sizing: border-box;
color: #fff;
display: flex;
flex-direction: column;
.top{
width: 100%;
font-size: 30rpx;
font-weight: 500;
margin-bottom: 10rpx;
}
.bottom{
width: 100%;
font-size: 26rpx;
.bottomCon{
box-sizing: border-box;
width: 100%;
display: flex;
justify-content: space-between;
}
}
}
}
.introductContent{
width: 100%;
box-sizing: border-box;
.infoCon{
width: 100%;
display: flex;
align-items: center;
color: #fff;
font-size: 24rpx;
margin-bottom: 10rpx;
.infoIcon{
margin-right: 15rpx;
}
}
}
}
.optionBtn{
width: 100%;
box-sizing: border-box;
display: flex;
justify-content: space-between;
padding: 20rpx 30rpx;
.btnCon{
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
.btnIcon{
font-size: 30rpx;
display: flex;
align-items: center;
justify-content: center;
padding: 10rpx;
}
.shareStyle{
color: #20269B;
font-size: 40rpx;
}
.commonBtn{
background-color: #20269B;
width: 50rpx;
height: 50rpx;
border-radius: 50%;
color: #ffff;
}
.btnTxt{
font-size: 26rpx;
}
}
}
}
.descriptionBox {
width: 510rpx;
padding: 40rpx;
.popupTit{
display: flex;
align-items: center;
justify-content: center;
font-size: 30rpx;
font-weight: 500;
margin-bottom: 10rpx;
}
.popupClose{
display: flex;
align-items: center;
justify-content: flex-end;
.icon-guanbi{
font-size: 28rpx;
}
}
.staticItem{
font-size: 28rpx;
margin-bottom: 10rpx;
.staticIcon{
font-size: 30rpx;
color: #20269B;
margin-right: 5rpx;
}
}
.imageBox{
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
font-size: 32rpx;
font-weight: 600;
.subTit{
font-size: 28rpx;
color: #919094;
margin: 15rpx 0;
font-weight: 400;
}
}
.codeBox{
display: flex;
align-items: center;
justify-content: center;
height: 250rpx;
}
.description{
color: rgba(56, 56, 56, 1);
font-size: 28rpx;
display: flex;
align-items: center;
justify-content: center;
}
}
.markBox {
position: fixed;
left: 0;
top: 0;
bottom: 0;
right: 0;
width: 100%;
height: 100%;
color: #fff;
display: flex;
justify-content: flex-end;
z-index: 100000;
background: rgba(0, 0, 0, 0.8);
.guideImgBox {
margin: 20px auto;
uni-image {
width: 25% !important;
position: absolute;
right: 0;
top: 0;
}
}
.tips {
margin-top: 30%;
padding: 0 30px;
}
}
}
::v-deep .my-segmented-control .segmented-control__item .uni-segmented-control__text {
font-size: 30rpx !important;
}
</style>
<template>
<view class="container" >
<!-- style="flex: 1;" -->
<view style="flex: 1;">
<view class="cardHeader" >
<view class="userHeader">
<!-- #ifdef APP -->
<text class="iconfont icon-youjiantou zuojiantou" @click="goBack()" style="left: 20rpx;"></text>
<!-- #endif -->
<view class="headerBox">
<view class="add">
<text class="iconfont icon-jiahao" ></text>
</view>
<view class="avartBox" @click="uploadAvatar('avatar')">
<view class="avartTip">
点击上传
</view>
<image v-if="optionForm.avatarUrl" :src="optionForm.avatarUrl " mode="widthFix"></image>
</view>
</view>
</view>
<view class="userInformation">
<view style="flex: 1;">
<view class="headerTitle">
基本信息
</view>
<view class="shimingBox">
<view class="itemBox">
<view class="formBox">
<view class="formItem">
<view class="left">
<text class="require">*</text>
<text>姓名</text>
</view>
<input
class="user-input"
maxlength="10"
type="text"
placeholder="请输入"
v-model="optionForm.userName"
/>
</view>
<!-- <view class="formItem" >
<view class="left">
<text class="require">*</text>
<text>证件类型</text>
</view>
<commonSelect
:dataList="idTypesList"
:visible="showIdType"
:showValue="idTypeIdx"
@confirm="changeIdTypeSelect"
@close="showIdType=false"
/>
</view> -->
<view class="formItem">
<view class="left">
<text class="require">*</text>
<text>手机号</text>
</view>
<input
class="user-input"
maxlength="11"
type="number"
placeholder="请输入"
v-model="optionForm.phone"
/>
</view>
<view class="formItem">
<view class="left">
<text class="require">*</text>
<text>邮箱</text>
</view>
<input
class="user-input"
maxlength="30"
type="text"
placeholder="请输入"
v-model="optionForm.email"
/>
</view>
<view class="formItem">
<view class="left">
<text class="require">*</text>
<text>上传企微二维码</text>
<view class="uploadTip">
请保证图片的清晰度(400*400)
</view>
</view>
<view class="iconBox" @click="uploadAvatar('qrCode')">
<text class="iconfont icon-zhaoxiangji"></text>
</view>
</view>
</view>
</view>
</view>
</view>
</view>
</view>
<view class="imageBox" v-if="optionForm.qwQrcode" >
<text>上传的二维码如下:</text>
<view class="imageCon">
<image :src="optionForm.qwQrcode" mode="widthFix" ></image>
</view>
</view>
</view>
<view class="cardBtn">
<view class="" @click="applyCard()">
申请名片
</view>
</view>
</view>
</template>
<script>
import api from "@/api/api";
import ListItem from '@/components/listItem/listItem.vue'
import commonSelect from '@/components/commonSelect/commonSelect.vue';
import common from '../../common/common';
import {
CommonUpload
} from '@/util/uploaderFile';
export default{
name:'businessCard',
components:{
ListItem,
commonSelect
},
data(){
return{
companyLogo : '../../static/logo2.png',
itemList:[
{leftText:'头像',rightImage:'../../static/logo2.png',id:'1',},
{leftText:'姓名',rightText:'豆丝店',id:'2'},
],
infoList:[
{name:'135 6477 5722',icon:'icon-dianhua',id:'1'},
{name:'yangww@homelegal.cn',icon:'icon-xinfeng',id:'2'},
{name:'上海市浦东新区陆家嘴软件园6号楼',icon:'icon-dingwei',id:'3'},
],
items: ["关于我们", "企业荣誉", "关注官微"],
current: 0,
systemInfo:{},
codeImage:'../../static/logo2.png',
dataForm: {
loginId: uni.getStorageSync('cffp_userId'),
targetType: "7",
targetId: '',
targetNo: "",
targetUseFor: "14",
targetSeq: "0"
},
optionForm: {
avatarUrl:'',
userName:'',
phone:'',
email:'',
qwQrcode:'',
userId:uni.getStorageSync('cffp_userId')
},
idTypesList:[]
}
},
onLoad() {
this.systemInfo = uni.getSystemInfoSync();
const { platform, deviceType, screenWidth, screenHeight } = this.systemInfo;
// console.log('this.systemInfo',this.systemInfo)
// console.log('platform',platform)
// console.log('deviceType',deviceType)
},
methods:{
uploadAvatar(upType) {
let that = this;
if(upType=='avatar'){
that.dataForm.targetUseFor = '2'
}else if(upType=='qrCode') {
that.dataForm.targetUseFor = '14'
}
CommonUpload(that.dataForm).then(res => {
if(upType=='avatar'){
this.optionForm.avatarUrl = res.data.filePath
}else if(upType=='qrCode') {
this.optionForm.qwQrcode = res.data.filePath
}
})
},
handleItemClick(type) {
console.log('点击了:', type)
// 根据类型跳转不同页面或执行不同操作
},
goBack() {
let back = getCurrentPages();
if (back && back.length > 1) {
uni.navigateBack({
delta: 1
});
}
},
// 提交申请名片
applyCard(){
let obj = {
avatarUrl:'头像',
userName:'姓名',
phone:'手机号',
email:'邮箱',
qwQrcode:'企微二维码',
}
for (var key1 in this.optionForm) {
for (var key2 in obj) {
if(key1==key2&&!this.optionForm[key1]){
uni.showModal({
title: '提示',
content: `${obj[key2]}不能为空`,
showCancel: false,
confirmText: '我知道了'
});
return
}
}
}
if(!common.phoneValid(this.optionForm.phone)){
uni.showModal({
title: '提示',
content: `请输入正确的手机号`,
showCancel: false,
confirmText: '我知道了'
});
return
}
if(!common.emailValid(this.optionForm.email)){
uni.showModal({
title: '提示',
content: `请输入正确的邮箱`,
showCancel: false,
confirmText: '我知道了'
});
return
}
api.saveApplyCard(
this.optionForm
).then(res =>{
if(res['success']){
uni.showModal({
title: '提交成功',
content: '您的名片正在审核中...',
showCancel: false,
success: function(res) {
if (res.confirm) {
uni.navigateBack({
delta: 1
});
}
}
});
}else {
uni.showToast({
title: res['message'],
duration: 2000,
icon: 'none'
})
}
})
}
},
}
</script>
<style lang="scss" scoped>
.container{
position: relative;
background-color: #fff;
display: flex;
flex-direction: column;
width: 100%;
height: auto;
box-sizing: border-box;
padding: 20rpx;
.cardHeader{
box-sizing: border-box;
width: 100%;
.headerTitle{
font-size: 35rpx;
color: #333333;
}
.custom-right{
.avatar{
flex-grow: 0;
width: 70rpx;
height: 70rpx;
border-radius: 50%;
overflow: hidden;
margin-right: 15rpx;
/* 背景图设置 */
background-size: cover;
background-position: center;
background-repeat: no-repeat;
/* 添加以下属性强制硬件加速 */
transform: translateZ(0);
-webkit-transform: translateZ(0);
backface-visibility: hidden;
-webkit-backface-visibility: hidden;
image{
width: 100%;
height: 100%;
object-fit: cover;
/* 同样为图片添加硬件加速 */
transform: translateZ(0);
-webkit-transform: translateZ(0);
border-radius: none !important;
}
}
}
}
.userHeader{
position: relative;
height: 250rpx;
width: 100%;
box-sizing: border-box;
.headerBox{
// margin-top: -20rpx;
// margin-left: 100rpx;
position: absolute;
bottom: 15%;
left: 50%;
transform: translateX(-50%);
z-index: 99;
.add{
width: 50rpx;
height: 50rpx;
position: absolute;
bottom: 2%;
right: 3%;
background-color: #20269B;
z-index: 2;
display: flex;
align-items: center;
justify-content: center;
padding: 8rpx;
border-radius: 50%;
box-sizing: border-box;
.icon-jiahao{
font-size: 28rpx;
color: #fff;
}
}
.avartBox{
width: 200rpx;
height: 200rpx;
border-radius: 50%;
border: 10rpx solid #fff;
box-sizing: border-box;
box-shadow: 0 0 30rpx 15rpx rgba(150, 150, 150, 0.1);
position: relative;
/* 添加以下属性强制硬件加速 */
transform: translateZ(0);
-webkit-transform: translateZ(0);
backface-visibility: hidden;
-webkit-backface-visibility: hidden;
overflow: hidden;
.avartTip{
font-size: 22rpx;
position: absolute;
top: 38%;
left: 50%;
transform: translateX(-50%);
}
image{
display: block; /* 确保图片是块级元素 */
width: 100%; /* 宽度填满容器 */
height: 100%; /* 高度填满容器 */
// border-radius: 50%; /* 保持圆形 */
object-fit: cover; /* 防止图片变形(可选) */
/* 同样为图片添加硬件加速 */
transform: translateZ(0);
-webkit-transform: translateZ(0);
}
}
}
}
.userInformation {
position: relative;
flex: 1;
width: 100%;
display: flex;
flex-direction: column;
.wave {
box-sizing: border-box;
min-width: 100%;
height: 120rpx;
position: relative;
padding: 0;
border: none;
box-shadow: 0 0 30rpx 100rpx rgba(253, 248, 245, 0.4);
image {
position: absolute;
top: -80%;
display: block;
min-width: 100%;
height: 100%;
object-fit: fill; /* 或 cover/contain 根据需求调整 */
}
.nickNameBox{
color: #333;
box-sizing: border-box;
width: 100%;
position: absolute;
top: -10%;
left: 0;
z-index: 88;
padding: 0rpx 30rpx 20rpx 30rpx;
font-size: 30rpx;
.box{
border-bottom: 1rpx solid #E4E4E4;
padding-bottom: 20rpx;
}
}
}
.shimingBox{
padding: 30rpx;
background-color: #fff;
color: #333;
position: relative;
.itemBox{
z-index: 100;
margin-bottom: 20rpx;
font-size: 28rpx;
.title{
font-size: 32rpx;
font-weight: 600;
color: block;
}
.subTit{
color: #666666;
font-size: 24rpx;
display: flex;
align-items: center;
padding-bottom: 10rpx;
border-bottom: 1rpx solid #EFEFEF;
margin-top: 10rpx;
.icon-circleDuiHao{
font-size: 26rpx;
color: #666666;
margin-right: 5rpx;
}
}
.tips{
color: #F43530;
margin: 15rpx 0;
}
.formBox{
.formItem{
display: flex;
align-items: center;
justify-content: space-between;
border-bottom: 1rpx solid #E8E8E8;
height: 100rpx;
position: relative;
.left{
font-size: 26rpx;
}
.require{
color: #F43530;
}
.user-input{
color: black;
font-size: 26rpx;
text-align: right;
padding-right: 20rpx;
width: 70%;
}
.iconBox{
padding: 20rpx;
background-color: #F2F2F2;
display: flex;
align-items: center;
justify-content: center;
.icon-zhaoxiangji{
font-size: 40rpx;
color: #ccc;
}
}
.uploadTip{
color: #A3A3A3;
font-size: 24rpx;
}
}
}
}
}
}
.upBox{
margin-top: 20rpx;
box-sizing: border-box;
width: 100%;
display: flex;
align-items: center;
justify-content: space-between;
.upTitle{
color: #6C6A66;
font-size: 28rpx;
}
.upDes{
color: #A3A3A3;
font-size: 25rpx;
}
.iconBox{
padding: 20rpx;
background-color: #F2F2F2;
display: flex;
align-items: center;
justify-content: center;
.icon-zhaoxiangji{
font-size: 40rpx;
color: #ccc;
}
}
}
.imageBox{
width: 100%;
box-sizing: border-box;
padding-left: 30rpx;
.imageCon{
width: 100%;
display: flex;
align-items: center;
justify-content: center;
image{
width: 400rpx !important;
}
}
}
.cardBtn{
width: 100%;
box-sizing: border-box;
display: flex;
align-items: center;
justify-content: center;
view{
background-color: #3639A9;
font-size: 30rpx;
color: #fff;
text-align: center;
width: 80%;
padding: 20rpx 0;
border-radius: 50rpx;
}
}
}
</style>
...@@ -18,7 +18,7 @@ ...@@ -18,7 +18,7 @@
"mp-painter": "^1.0.1", "mp-painter": "^1.0.1",
"nanoid": "^4.0.0", "nanoid": "^4.0.0",
"pdf.js": "^0.1.0", "pdf.js": "^0.1.0",
"pdfjs-dist": "^2.11.338", "pdfjs-dist": "^3.11.174",
"qrcode": "^1.5.4", "qrcode": "^1.5.4",
"qrcodejs2": "^0.0.2", "qrcodejs2": "^0.0.2",
"uqrcodejs": "^4.0.7", "uqrcodejs": "^4.0.7",
...@@ -476,6 +476,62 @@ ...@@ -476,6 +476,62 @@
"node": ">=18" "node": ">=18"
} }
}, },
"node_modules/@mapbox/node-pre-gyp": {
"version": "1.0.11",
"resolved": "https://registry.npmmirror.com/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.11.tgz",
"integrity": "sha512-Yhlar6v9WQgUp/He7BdgzOz8lqMQ8sU+jkCq7Wx8Myc5YFJLbEe7lgui/V7G1qB1DJykHSGwreceSaD60Y0PUQ==",
"optional": true,
"dependencies": {
"detect-libc": "^2.0.0",
"https-proxy-agent": "^5.0.0",
"make-dir": "^3.1.0",
"node-fetch": "^2.6.7",
"nopt": "^5.0.0",
"npmlog": "^5.0.1",
"rimraf": "^3.0.2",
"semver": "^7.3.5",
"tar": "^6.1.11"
},
"bin": {
"node-pre-gyp": "bin/node-pre-gyp"
}
},
"node_modules/@mapbox/node-pre-gyp/node_modules/make-dir": {
"version": "3.1.0",
"resolved": "https://registry.npmmirror.com/make-dir/-/make-dir-3.1.0.tgz",
"integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==",
"optional": true,
"dependencies": {
"semver": "^6.0.0"
},
"engines": {
"node": ">=8"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/@mapbox/node-pre-gyp/node_modules/make-dir/node_modules/semver": {
"version": "6.3.1",
"resolved": "https://registry.npmmirror.com/semver/-/semver-6.3.1.tgz",
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
"optional": true,
"bin": {
"semver": "bin/semver.js"
}
},
"node_modules/@mapbox/node-pre-gyp/node_modules/semver": {
"version": "7.7.3",
"resolved": "https://registry.npmmirror.com/semver/-/semver-7.7.3.tgz",
"integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==",
"optional": true,
"bin": {
"semver": "bin/semver.js"
},
"engines": {
"node": ">=10"
}
},
"node_modules/@rollup/plugin-virtual": { "node_modules/@rollup/plugin-virtual": {
"version": "3.0.2", "version": "3.0.2",
"resolved": "https://registry.npmmirror.com/@rollup/plugin-virtual/-/plugin-virtual-3.0.2.tgz", "resolved": "https://registry.npmmirror.com/@rollup/plugin-virtual/-/plugin-virtual-3.0.2.tgz",
...@@ -1032,6 +1088,24 @@ ...@@ -1032,6 +1088,24 @@
"resolved": "https://registry.npmmirror.com/@uqrcode/js/-/js-4.0.7.tgz", "resolved": "https://registry.npmmirror.com/@uqrcode/js/-/js-4.0.7.tgz",
"integrity": "sha512-4lIVp0mBrZw3yltc3C0/JuxMyNcqh7olX95xQYttrotITAxCL1AA0/RdcsBTSMP1M6TcKvJSuDDNUurDKyNuNw==" "integrity": "sha512-4lIVp0mBrZw3yltc3C0/JuxMyNcqh7olX95xQYttrotITAxCL1AA0/RdcsBTSMP1M6TcKvJSuDDNUurDKyNuNw=="
}, },
"node_modules/abbrev": {
"version": "1.1.1",
"resolved": "https://registry.npmmirror.com/abbrev/-/abbrev-1.1.1.tgz",
"integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==",
"optional": true
},
"node_modules/agent-base": {
"version": "6.0.2",
"resolved": "https://registry.npmmirror.com/agent-base/-/agent-base-6.0.2.tgz",
"integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==",
"optional": true,
"dependencies": {
"debug": "4"
},
"engines": {
"node": ">= 6.0.0"
}
},
"node_modules/ansi-regex": { "node_modules/ansi-regex": {
"version": "5.0.1", "version": "5.0.1",
"resolved": "https://registry.npmmirror.com/ansi-regex/-/ansi-regex-5.0.1.tgz", "resolved": "https://registry.npmmirror.com/ansi-regex/-/ansi-regex-5.0.1.tgz",
...@@ -1054,6 +1128,32 @@ ...@@ -1054,6 +1128,32 @@
"url": "https://github.com/chalk/ansi-styles?sponsor=1" "url": "https://github.com/chalk/ansi-styles?sponsor=1"
} }
}, },
"node_modules/aproba": {
"version": "2.1.0",
"resolved": "https://registry.npmmirror.com/aproba/-/aproba-2.1.0.tgz",
"integrity": "sha512-tLIEcj5GuR2RSTnxNKdkK0dJ/GrC7P38sUkiDmDuHfsHmbagTFAxDVIBltoklXEVIQ/f14IL8IMJ5pn9Hez1Ew==",
"optional": true
},
"node_modules/are-we-there-yet": {
"version": "2.0.0",
"resolved": "https://registry.npmmirror.com/are-we-there-yet/-/are-we-there-yet-2.0.0.tgz",
"integrity": "sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw==",
"deprecated": "This package is no longer supported.",
"optional": true,
"dependencies": {
"delegates": "^1.0.0",
"readable-stream": "^3.6.0"
},
"engines": {
"node": ">=10"
}
},
"node_modules/balanced-match": {
"version": "1.0.2",
"resolved": "https://registry.npmmirror.com/balanced-match/-/balanced-match-1.0.2.tgz",
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
"optional": true
},
"node_modules/base64-arraybuffer": { "node_modules/base64-arraybuffer": {
"version": "1.0.2", "version": "1.0.2",
"resolved": "https://registry.npmmirror.com/base64-arraybuffer/-/base64-arraybuffer-1.0.2.tgz", "resolved": "https://registry.npmmirror.com/base64-arraybuffer/-/base64-arraybuffer-1.0.2.tgz",
...@@ -1062,6 +1162,16 @@ ...@@ -1062,6 +1162,16 @@
"node": ">= 0.6.0" "node": ">= 0.6.0"
} }
}, },
"node_modules/brace-expansion": {
"version": "1.1.12",
"resolved": "https://registry.npmmirror.com/brace-expansion/-/brace-expansion-1.1.12.tgz",
"integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==",
"optional": true,
"dependencies": {
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
}
},
"node_modules/camelcase": { "node_modules/camelcase": {
"version": "5.3.1", "version": "5.3.1",
"resolved": "https://registry.npmmirror.com/camelcase/-/camelcase-5.3.1.tgz", "resolved": "https://registry.npmmirror.com/camelcase/-/camelcase-5.3.1.tgz",
...@@ -1070,6 +1180,30 @@ ...@@ -1070,6 +1180,30 @@
"node": ">=6" "node": ">=6"
} }
}, },
"node_modules/canvas": {
"version": "2.11.2",
"resolved": "https://registry.npmmirror.com/canvas/-/canvas-2.11.2.tgz",
"integrity": "sha512-ItanGBMrmRV7Py2Z+Xhs7cT+FNt5K0vPL4p9EZ/UX/Mu7hFbkxSjKF2KVtPwX7UYWp7dRKnrTvReflgrItJbdw==",
"hasInstallScript": true,
"optional": true,
"dependencies": {
"@mapbox/node-pre-gyp": "^1.0.0",
"nan": "^2.17.0",
"simple-get": "^3.0.3"
},
"engines": {
"node": ">=6"
}
},
"node_modules/chownr": {
"version": "2.0.0",
"resolved": "https://registry.npmmirror.com/chownr/-/chownr-2.0.0.tgz",
"integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==",
"optional": true,
"engines": {
"node": ">=10"
}
},
"node_modules/cliui": { "node_modules/cliui": {
"version": "6.0.0", "version": "6.0.0",
"resolved": "https://registry.npmmirror.com/cliui/-/cliui-6.0.0.tgz", "resolved": "https://registry.npmmirror.com/cliui/-/cliui-6.0.0.tgz",
...@@ -1110,6 +1244,27 @@ ...@@ -1110,6 +1244,27 @@
"resolved": "https://registry.npmmirror.com/color-name/-/color-name-1.1.4.tgz", "resolved": "https://registry.npmmirror.com/color-name/-/color-name-1.1.4.tgz",
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
}, },
"node_modules/color-support": {
"version": "1.1.3",
"resolved": "https://registry.npmmirror.com/color-support/-/color-support-1.1.3.tgz",
"integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==",
"optional": true,
"bin": {
"color-support": "bin.js"
}
},
"node_modules/concat-map": {
"version": "0.0.1",
"resolved": "https://registry.npmmirror.com/concat-map/-/concat-map-0.0.1.tgz",
"integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
"optional": true
},
"node_modules/console-control-strings": {
"version": "1.1.0",
"resolved": "https://registry.npmmirror.com/console-control-strings/-/console-control-strings-1.1.0.tgz",
"integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==",
"optional": true
},
"node_modules/copy-anything": { "node_modules/copy-anything": {
"version": "2.0.6", "version": "2.0.6",
"resolved": "https://registry.npmmirror.com/copy-anything/-/copy-anything-2.0.6.tgz", "resolved": "https://registry.npmmirror.com/copy-anything/-/copy-anything-2.0.6.tgz",
...@@ -1143,6 +1298,23 @@ ...@@ -1143,6 +1298,23 @@
"integrity": "sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==", "integrity": "sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==",
"license": "MIT" "license": "MIT"
}, },
"node_modules/debug": {
"version": "4.4.3",
"resolved": "https://registry.npmmirror.com/debug/-/debug-4.4.3.tgz",
"integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==",
"optional": true,
"dependencies": {
"ms": "^2.1.3"
},
"engines": {
"node": ">=6.0"
},
"peerDependenciesMeta": {
"supports-color": {
"optional": true
}
}
},
"node_modules/decamelize": { "node_modules/decamelize": {
"version": "1.2.0", "version": "1.2.0",
"resolved": "https://registry.npmmirror.com/decamelize/-/decamelize-1.2.0.tgz", "resolved": "https://registry.npmmirror.com/decamelize/-/decamelize-1.2.0.tgz",
...@@ -1151,6 +1323,33 @@ ...@@ -1151,6 +1323,33 @@
"node": ">=0.10.0" "node": ">=0.10.0"
} }
}, },
"node_modules/decompress-response": {
"version": "4.2.1",
"resolved": "https://registry.npmmirror.com/decompress-response/-/decompress-response-4.2.1.tgz",
"integrity": "sha512-jOSne2qbyE+/r8G1VU+G/82LBs2Fs4LAsTiLSHOCOMZQl2OKZ6i8i4IyHemTe+/yIXOtTcRQMzPcgyhoFlqPkw==",
"optional": true,
"dependencies": {
"mimic-response": "^2.0.0"
},
"engines": {
"node": ">=8"
}
},
"node_modules/delegates": {
"version": "1.0.0",
"resolved": "https://registry.npmmirror.com/delegates/-/delegates-1.0.0.tgz",
"integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==",
"optional": true
},
"node_modules/detect-libc": {
"version": "2.1.2",
"resolved": "https://registry.npmmirror.com/detect-libc/-/detect-libc-2.1.2.tgz",
"integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==",
"optional": true,
"engines": {
"node": ">=8"
}
},
"node_modules/dijkstrajs": { "node_modules/dijkstrajs": {
"version": "1.0.3", "version": "1.0.3",
"resolved": "https://registry.npmmirror.com/dijkstrajs/-/dijkstrajs-1.0.3.tgz", "resolved": "https://registry.npmmirror.com/dijkstrajs/-/dijkstrajs-1.0.3.tgz",
...@@ -1257,6 +1456,36 @@ ...@@ -1257,6 +1456,36 @@
"node": ">=8" "node": ">=8"
} }
}, },
"node_modules/fs-minipass": {
"version": "2.1.0",
"resolved": "https://registry.npmmirror.com/fs-minipass/-/fs-minipass-2.1.0.tgz",
"integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==",
"optional": true,
"dependencies": {
"minipass": "^3.0.0"
},
"engines": {
"node": ">= 8"
}
},
"node_modules/fs-minipass/node_modules/minipass": {
"version": "3.3.6",
"resolved": "https://registry.npmmirror.com/minipass/-/minipass-3.3.6.tgz",
"integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==",
"optional": true,
"dependencies": {
"yallist": "^4.0.0"
},
"engines": {
"node": ">=8"
}
},
"node_modules/fs.realpath": {
"version": "1.0.0",
"resolved": "https://registry.npmmirror.com/fs.realpath/-/fs.realpath-1.0.0.tgz",
"integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==",
"optional": true
},
"node_modules/fsevents": { "node_modules/fsevents": {
"version": "2.3.3", "version": "2.3.3",
"resolved": "https://registry.npmmirror.com/fsevents/-/fsevents-2.3.3.tgz", "resolved": "https://registry.npmmirror.com/fsevents/-/fsevents-2.3.3.tgz",
...@@ -1272,6 +1501,27 @@ ...@@ -1272,6 +1501,27 @@
"node": "^8.16.0 || ^10.6.0 || >=11.0.0" "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
} }
}, },
"node_modules/gauge": {
"version": "3.0.2",
"resolved": "https://registry.npmmirror.com/gauge/-/gauge-3.0.2.tgz",
"integrity": "sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q==",
"deprecated": "This package is no longer supported.",
"optional": true,
"dependencies": {
"aproba": "^1.0.3 || ^2.0.0",
"color-support": "^1.1.2",
"console-control-strings": "^1.0.0",
"has-unicode": "^2.0.1",
"object-assign": "^4.1.1",
"signal-exit": "^3.0.0",
"string-width": "^4.2.3",
"strip-ansi": "^6.0.1",
"wide-align": "^1.1.2"
},
"engines": {
"node": ">=10"
}
},
"node_modules/get-caller-file": { "node_modules/get-caller-file": {
"version": "2.0.5", "version": "2.0.5",
"resolved": "https://registry.npmmirror.com/get-caller-file/-/get-caller-file-2.0.5.tgz", "resolved": "https://registry.npmmirror.com/get-caller-file/-/get-caller-file-2.0.5.tgz",
...@@ -1280,6 +1530,27 @@ ...@@ -1280,6 +1530,27 @@
"node": "6.* || 8.* || >= 10.*" "node": "6.* || 8.* || >= 10.*"
} }
}, },
"node_modules/glob": {
"version": "7.2.3",
"resolved": "https://registry.npmmirror.com/glob/-/glob-7.2.3.tgz",
"integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
"deprecated": "Glob versions prior to v9 are no longer supported",
"optional": true,
"dependencies": {
"fs.realpath": "^1.0.0",
"inflight": "^1.0.4",
"inherits": "2",
"minimatch": "^3.1.1",
"once": "^1.3.0",
"path-is-absolute": "^1.0.0"
},
"engines": {
"node": "*"
},
"funding": {
"url": "https://github.com/sponsors/isaacs"
}
},
"node_modules/graceful-fs": { "node_modules/graceful-fs": {
"version": "4.2.11", "version": "4.2.11",
"resolved": "https://registry.npmmirror.com/graceful-fs/-/graceful-fs-4.2.11.tgz", "resolved": "https://registry.npmmirror.com/graceful-fs/-/graceful-fs-4.2.11.tgz",
...@@ -1288,6 +1559,12 @@ ...@@ -1288,6 +1559,12 @@
"license": "ISC", "license": "ISC",
"optional": true "optional": true
}, },
"node_modules/has-unicode": {
"version": "2.0.1",
"resolved": "https://registry.npmmirror.com/has-unicode/-/has-unicode-2.0.1.tgz",
"integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==",
"optional": true
},
"node_modules/html2canvas": { "node_modules/html2canvas": {
"version": "1.4.1", "version": "1.4.1",
"resolved": "https://registry.npmmirror.com/html2canvas/-/html2canvas-1.4.1.tgz", "resolved": "https://registry.npmmirror.com/html2canvas/-/html2canvas-1.4.1.tgz",
...@@ -1300,6 +1577,19 @@ ...@@ -1300,6 +1577,19 @@
"node": ">=8.0.0" "node": ">=8.0.0"
} }
}, },
"node_modules/https-proxy-agent": {
"version": "5.0.1",
"resolved": "https://registry.npmmirror.com/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz",
"integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==",
"optional": true,
"dependencies": {
"agent-base": "6",
"debug": "4"
},
"engines": {
"node": ">= 6"
}
},
"node_modules/iconv-lite": { "node_modules/iconv-lite": {
"version": "0.6.3", "version": "0.6.3",
"resolved": "https://registry.npmmirror.com/iconv-lite/-/iconv-lite-0.6.3.tgz", "resolved": "https://registry.npmmirror.com/iconv-lite/-/iconv-lite-0.6.3.tgz",
...@@ -1328,6 +1618,23 @@ ...@@ -1328,6 +1618,23 @@
"node": ">=0.10.0" "node": ">=0.10.0"
} }
}, },
"node_modules/inflight": {
"version": "1.0.6",
"resolved": "https://registry.npmmirror.com/inflight/-/inflight-1.0.6.tgz",
"integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==",
"deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.",
"optional": true,
"dependencies": {
"once": "^1.3.0",
"wrappy": "1"
}
},
"node_modules/inherits": {
"version": "2.0.4",
"resolved": "https://registry.npmmirror.com/inherits/-/inherits-2.0.4.tgz",
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
"optional": true
},
"node_modules/is-fullwidth-code-point": { "node_modules/is-fullwidth-code-point": {
"version": "3.0.0", "version": "3.0.0",
"resolved": "https://registry.npmmirror.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", "resolved": "https://registry.npmmirror.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
...@@ -1416,11 +1723,93 @@ ...@@ -1416,11 +1723,93 @@
"node": ">=4" "node": ">=4"
} }
}, },
"node_modules/mimic-response": {
"version": "2.1.0",
"resolved": "https://registry.npmmirror.com/mimic-response/-/mimic-response-2.1.0.tgz",
"integrity": "sha512-wXqjST+SLt7R009ySCglWBCFpjUygmCIfD790/kVbiGmUgfYGuB14PiTd5DwVxSV4NcYHjzMkoj5LjQZwTQLEA==",
"optional": true,
"engines": {
"node": ">=8"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/minimatch": {
"version": "3.1.2",
"resolved": "https://registry.npmmirror.com/minimatch/-/minimatch-3.1.2.tgz",
"integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
"optional": true,
"dependencies": {
"brace-expansion": "^1.1.7"
},
"engines": {
"node": "*"
}
},
"node_modules/minipass": {
"version": "5.0.0",
"resolved": "https://registry.npmmirror.com/minipass/-/minipass-5.0.0.tgz",
"integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==",
"optional": true,
"engines": {
"node": ">=8"
}
},
"node_modules/minizlib": {
"version": "2.1.2",
"resolved": "https://registry.npmmirror.com/minizlib/-/minizlib-2.1.2.tgz",
"integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==",
"optional": true,
"dependencies": {
"minipass": "^3.0.0",
"yallist": "^4.0.0"
},
"engines": {
"node": ">= 8"
}
},
"node_modules/minizlib/node_modules/minipass": {
"version": "3.3.6",
"resolved": "https://registry.npmmirror.com/minipass/-/minipass-3.3.6.tgz",
"integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==",
"optional": true,
"dependencies": {
"yallist": "^4.0.0"
},
"engines": {
"node": ">=8"
}
},
"node_modules/mkdirp": {
"version": "1.0.4",
"resolved": "https://registry.npmmirror.com/mkdirp/-/mkdirp-1.0.4.tgz",
"integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==",
"optional": true,
"bin": {
"mkdirp": "bin/cmd.js"
},
"engines": {
"node": ">=10"
}
},
"node_modules/mp-painter": { "node_modules/mp-painter": {
"version": "1.0.1", "version": "1.0.1",
"resolved": "https://registry.npmmirror.com/mp-painter/-/mp-painter-1.0.1.tgz", "resolved": "https://registry.npmmirror.com/mp-painter/-/mp-painter-1.0.1.tgz",
"integrity": "sha512-qq7Pt2o4MEbfM0XVfuObQTnhq5rAprudLexNvQ4nBQL/dgQPq1BvBzwhRYGrUEMB0UpOcKTw+xpaEW0ZMyL89Q==" "integrity": "sha512-qq7Pt2o4MEbfM0XVfuObQTnhq5rAprudLexNvQ4nBQL/dgQPq1BvBzwhRYGrUEMB0UpOcKTw+xpaEW0ZMyL89Q=="
}, },
"node_modules/ms": {
"version": "2.1.3",
"resolved": "https://registry.npmmirror.com/ms/-/ms-2.1.3.tgz",
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
"optional": true
},
"node_modules/nan": {
"version": "2.24.0",
"resolved": "https://registry.npmmirror.com/nan/-/nan-2.24.0.tgz",
"integrity": "sha512-Vpf9qnVW1RaDkoNKFUvfxqAbtI8ncb8OJlqZ9wwpXzWPEsvsB1nvdUi6oYrHIkQ1Y/tMDnr1h4nczS0VB9Xykg==",
"optional": true
},
"node_modules/nanoid": { "node_modules/nanoid": {
"version": "4.0.2", "version": "4.0.2",
"resolved": "https://registry.npmmirror.com/nanoid/-/nanoid-4.0.2.tgz", "resolved": "https://registry.npmmirror.com/nanoid/-/nanoid-4.0.2.tgz",
...@@ -1457,6 +1846,72 @@ ...@@ -1457,6 +1846,72 @@
"node": ">= 4.4.x" "node": ">= 4.4.x"
} }
}, },
"node_modules/node-fetch": {
"version": "2.7.0",
"resolved": "https://registry.npmmirror.com/node-fetch/-/node-fetch-2.7.0.tgz",
"integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==",
"optional": true,
"dependencies": {
"whatwg-url": "^5.0.0"
},
"engines": {
"node": "4.x || >=6.0.0"
},
"peerDependencies": {
"encoding": "^0.1.0"
},
"peerDependenciesMeta": {
"encoding": {
"optional": true
}
}
},
"node_modules/nopt": {
"version": "5.0.0",
"resolved": "https://registry.npmmirror.com/nopt/-/nopt-5.0.0.tgz",
"integrity": "sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==",
"optional": true,
"dependencies": {
"abbrev": "1"
},
"bin": {
"nopt": "bin/nopt.js"
},
"engines": {
"node": ">=6"
}
},
"node_modules/npmlog": {
"version": "5.0.1",
"resolved": "https://registry.npmmirror.com/npmlog/-/npmlog-5.0.1.tgz",
"integrity": "sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw==",
"deprecated": "This package is no longer supported.",
"optional": true,
"dependencies": {
"are-we-there-yet": "^2.0.0",
"console-control-strings": "^1.1.0",
"gauge": "^3.0.0",
"set-blocking": "^2.0.0"
}
},
"node_modules/object-assign": {
"version": "4.1.1",
"resolved": "https://registry.npmmirror.com/object-assign/-/object-assign-4.1.1.tgz",
"integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==",
"optional": true,
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/once": {
"version": "1.4.0",
"resolved": "https://registry.npmmirror.com/once/-/once-1.4.0.tgz",
"integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
"optional": true,
"dependencies": {
"wrappy": "1"
}
},
"node_modules/p-limit": { "node_modules/p-limit": {
"version": "2.3.0", "version": "2.3.0",
"resolved": "https://registry.npmmirror.com/p-limit/-/p-limit-2.3.0.tgz", "resolved": "https://registry.npmmirror.com/p-limit/-/p-limit-2.3.0.tgz",
...@@ -1508,6 +1963,24 @@ ...@@ -1508,6 +1963,24 @@
"node": ">=8" "node": ">=8"
} }
}, },
"node_modules/path-is-absolute": {
"version": "1.0.1",
"resolved": "https://registry.npmmirror.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
"integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==",
"optional": true,
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/path2d-polyfill": {
"version": "2.0.1",
"resolved": "https://registry.npmmirror.com/path2d-polyfill/-/path2d-polyfill-2.0.1.tgz",
"integrity": "sha512-ad/3bsalbbWhmBo0D6FZ4RNMwsLsPpL6gnvhuSaU5Vm7b06Kr5ubSltQQ0T7YKsiJQO+g22zJ4dJKNTXIyOXtA==",
"optional": true,
"engines": {
"node": ">=8"
}
},
"node_modules/pdf.js": { "node_modules/pdf.js": {
"version": "0.1.0", "version": "0.1.0",
"resolved": "https://registry.npmmirror.com/pdf.js/-/pdf.js-0.1.0.tgz", "resolved": "https://registry.npmmirror.com/pdf.js/-/pdf.js-0.1.0.tgz",
...@@ -1520,17 +1993,15 @@ ...@@ -1520,17 +1993,15 @@
} }
}, },
"node_modules/pdfjs-dist": { "node_modules/pdfjs-dist": {
"version": "2.11.338", "version": "3.11.174",
"resolved": "https://registry.npmmirror.com/pdfjs-dist/-/pdfjs-dist-2.11.338.tgz", "resolved": "https://registry.npmmirror.com/pdfjs-dist/-/pdfjs-dist-3.11.174.tgz",
"integrity": "sha512-Ti5VTB0VvSdtTtc7TG71ghMx0SEuNcEs4ghVuZxW0p6OqLjMc0xekZV1B+MmlxEG2Du2e5jgazucWIG/SXTcdA==", "integrity": "sha512-TdTZPf1trZ8/UFu5Cx/GXB7GZM30LT+wWUNfsi6Bq8ePLnb+woNKtDymI2mxZYBpMbonNFqKmiz684DIfnd8dA==",
"license": "Apache-2.0", "engines": {
"peerDependencies": { "node": ">=18"
"worker-loader": "^3.0.8"
}, },
"peerDependenciesMeta": { "optionalDependencies": {
"worker-loader": { "canvas": "^2.11.2",
"optional": true "path2d-polyfill": "^2.0.1"
}
} }
}, },
"node_modules/picocolors": { "node_modules/picocolors": {
...@@ -1649,6 +2120,20 @@ ...@@ -1649,6 +2120,20 @@
"resolved": "https://registry.npmmirror.com/qrcodejs2/-/qrcodejs2-0.0.2.tgz", "resolved": "https://registry.npmmirror.com/qrcodejs2/-/qrcodejs2-0.0.2.tgz",
"integrity": "sha512-+Y4HA+cb6qUzdgvI3KML8GYpMFwB24dFwzMkS/yXq6hwtUGNUnZQdUnksrV1XGMc2mid5ROw5SAuY9XhI3ValA==" "integrity": "sha512-+Y4HA+cb6qUzdgvI3KML8GYpMFwB24dFwzMkS/yXq6hwtUGNUnZQdUnksrV1XGMc2mid5ROw5SAuY9XhI3ValA=="
}, },
"node_modules/readable-stream": {
"version": "3.6.2",
"resolved": "https://registry.npmmirror.com/readable-stream/-/readable-stream-3.6.2.tgz",
"integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==",
"optional": true,
"dependencies": {
"inherits": "^2.0.3",
"string_decoder": "^1.1.1",
"util-deprecate": "^1.0.1"
},
"engines": {
"node": ">= 6"
}
},
"node_modules/require-directory": { "node_modules/require-directory": {
"version": "2.1.1", "version": "2.1.1",
"resolved": "https://registry.npmmirror.com/require-directory/-/require-directory-2.1.1.tgz", "resolved": "https://registry.npmmirror.com/require-directory/-/require-directory-2.1.1.tgz",
...@@ -1662,6 +2147,22 @@ ...@@ -1662,6 +2147,22 @@
"resolved": "https://registry.npmmirror.com/require-main-filename/-/require-main-filename-2.0.0.tgz", "resolved": "https://registry.npmmirror.com/require-main-filename/-/require-main-filename-2.0.0.tgz",
"integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==" "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg=="
}, },
"node_modules/rimraf": {
"version": "3.0.2",
"resolved": "https://registry.npmmirror.com/rimraf/-/rimraf-3.0.2.tgz",
"integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==",
"deprecated": "Rimraf versions prior to v4 are no longer supported",
"optional": true,
"dependencies": {
"glob": "^7.1.3"
},
"bin": {
"rimraf": "bin.js"
},
"funding": {
"url": "https://github.com/sponsors/isaacs"
}
},
"node_modules/rollup": { "node_modules/rollup": {
"version": "4.52.5", "version": "4.52.5",
"resolved": "https://registry.npmmirror.com/rollup/-/rollup-4.52.5.tgz", "resolved": "https://registry.npmmirror.com/rollup/-/rollup-4.52.5.tgz",
...@@ -1704,6 +2205,26 @@ ...@@ -1704,6 +2205,26 @@
"fsevents": "~2.3.2" "fsevents": "~2.3.2"
} }
}, },
"node_modules/safe-buffer": {
"version": "5.2.1",
"resolved": "https://registry.npmmirror.com/safe-buffer/-/safe-buffer-5.2.1.tgz",
"integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/feross"
},
{
"type": "patreon",
"url": "https://www.patreon.com/feross"
},
{
"type": "consulting",
"url": "https://feross.org/support"
}
],
"optional": true
},
"node_modules/safer-buffer": { "node_modules/safer-buffer": {
"version": "2.1.2", "version": "2.1.2",
"resolved": "https://registry.npmmirror.com/safer-buffer/-/safer-buffer-2.1.2.tgz", "resolved": "https://registry.npmmirror.com/safer-buffer/-/safer-buffer-2.1.2.tgz",
...@@ -1736,6 +2257,43 @@ ...@@ -1736,6 +2257,43 @@
"resolved": "https://registry.npmmirror.com/set-blocking/-/set-blocking-2.0.0.tgz", "resolved": "https://registry.npmmirror.com/set-blocking/-/set-blocking-2.0.0.tgz",
"integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==" "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw=="
}, },
"node_modules/signal-exit": {
"version": "3.0.7",
"resolved": "https://registry.npmmirror.com/signal-exit/-/signal-exit-3.0.7.tgz",
"integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==",
"optional": true
},
"node_modules/simple-concat": {
"version": "1.0.1",
"resolved": "https://registry.npmmirror.com/simple-concat/-/simple-concat-1.0.1.tgz",
"integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/feross"
},
{
"type": "patreon",
"url": "https://www.patreon.com/feross"
},
{
"type": "consulting",
"url": "https://feross.org/support"
}
],
"optional": true
},
"node_modules/simple-get": {
"version": "3.1.1",
"resolved": "https://registry.npmmirror.com/simple-get/-/simple-get-3.1.1.tgz",
"integrity": "sha512-CQ5LTKGfCpvE1K0n2us+kuMPbk/q0EKl82s4aheV9oXjFEz6W/Y7oQFVJuU6QG77hRT4Ghb5RURteF5vnWjupA==",
"optional": true,
"dependencies": {
"decompress-response": "^4.2.0",
"once": "^1.3.1",
"simple-concat": "^1.0.0"
}
},
"node_modules/source-map": { "node_modules/source-map": {
"version": "0.6.1", "version": "0.6.1",
"resolved": "https://registry.npmmirror.com/source-map/-/source-map-0.6.1.tgz", "resolved": "https://registry.npmmirror.com/source-map/-/source-map-0.6.1.tgz",
...@@ -1757,6 +2315,15 @@ ...@@ -1757,6 +2315,15 @@
"node": ">=0.10.0" "node": ">=0.10.0"
} }
}, },
"node_modules/string_decoder": {
"version": "1.3.0",
"resolved": "https://registry.npmmirror.com/string_decoder/-/string_decoder-1.3.0.tgz",
"integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
"optional": true,
"dependencies": {
"safe-buffer": "~5.2.0"
}
},
"node_modules/string-width": { "node_modules/string-width": {
"version": "4.2.3", "version": "4.2.3",
"resolved": "https://registry.npmmirror.com/string-width/-/string-width-4.2.3.tgz", "resolved": "https://registry.npmmirror.com/string-width/-/string-width-4.2.3.tgz",
...@@ -1781,6 +2348,23 @@ ...@@ -1781,6 +2348,23 @@
"node": ">=8" "node": ">=8"
} }
}, },
"node_modules/tar": {
"version": "6.2.1",
"resolved": "https://registry.npmmirror.com/tar/-/tar-6.2.1.tgz",
"integrity": "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==",
"optional": true,
"dependencies": {
"chownr": "^2.0.0",
"fs-minipass": "^2.0.0",
"minipass": "^5.0.0",
"minizlib": "^2.1.1",
"mkdirp": "^1.0.3",
"yallist": "^4.0.0"
},
"engines": {
"node": ">=10"
}
},
"node_modules/text-segmentation": { "node_modules/text-segmentation": {
"version": "1.0.3", "version": "1.0.3",
"resolved": "https://registry.npmmirror.com/text-segmentation/-/text-segmentation-1.0.3.tgz", "resolved": "https://registry.npmmirror.com/text-segmentation/-/text-segmentation-1.0.3.tgz",
...@@ -1806,6 +2390,12 @@ ...@@ -1806,6 +2390,12 @@
"url": "https://github.com/sponsors/SuperchupuDev" "url": "https://github.com/sponsors/SuperchupuDev"
} }
}, },
"node_modules/tr46": {
"version": "0.0.3",
"resolved": "https://registry.npmmirror.com/tr46/-/tr46-0.0.3.tgz",
"integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==",
"optional": true
},
"node_modules/tslib": { "node_modules/tslib": {
"version": "2.3.0", "version": "2.3.0",
"resolved": "https://registry.npmmirror.com/tslib/-/tslib-2.3.0.tgz", "resolved": "https://registry.npmmirror.com/tslib/-/tslib-2.3.0.tgz",
...@@ -1817,6 +2407,12 @@ ...@@ -1817,6 +2407,12 @@
"resolved": "https://registry.npmmirror.com/uqrcodejs/-/uqrcodejs-4.0.7.tgz", "resolved": "https://registry.npmmirror.com/uqrcodejs/-/uqrcodejs-4.0.7.tgz",
"integrity": "sha512-84+aZmD2godCVI+93lxE3YUAPNY8zAJvNA7xRS7R7U+q57KzMDepBSfNCwoRUhWOfR6eHFoAOcHRPwsP6ka1cA==" "integrity": "sha512-84+aZmD2godCVI+93lxE3YUAPNY8zAJvNA7xRS7R7U+q57KzMDepBSfNCwoRUhWOfR6eHFoAOcHRPwsP6ka1cA=="
}, },
"node_modules/util-deprecate": {
"version": "1.0.2",
"resolved": "https://registry.npmmirror.com/util-deprecate/-/util-deprecate-1.0.2.tgz",
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
"optional": true
},
"node_modules/utrie": { "node_modules/utrie": {
"version": "1.0.2", "version": "1.0.2",
"resolved": "https://registry.npmmirror.com/utrie/-/utrie-1.0.2.tgz", "resolved": "https://registry.npmmirror.com/utrie/-/utrie-1.0.2.tgz",
...@@ -1928,11 +2524,36 @@ ...@@ -1928,11 +2524,36 @@
"vite": ">=2.8" "vite": ">=2.8"
} }
}, },
"node_modules/webidl-conversions": {
"version": "3.0.1",
"resolved": "https://registry.npmmirror.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
"integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==",
"optional": true
},
"node_modules/whatwg-url": {
"version": "5.0.0",
"resolved": "https://registry.npmmirror.com/whatwg-url/-/whatwg-url-5.0.0.tgz",
"integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==",
"optional": true,
"dependencies": {
"tr46": "~0.0.3",
"webidl-conversions": "^3.0.0"
}
},
"node_modules/which-module": { "node_modules/which-module": {
"version": "2.0.1", "version": "2.0.1",
"resolved": "https://registry.npmmirror.com/which-module/-/which-module-2.0.1.tgz", "resolved": "https://registry.npmmirror.com/which-module/-/which-module-2.0.1.tgz",
"integrity": "sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==" "integrity": "sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ=="
}, },
"node_modules/wide-align": {
"version": "1.1.5",
"resolved": "https://registry.npmmirror.com/wide-align/-/wide-align-1.1.5.tgz",
"integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==",
"optional": true,
"dependencies": {
"string-width": "^1.0.2 || 2 || 3 || 4"
}
},
"node_modules/wrap-ansi": { "node_modules/wrap-ansi": {
"version": "6.2.0", "version": "6.2.0",
"resolved": "https://registry.npmmirror.com/wrap-ansi/-/wrap-ansi-6.2.0.tgz", "resolved": "https://registry.npmmirror.com/wrap-ansi/-/wrap-ansi-6.2.0.tgz",
...@@ -1946,11 +2567,23 @@ ...@@ -1946,11 +2567,23 @@
"node": ">=8" "node": ">=8"
} }
}, },
"node_modules/wrappy": {
"version": "1.0.2",
"resolved": "https://registry.npmmirror.com/wrappy/-/wrappy-1.0.2.tgz",
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
"optional": true
},
"node_modules/y18n": { "node_modules/y18n": {
"version": "4.0.3", "version": "4.0.3",
"resolved": "https://registry.npmmirror.com/y18n/-/y18n-4.0.3.tgz", "resolved": "https://registry.npmmirror.com/y18n/-/y18n-4.0.3.tgz",
"integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==" "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ=="
}, },
"node_modules/yallist": {
"version": "4.0.0",
"resolved": "https://registry.npmmirror.com/yallist/-/yallist-4.0.0.tgz",
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
"optional": true
},
"node_modules/yargs": { "node_modules/yargs": {
"version": "15.4.1", "version": "15.4.1",
"resolved": "https://registry.npmmirror.com/yargs/-/yargs-15.4.1.tgz", "resolved": "https://registry.npmmirror.com/yargs/-/yargs-15.4.1.tgz",
......
...@@ -25,7 +25,7 @@ ...@@ -25,7 +25,7 @@
"mp-painter": "^1.0.1", "mp-painter": "^1.0.1",
"nanoid": "^4.0.0", "nanoid": "^4.0.0",
"pdf.js": "^0.1.0", "pdf.js": "^0.1.0",
"pdfjs-dist": "^2.11.338", "pdfjs-dist": "^3.11.174",
"qrcode": "^1.5.4", "qrcode": "^1.5.4",
"qrcodejs2": "^0.0.2", "qrcodejs2": "^0.0.2",
"uqrcodejs": "^4.0.7", "uqrcodejs": "^4.0.7",
......
...@@ -597,6 +597,21 @@ ...@@ -597,6 +597,21 @@
"style": { "style": {
"navigationBarTitleText": "佣金详情" "navigationBarTitleText": "佣金详情"
} }
},
{
"path" : "businessCard/businessCard",
"style" :
{
"navigationBarTitleText" : "我的名片"
}
},
{
"path" : "noBusinessCard/noBusinessCard",
"style" :
{
"navigationBarTitleText" : "我的名片"
}
} }
] ]
......
...@@ -1189,25 +1189,6 @@ ...@@ -1189,25 +1189,6 @@
} }
}, },
// 重试机制
// retryGenerate() {
// if (this.retryCount < this.maxRetryCount) {
// this.retryCount++;
// const delay = 1000 * this.retryCount;
// console.log(`第${this.retryCount}次重试,${delay}ms后重试...`);
// setTimeout(() => {
// this.generateQrcodeAndCapture();
// }, delay);
// } else {
// // uni.showToast({
// // title: '生成分享图失败,请稍后再试',
// // icon: 'none'
// // });
// }
// },
// 生成二维码 // 生成二维码
makeQrcode() { makeQrcode() {
......
...@@ -351,7 +351,6 @@ ...@@ -351,7 +351,6 @@
this.$refs.partnerTipPopup.open() this.$refs.partnerTipPopup.open()
return return
} }
// 正常逻辑先注释掉
if(this.runEnv == 'browser'){ if(this.runEnv == 'browser'){
dataHandling.pocessTracking( dataHandling.pocessTracking(
'点击', '点击',
......
...@@ -67,10 +67,7 @@ ...@@ -67,10 +67,7 @@
@changeCourseClassify="changeCourseClassify" @changeCourseClassify="changeCourseClassify"
ref="courselist" ref="courselist"
></courselist> ></courselist>
<view class="productListBox">
</view>
</view> </view>
<view class="productEmpty" v-else> <view class="productEmpty" v-else>
暂无数据 暂无数据
......
...@@ -50,6 +50,15 @@ ...@@ -50,6 +50,15 @@
<view class="iconfont icon-youjiantou iconColor"></view> <view class="iconfont icon-youjiantou iconColor"></view>
</view> </view>
</view> </view>
<!-- 不是合伙人的角色可以看名片 v-if="customerBasicInfo.userIdentity&&customerBasicInfo.userIdentity!=='PARTNER'" -->
<view class="infoBody" v-if="customerBasicInfo.userIdentity&&customerBasicInfo.userIdentity!=='PARTNER'" style="margin-top: 10rpx;" @click="businessCard()">
<view class="">
我的名片
</view>
<view class="">
<view class="iconfont icon-youjiantou iconColor"></view>
</view>
</view>
<view class="kuaiBox" v-for="item in mainMenuLists" :key="item.id"> <view class="kuaiBox" v-for="item in mainMenuLists" :key="item.id">
<view class="kuaiTit"> <view class="kuaiTit">
{{item.categoryName}} {{item.categoryName}}
...@@ -660,20 +669,21 @@ ...@@ -660,20 +669,21 @@
api.queryInfo({userId:uni.getStorageSync('cffp_userId')}).then(res=>{ api.queryInfo({userId:uni.getStorageSync('cffp_userId')}).then(res=>{
if(res['success']){ if(res['success']){
this.customerBasicInfo = res['data']; this.customerBasicInfo = res['data'];
// id=03的权限设置 // id=03的权限设置
// 执行处理 // 执行处理
const result = this.setSpecificMenuIsShow(this.mainMenuLists, this.customerBasicInfo.accessPermission); const result = this.setSpecificMenuIsShow(this.mainMenuLists, this.customerBasicInfo.accessPermission);
// 输出结果(仅展示id=03的children验证效果) // 输出结果(仅展示id=03的children验证效果)
// console.log('处理后的"学习研讨"子菜单:', // console.log('处理后的"学习研讨"子菜单:',
// JSON.stringify(result.find(menu => menu.id === '03')?.children, null, 2)); // JSON.stringify(result.find(menu => menu.id === '03')?.children, null, 2));
// this.customerBasicInfo.userIdentity = 'DISTRIBUTOR'
let name = this.customerBasicInfo.realName || this.customerBasicInfo.nickName let name = this.customerBasicInfo.realName || this.customerBasicInfo.nickName
if(name && name.length>4){ if(name && name.length>4){
this.showMyName = name.substring(0, 4) + '...' this.showMyName = name.substring(0, 4) + '...'
}else { }else {
this.showMyName = name this.showMyName = name
} }
// this.customerBasicInfo.parentNickName = '除非进行相对路径配置'
// this.customerBasicInfo.parentRealName = '除非进行相对路径配置'
if(this.customerBasicInfo.parentRealName&&this.customerBasicInfo.parentNickName && this.customerBasicInfo.parentNickName.length>3){ if(this.customerBasicInfo.parentRealName&&this.customerBasicInfo.parentNickName && this.customerBasicInfo.parentNickName.length>3){
this.customerBasicInfo.parentNickName = this.customerBasicInfo.parentNickName.substring(0, 3) + '..' this.customerBasicInfo.parentNickName = this.customerBasicInfo.parentNickName.substring(0, 3) + '..'
} }
...@@ -691,7 +701,58 @@ ...@@ -691,7 +701,58 @@
} }
}) })
},
// 获取名片状态
// getCard(){
// }
// 我的名片页面
businessCard(){
if(!uni.getStorageSync('loginType')||uni.getStorageSync('loginType')=='visitor'){
this.isLogin()
return
}
let userId = uni.getStorageSync('cffp_userId')
// 和后端协商一致,先查询名片状态,在做出相应反应
api.getBusinessCard(
userId
).then(res =>{
if(res['success']){
let cardStatus = res.data.data.cardStatus
if(cardStatus=='1'){
//未申请名片
uni.navigateTo({
url:'/myPackageA/noBusinessCard/noBusinessCard'
});
}else if(cardStatus=='2'){
// 名片审核中
uni.showModal({
title: '提示',
content: `您申请的名片正在审核中,请耐心等待...`,
showCancel: false,
confirmText: '我知道了'
});
}else {
//申请的名片已经审核通过
uni.navigateTo({
url:'/myPackageA/businessCard/businessCard'
});
}
}else {
uni.showToast({
title: res['message'],
duration: 2000,
icon: 'none'
})
} }
})
// uni.navigateTo({
// url:'/myPackageA/businessCard/businessCard'
// });
// uni.navigateTo({
// url:'/myPackageA/noBusinessCard/noBusinessCard'
// });
},
}, },
...@@ -705,7 +766,6 @@ ...@@ -705,7 +766,6 @@
} }
.container{ .container{
box-sizing:border-box; box-sizing:border-box;
// background-color: #f7f7f7;
min-height: 100vh; /* 使用视口高度 */ min-height: 100vh; /* 使用视口高度 */
height: auto !important; height: auto !important;
height: 100vh; height: 100vh;
......
...@@ -55,6 +55,72 @@ ...@@ -55,6 +55,72 @@
<ul class="icon_lists dib-box"> <ul class="icon_lists dib-box">
<li class="dib"> <li class="dib">
<span class="icon iconfont">&#xe501;</span>
<div class="name">重点人群统计</div>
<div class="code-name">&amp;#xe501;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe502;</span>
<div class="name">总访问量</div>
<div class="code-name">&amp;#xe502;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe450;</span>
<div class="name">分享数据</div>
<div class="code-name">&amp;#xe450;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe447;</span>
<div class="name">邮箱</div>
<div class="code-name">&amp;#xe447;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe448;</span>
<div class="name">照相机</div>
<div class="code-name">&amp;#xe448;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe449;</span>
<div class="name">关注我的</div>
<div class="code-name">&amp;#xe449;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe446;</span>
<div class="name">导航</div>
<div class="code-name">&amp;#xe446;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe445;</span>
<div class="name">分享</div>
<div class="code-name">&amp;#xe445;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe444;</span>
<div class="name">信封</div>
<div class="code-name">&amp;#xe444;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe443;</span>
<div class="name">定位</div>
<div class="code-name">&amp;#xe443;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe442;</span>
<div class="name">电话</div>
<div class="code-name">&amp;#xe442;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe441;</span> <span class="icon iconfont">&#xe441;</span>
<div class="name">loading</div> <div class="name">loading</div>
<div class="code-name">&amp;#xe441;</div> <div class="code-name">&amp;#xe441;</div>
...@@ -450,9 +516,9 @@ ...@@ -450,9 +516,9 @@
<pre><code class="language-css" <pre><code class="language-css"
>@font-face { >@font-face {
font-family: 'iconfont'; font-family: 'iconfont';
src: url('iconfont.woff2?t=1755827337778') format('woff2'), src: url('iconfont.woff2?t=1763109218794') format('woff2'),
url('iconfont.woff?t=1755827337778') format('woff'), url('iconfont.woff?t=1763109218794') format('woff'),
url('iconfont.ttf?t=1755827337778') format('truetype'); url('iconfont.ttf?t=1763109218794') format('truetype');
} }
</code></pre> </code></pre>
<h3 id="-iconfont-">第二步:定义使用 iconfont 的样式</h3> <h3 id="-iconfont-">第二步:定义使用 iconfont 的样式</h3>
...@@ -479,6 +545,105 @@ ...@@ -479,6 +545,105 @@
<ul class="icon_lists dib-box"> <ul class="icon_lists dib-box">
<li class="dib"> <li class="dib">
<span class="icon iconfont icon-zhongdianrenquntongji"></span>
<div class="name">
重点人群统计
</div>
<div class="code-name">.icon-zhongdianrenquntongji
</div>
</li>
<li class="dib">
<span class="icon iconfont icon-zongfangwenliang"></span>
<div class="name">
总访问量
</div>
<div class="code-name">.icon-zongfangwenliang
</div>
</li>
<li class="dib">
<span class="icon iconfont icon-fenxiangshuju"></span>
<div class="name">
分享数据
</div>
<div class="code-name">.icon-fenxiangshuju
</div>
</li>
<li class="dib">
<span class="icon iconfont icon-youxiang"></span>
<div class="name">
邮箱
</div>
<div class="code-name">.icon-youxiang
</div>
</li>
<li class="dib">
<span class="icon iconfont icon-zhaoxiangji"></span>
<div class="name">
照相机
</div>
<div class="code-name">.icon-zhaoxiangji
</div>
</li>
<li class="dib">
<span class="icon iconfont icon-guanzhuwode"></span>
<div class="name">
关注我的
</div>
<div class="code-name">.icon-guanzhuwode
</div>
</li>
<li class="dib">
<span class="icon iconfont icon-daohang"></span>
<div class="name">
导航
</div>
<div class="code-name">.icon-daohang
</div>
</li>
<li class="dib">
<span class="icon iconfont icon-fenxiang"></span>
<div class="name">
分享
</div>
<div class="code-name">.icon-fenxiang
</div>
</li>
<li class="dib">
<span class="icon iconfont icon-xinfeng"></span>
<div class="name">
信封
</div>
<div class="code-name">.icon-xinfeng
</div>
</li>
<li class="dib">
<span class="icon iconfont icon-dingwei"></span>
<div class="name">
定位
</div>
<div class="code-name">.icon-dingwei
</div>
</li>
<li class="dib">
<span class="icon iconfont icon-dianhua"></span>
<div class="name">
电话
</div>
<div class="code-name">.icon-dianhua
</div>
</li>
<li class="dib">
<span class="icon iconfont icon-loading"></span> <span class="icon iconfont icon-loading"></span>
<div class="name"> <div class="name">
loading loading
...@@ -1074,6 +1239,94 @@ ...@@ -1074,6 +1239,94 @@
<li class="dib"> <li class="dib">
<svg class="icon svg-icon" aria-hidden="true"> <svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-zhongdianrenquntongji"></use>
</svg>
<div class="name">重点人群统计</div>
<div class="code-name">#icon-zhongdianrenquntongji</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-zongfangwenliang"></use>
</svg>
<div class="name">总访问量</div>
<div class="code-name">#icon-zongfangwenliang</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-fenxiangshuju"></use>
</svg>
<div class="name">分享数据</div>
<div class="code-name">#icon-fenxiangshuju</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-youxiang"></use>
</svg>
<div class="name">邮箱</div>
<div class="code-name">#icon-youxiang</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-zhaoxiangji"></use>
</svg>
<div class="name">照相机</div>
<div class="code-name">#icon-zhaoxiangji</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-guanzhuwode"></use>
</svg>
<div class="name">关注我的</div>
<div class="code-name">#icon-guanzhuwode</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-daohang"></use>
</svg>
<div class="name">导航</div>
<div class="code-name">#icon-daohang</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-fenxiang"></use>
</svg>
<div class="name">分享</div>
<div class="code-name">#icon-fenxiang</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-xinfeng"></use>
</svg>
<div class="name">信封</div>
<div class="code-name">#icon-xinfeng</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-dingwei"></use>
</svg>
<div class="name">定位</div>
<div class="code-name">#icon-dingwei</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-dianhua"></use>
</svg>
<div class="name">电话</div>
<div class="code-name">#icon-dianhua</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-loading"></use> <use xlink:href="#icon-loading"></use>
</svg> </svg>
<div class="name">loading</div> <div class="name">loading</div>
......
@font-face { @font-face {
font-family: "iconfont"; /* Project id 4933433 */ font-family: "iconfont"; /* Project id 4933433 */
src: url('iconfont.woff2?t=1755827337778') format('woff2'), src: url('iconfont.woff2?t=1763109218794') format('woff2'),
url('iconfont.woff?t=1755827337778') format('woff'), url('iconfont.woff?t=1763109218794') format('woff'),
url('iconfont.ttf?t=1755827337778') format('truetype'); url('iconfont.ttf?t=1763109218794') format('truetype');
} }
.iconfont { .iconfont {
...@@ -13,6 +13,50 @@ ...@@ -13,6 +13,50 @@
-moz-osx-font-smoothing: grayscale; -moz-osx-font-smoothing: grayscale;
} }
.icon-zhongdianrenquntongji:before {
content: "\e501";
}
.icon-zongfangwenliang:before {
content: "\e502";
}
.icon-fenxiangshuju:before {
content: "\e450";
}
.icon-youxiang:before {
content: "\e447";
}
.icon-zhaoxiangji:before {
content: "\e448";
}
.icon-guanzhuwode:before {
content: "\e449";
}
.icon-daohang:before {
content: "\e446";
}
.icon-fenxiang:before {
content: "\e445";
}
.icon-xinfeng:before {
content: "\e444";
}
.icon-dingwei:before {
content: "\e443";
}
.icon-dianhua:before {
content: "\e442";
}
.icon-loading:before { .icon-loading:before {
content: "\e441"; content: "\e441";
} }
......
This source diff could not be displayed because it is too large. You can view the blob instead.
...@@ -6,6 +6,83 @@ ...@@ -6,6 +6,83 @@
"description": "", "description": "",
"glyphs": [ "glyphs": [
{ {
"icon_id": "6008410",
"name": "重点人群统计",
"font_class": "zhongdianrenquntongji",
"unicode": "e501",
"unicode_decimal": 58625
},
{
"icon_id": "36876274",
"name": "总访问量",
"font_class": "zongfangwenliang",
"unicode": "e502",
"unicode_decimal": 58626
},
{
"icon_id": "24849517",
"name": "分享数据",
"font_class": "fenxiangshuju",
"unicode": "e450",
"unicode_decimal": 58448
},
{
"icon_id": "6186661",
"name": "邮箱",
"font_class": "youxiang",
"unicode": "e447",
"unicode_decimal": 58439
},
{
"icon_id": "630128",
"name": "照相机",
"font_class": "zhaoxiangji",
"unicode": "e448",
"unicode_decimal": 58440
},
{
"icon_id": "19942963",
"name": "关注我的",
"font_class": "guanzhuwode",
"unicode": "e449",
"unicode_decimal": 58441
},
{
"icon_id": "1069168",
"name": "导航",
"font_class": "daohang",
"unicode": "e446",
"unicode_decimal": 58438
},
{
"icon_id": "2217392",
"name": "分享",
"font_class": "fenxiang",
"unicode": "e445",
"unicode_decimal": 58437
},
{
"icon_id": "2380681",
"name": "信封",
"font_class": "xinfeng",
"unicode": "e444",
"unicode_decimal": 58436
},
{
"icon_id": "6582343",
"name": "定位",
"font_class": "dingwei",
"unicode": "e443",
"unicode_decimal": 58435
},
{
"icon_id": "25964419",
"name": "电话",
"font_class": "dianhua",
"unicode": "e442",
"unicode_decimal": 58434
},
{
"icon_id": "10273624", "icon_id": "10273624",
"name": "loading", "name": "loading",
"font_class": "loading", "font_class": "loading",
......
## 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目录规范
<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>
{
"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"
}
}
}
}
}
\ No newline at end of file
## Badge 数字角标
> **组件名:uni-badge**
> 代码块: `uBadge`
数字角标一般和其它控件(列表、9宫格等)配合使用,用于进行数量提示,默认为实心灰色背景,
### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-badge)
#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839
## 1.3.1(2021-12-20)
- 修复 在vue页面下略缩图显示不正常的bug
## 1.3.0(2021-11-19)
- 重构插槽的用法 ,header 替换为 title
- 新增 actions 插槽
- 新增 cover 封面图属性和插槽
- 新增 padding 内容默认内边距离
- 新增 margin 卡片默认外边距离
- 新增 spacing 卡片默认内边距
- 新增 shadow 卡片阴影属性
- 取消 mode 属性,可使用组合插槽代替
- 取消 note 属性 ,使用actions插槽代替
- 优化 组件UI,并提供设计资源,详见:[https://uniapp.dcloud.io/component/uniui/resource](https://uniapp.dcloud.io/component/uniui/resource)
- 文档迁移,详见:[https://uniapp.dcloud.io/component/uniui/uni-card](https://uniapp.dcloud.io/component/uniui/uni-card)
## 1.2.1(2021-07-30)
- 优化 vue3下事件警告的问题
## 1.2.0(2021-07-13)
- 组件兼容 vue3,如何创建vue3项目详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834)
## 1.1.8(2021-07-01)
- 优化 图文卡片无图片加载时,提供占位图标
- 新增 header 插槽,自定义卡片头部( 图文卡片 mode="style" 时,不支持)
- 修复 thumbnail 不存在仍然占位的 bug
## 1.1.7(2021-05-12)
- 新增 组件示例地址
## 1.1.6(2021-02-04)
- 调整为uni_modules目录规范
<template>
<view class="uni-card" :class="{ 'uni-card--full': isFull, 'uni-card--shadow': isShadow,'uni-card--border':border}"
:style="{'margin':isFull?0:margin,'padding':spacing,'box-shadow':isShadow?shadow:''}">
<!-- 封面 -->
<slot name="cover">
<view v-if="cover" class="uni-card__cover">
<image class="uni-card__cover-image" mode="widthFix" @click="onClick('cover')" :src="cover"></image>
</view>
</slot>
<slot name="title">
<view v-if="title || extra" class="uni-card__header">
<!-- 卡片标题 -->
<view class="uni-card__header-box" @click="onClick('title')">
<view v-if="thumbnail" class="uni-card__header-avatar">
<image class="uni-card__header-avatar-image" :src="thumbnail" mode="aspectFit" />
</view>
<view class="uni-card__header-content">
<text class="uni-card__header-content-title uni-ellipsis">{{ title }}</text>
<text v-if="title&&subTitle"
class="uni-card__header-content-subtitle uni-ellipsis">{{ subTitle }}</text>
</view>
</view>
<view class="uni-card__header-extra" @click="onClick('extra')">
<text class="uni-card__header-extra-text">{{ extra }}</text>
</view>
</view>
</slot>
<!-- 卡片内容 -->
<view class="uni-card__content" :style="{padding:padding}" @click="onClick('content')">
<slot></slot>
</view>
<view class="uni-card__actions" @click="onClick('actions')">
<slot name="actions"></slot>
</view>
</view>
</template>
<script>
/**
* Card 卡片
* @description 卡片视图组件
* @tutorial https://ext.dcloud.net.cn/plugin?id=22
* @property {String} title 标题文字
* @property {String} subTitle 副标题
* @property {Number} padding 内容内边距
* @property {Number} margin 卡片外边距
* @property {Number} spacing 卡片内边距
* @property {String} extra 标题额外信息
* @property {String} cover 封面图(本地路径需要引入)
* @property {String} thumbnail 标题左侧缩略图
* @property {Boolean} is-full = [true | false] 卡片内容是否通栏,为 true 时将去除padding值
* @property {Boolean} is-shadow = [true | false] 卡片内容是否开启阴影
* @property {String} shadow 卡片阴影
* @property {Boolean} border 卡片边框
* @event {Function} click 点击 Card 触发事件
*/
export default {
name: 'UniCard',
emits: ['click'],
props: {
title: {
type: String,
default: ''
},
subTitle: {
type: String,
default: ''
},
padding: {
type: String,
default: '10px'
},
margin: {
type: String,
default: '15px'
},
spacing: {
type: String,
default: '0 10px'
},
extra: {
type: String,
default: ''
},
cover: {
type: String,
default: ''
},
thumbnail: {
type: String,
default: ''
},
isFull: {
// 内容区域是否通栏
type: Boolean,
default: false
},
isShadow: {
// 是否开启阴影
type: Boolean,
default: true
},
shadow: {
type: String,
default: '0px 0px 3px 1px rgba(0, 0, 0, 0.08)'
},
border: {
type: Boolean,
default: true
}
},
methods: {
onClick(type) {
this.$emit('click', type)
}
}
}
</script>
<style lang="scss">
$uni-border-3: #EBEEF5 !default;
$uni-shadow-base:0 0px 6px 1px rgba($color: #a5a5a5, $alpha: 0.2) !default;
$uni-main-color: #3a3a3a !default;
$uni-base-color: #6a6a6a !default;
$uni-secondary-color: #909399 !default;
$uni-spacing-sm: 8px !default;
$uni-border-color:$uni-border-3;
$uni-shadow: $uni-shadow-base;
$uni-card-title: 15px;
$uni-cart-title-color:$uni-main-color;
$uni-card-subtitle: 12px;
$uni-cart-subtitle-color:$uni-secondary-color;
$uni-card-spacing: 10px;
$uni-card-content-color: $uni-base-color;
.uni-card {
margin: $uni-card-spacing;
padding: 0 $uni-spacing-sm;
border-radius: 4px;
overflow: hidden;
font-family: Helvetica Neue, Helvetica, PingFang SC, Hiragino Sans GB, Microsoft YaHei, SimSun, sans-serif;
background-color: #fff;
flex: 1;
.uni-card__cover {
position: relative;
margin-top: $uni-card-spacing;
flex-direction: row;
overflow: hidden;
border-radius: 4px;
.uni-card__cover-image {
flex: 1;
// width: 100%;
/* #ifndef APP-PLUS */
vertical-align: middle;
/* #endif */
}
}
.uni-card__header {
display: flex;
border-bottom: 1px $uni-border-color solid;
flex-direction: row;
align-items: center;
padding: $uni-card-spacing;
overflow: hidden;
.uni-card__header-box {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex: 1;
flex-direction: row;
align-items: center;
overflow: hidden;
}
.uni-card__header-avatar {
width: 40px;
height: 40px;
overflow: hidden;
border-radius: 5px;
margin-right: $uni-card-spacing;
.uni-card__header-avatar-image {
flex: 1;
width: 40px;
height: 40px;
}
}
.uni-card__header-content {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: column;
justify-content: center;
flex: 1;
// height: 40px;
overflow: hidden;
.uni-card__header-content-title {
font-size: $uni-card-title;
color: $uni-cart-title-color;
// line-height: 22px;
}
.uni-card__header-content-subtitle {
font-size: $uni-card-subtitle;
margin-top: 5px;
color: $uni-cart-subtitle-color;
}
}
.uni-card__header-extra {
line-height: 12px;
.uni-card__header-extra-text {
font-size: 12px;
color: $uni-cart-subtitle-color;
}
}
}
.uni-card__content {
padding: $uni-card-spacing;
font-size: 14px;
color: $uni-card-content-color;
line-height: 22px;
}
.uni-card__actions {
font-size: 12px;
}
}
.uni-card--border {
border: 1px solid $uni-border-color;
}
.uni-card--shadow {
position: relative;
/* #ifndef APP-NVUE */
box-shadow: $uni-shadow;
/* #endif */
}
.uni-card--full {
margin: 0;
border-left-width: 0;
border-left-width: 0;
border-radius: 0;
}
/* #ifndef APP-NVUE */
.uni-card--full:after {
border-radius: 0;
}
/* #endif */
.uni-ellipsis {
/* #ifndef APP-NVUE */
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
/* #endif */
/* #ifdef APP-NVUE */
lines: 1;
/* #endif */
}
</style>
{
"id": "uni-card",
"displayName": "uni-card 卡片",
"version": "1.3.1",
"description": "Card 组件,提供常见的卡片样式。",
"keywords": [
"uni-ui",
"uniui",
"card",
"",
"卡片"
],
"repository": "https://github.com/dcloudio/uni-ui",
"engines": {
"HBuilderX": ""
},
"directories": {
"example": "../../temps/example_temps"
},
"dcloudext": {
"category": [
"前端组件",
"通用组件"
],
"sale": {
"regular": {
"price": "0.00"
},
"sourcecode": {
"price": "0.00"
}
},
"contact": {
"qq": ""
},
"declaration": {
"ads": "无",
"data": "无",
"permissions": "无"
},
"npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui"
},
"uni_modules": {
"dependencies": [
"uni-icons",
"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"
},
"快应用": {
"华为": "u",
"联盟": "u"
},
"Vue": {
"vue2": "y",
"vue3": "y"
}
}
}
}
}
## Card 卡片
> **组件名:uni-card**
> 代码块: `uCard`
卡片视图组件。
### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-card)
#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839
## 1.1.2(2025-09-17)
- 修复 设置readonly属性后内容插槽失效的问题。
## 1.1.1(2025-09-03)
- 修复 动态dir目录,不生效的问题
## 1.1.0(2025-09-02)
- 新增 dir 属性,可以选择上传目录
## 1.0.13(2025-08-18)
- 修复 删除文件后,返回信息不包含file对象的问题
## 1.0.12(2025-04-14)
- 修复 支付宝小程序 上传样式问题
## 1.0.10(2024-07-09)
- 优化 vue3兼容性
## 1.0.9(2024-07-09)
- 修复 value 属性不兼容vue3的bug
## 1.0.8(2024-03-20)
- 补充 删除文件时返回文件下标
## 1.0.7(2024-02-21)
- 新增 微信小程序选择视频时改用chooseMedia,并返回视频缩略图
## 1.0.6(2024-01-06)
- 新增 微信小程序不再调用chooseImage,而是调用chooseMedia
## 1.0.5(2024-01-03)
- 新增 上传文件至云存储携带本地文件名称
## 1.0.4(2023-03-29)
- 修复 手动上传删除一个文件后不能再上传的bug
## 1.0.3(2022-12-19)
- 新增 sourceType 属性, 可以自定义图片和视频选择的来源
## 1.0.2(2022-07-04)
- 修复 在uni-forms下样式不生效的bug
## 1.0.1(2021-11-23)
- 修复 参数为对象的情况下,url在某些情况显示错误的bug
## 1.0.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-file-picker](https://uniapp.dcloud.io/component/uniui/uni-file-picker)
## 0.2.16(2021-11-08)
- 修复 传入空对象 ,显示错误的Bug
## 0.2.15(2021-08-30)
- 修复 return-type="object" 时且存在v-model时,无法删除文件的Bug
## 0.2.14(2021-08-23)
- 新增 参数中返回 fileID 字段
## 0.2.13(2021-08-23)
- 修复 腾讯云传入fileID 不能回显的bug
- 修复 选择图片后,不能放大的问题
## 0.2.12(2021-08-17)
- 修复 由于 0.2.11 版本引起的不能回显图片的Bug
## 0.2.11(2021-08-16)
- 新增 clearFiles(index) 方法,可以手动删除指定文件
- 修复 v-model 值设为 null 报错的Bug
## 0.2.10(2021-08-13)
- 修复 return-type="object" 时,无法删除文件的Bug
## 0.2.9(2021-08-03)
- 修复 auto-upload 属性失效的Bug
## 0.2.8(2021-07-31)
- 修复 fileExtname属性不指定值报错的Bug
## 0.2.7(2021-07-31)
- 修复 在某种场景下图片不回显的Bug
## 0.2.6(2021-07-30)
- 修复 return-type为object下,返回值不正确的Bug
## 0.2.5(2021-07-30)
- 修复(重要) H5 平台下如果和uni-forms组件一同使用导致页面卡死的问题
## 0.2.3(2021-07-28)
- 优化 调整示例代码
## 0.2.2(2021-07-27)
- 修复 vue3 下赋值错误的Bug
- 优化 h5平台下上传文件导致页面卡死的问题
## 0.2.0(2021-07-13)
- 组件兼容 vue3,如何创建vue3项目,详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834)
## 0.1.1(2021-07-02)
- 修复 sourceType 缺少默认值导致 ios 无法选择文件
## 0.1.0(2021-06-30)
- 优化 解耦与uniCloud的强绑定关系 ,如不绑定服务空间,默认autoUpload为false且不可更改
## 0.0.11(2021-06-30)
- 修复 由 0.0.10 版本引发的 returnType 属性失效的问题
## 0.0.10(2021-06-29)
- 优化 文件上传后进度条消失时机
## 0.0.9(2021-06-29)
- 修复 在uni-forms 中,删除文件 ,获取的值不对的Bug
## 0.0.8(2021-06-15)
- 修复 删除文件时无法触发 v-model 的Bug
## 0.0.7(2021-05-12)
- 新增 组件示例地址
## 0.0.6(2021-04-09)
- 修复 选择的文件非 file-extname 字段指定的扩展名报错的Bug
## 0.0.5(2021-04-09)
- 优化 更新组件示例
## 0.0.4(2021-04-09)
- 优化 file-extname 字段支持字符串写法,多个扩展名需要用逗号分隔
## 0.0.3(2021-02-05)
- 调整为uni_modules目录规范
- 修复 微信小程序不指定 fileExtname 属性选择失败的Bug
'use strict';
const ERR_MSG_OK = 'chooseAndUploadFile:ok';
const ERR_MSG_FAIL = 'chooseAndUploadFile:fail';
function chooseImage(opts) {
const {
count,
sizeType = ['original', 'compressed'],
sourceType,
extension
} = opts
return new Promise((resolve, reject) => {
// 微信由于旧接口不再维护,针对微信小程序平台改用chooseMedia接口
// #ifdef MP-WEIXIN
uni.chooseMedia({
count,
sizeType,
sourceType,
mediaType: ['image'],
extension,
success(res) {
res.tempFiles.forEach(item => {
item.path = item.tempFilePath;
})
resolve(normalizeChooseAndUploadFileRes(res, 'image'));
},
fail(res) {
reject({
errMsg: res.errMsg.replace('chooseImage:fail', ERR_MSG_FAIL),
});
},
})
// #endif
// #ifndef MP-WEIXIN
uni.chooseImage({
count,
sizeType,
sourceType,
extension,
success(res) {
resolve(normalizeChooseAndUploadFileRes(res, 'image'));
},
fail(res) {
reject({
errMsg: res.errMsg.replace('chooseImage:fail', ERR_MSG_FAIL),
});
},
});
// #endif
});
}
function chooseVideo(opts) {
const {
count,
camera,
compressed,
maxDuration,
sourceType,
extension
} = opts;
return new Promise((resolve, reject) => {
// 微信由于旧接口不再维护,针对微信小程序平台改用chooseMedia接口
// #ifdef MP-WEIXIN
uni.chooseMedia({
count,
compressed,
maxDuration,
sourceType,
extension,
mediaType: ['video'],
success(res) {
const {
tempFiles,
} = res;
resolve(normalizeChooseAndUploadFileRes({
errMsg: 'chooseVideo:ok',
tempFiles: tempFiles.map(item => {
return {
name: item.name || '',
path: item.tempFilePath,
thumbTempFilePath: item.thumbTempFilePath,
size:item.size,
type: (res.tempFile && res.tempFile.type) || '',
width:item.width,
height:item.height,
duration:item.duration,
fileType: 'video',
cloudPath: '',
}
}),
}, 'video'));
},
fail(res) {
reject({
errMsg: res.errMsg.replace('chooseVideo:fail', ERR_MSG_FAIL),
});
},
})
// #endif
// #ifndef MP-WEIXIN
uni.chooseVideo({
camera,
compressed,
maxDuration,
sourceType,
extension,
success(res) {
const {
tempFilePath,
duration,
size,
height,
width
} = res;
resolve(normalizeChooseAndUploadFileRes({
errMsg: 'chooseVideo:ok',
tempFilePaths: [tempFilePath],
tempFiles: [{
name: (res.tempFile && res.tempFile.name) || '',
path: tempFilePath,
size,
type: (res.tempFile && res.tempFile.type) || '',
width,
height,
duration,
fileType: 'video',
cloudPath: '',
}, ],
}, 'video'));
},
fail(res) {
reject({
errMsg: res.errMsg.replace('chooseVideo:fail', ERR_MSG_FAIL),
});
},
});
// #endif
});
}
function chooseAll(opts) {
const {
count,
extension
} = opts;
return new Promise((resolve, reject) => {
let chooseFile = uni.chooseFile;
if (typeof wx !== 'undefined' &&
typeof wx.chooseMessageFile === 'function') {
chooseFile = wx.chooseMessageFile;
}
if (typeof chooseFile !== 'function') {
return reject({
errMsg: ERR_MSG_FAIL + ' 请指定 type 类型,该平台仅支持选择 image 或 video。',
});
}
chooseFile({
type: 'all',
count,
extension,
success(res) {
resolve(normalizeChooseAndUploadFileRes(res));
},
fail(res) {
reject({
errMsg: res.errMsg.replace('chooseFile:fail', ERR_MSG_FAIL),
});
},
});
});
}
function normalizeChooseAndUploadFileRes(res, fileType) {
res.tempFiles.forEach((item, index) => {
if (!item.name) {
item.name = item.path.substring(item.path.lastIndexOf('/') + 1);
}
if (fileType) {
item.fileType = fileType;
}
item.cloudPath =
Date.now() + '_' + index + item.name.substring(item.name.lastIndexOf('.'));
});
if (!res.tempFilePaths) {
res.tempFilePaths = res.tempFiles.map((file) => file.path);
}
return res;
}
function uploadCloudFiles(files, max = 5, onUploadProgress) {
files = JSON.parse(JSON.stringify(files))
const len = files.length
let count = 0
let self = this
return new Promise(resolve => {
while (count < max) {
next()
}
function next() {
let cur = count++
if (cur >= len) {
!files.find(item => !item.url && !item.errMsg) && resolve(files)
return
}
const fileItem = files[cur]
const index = self.files.findIndex(v => v.uuid === fileItem.uuid)
fileItem.url = ''
delete fileItem.errMsg
uniCloud
.uploadFile({
filePath: fileItem.path,
cloudPath: fileItem.cloudPath,
fileType: fileItem.fileType,
onUploadProgress: res => {
res.index = index
onUploadProgress && onUploadProgress(res)
}
})
.then(res => {
fileItem.url = res.fileID
fileItem.index = index
if (cur < len) {
next()
}
})
.catch(res => {
fileItem.errMsg = res.errMsg || res.message
fileItem.index = index
if (cur < len) {
next()
}
})
}
})
}
function uploadFiles(choosePromise, {
onChooseFile,
onUploadProgress
}) {
return choosePromise
.then((res) => {
if (onChooseFile) {
const customChooseRes = onChooseFile(res);
if (typeof customChooseRes !== 'undefined') {
return Promise.resolve(customChooseRes).then((chooseRes) => typeof chooseRes === 'undefined' ?
res : chooseRes);
}
}
return res;
})
.then((res) => {
if (res === false) {
return {
errMsg: ERR_MSG_OK,
tempFilePaths: [],
tempFiles: [],
};
}
return res
})
}
function chooseAndUploadFile(opts = {
type: 'all'
}) {
if (opts.type === 'image') {
return uploadFiles(chooseImage(opts), opts);
} else if (opts.type === 'video') {
return uploadFiles(chooseVideo(opts), opts);
}
return uploadFiles(chooseAll(opts), opts);
}
export {
chooseAndUploadFile,
uploadCloudFiles
};
<template>
<view class="uni-file-picker">
<view v-if="title" class="uni-file-picker__header">
<text class="file-title">{{ title }}</text>
<text class="file-count">{{ filesList.length }}/{{ limitLength }}</text>
</view>
<upload-image v-if="fileMediatype === 'image' && showType === 'grid'" :readonly="readonly" :image-styles="imageStyles" :files-list="filesList" :limit="limitLength" :disablePreview="disablePreview" :delIcon="delIcon" @uploadFiles="uploadFiles" @choose="choose" @delFile="delFile">
<slot>
<view class="icon-add"></view>
<view class="icon-add rotate"></view>
</slot>
</upload-image>
<upload-file v-if="fileMediatype !== 'image' || showType !== 'grid'" :readonly="readonly" :list-styles="listStyles" :files-list="filesList" :showType="showType" :delIcon="delIcon" @uploadFiles="uploadFiles" @choose="choose" @delFile="delFile">
<slot><button type="primary" size="mini">选择文件</button></slot>
</upload-file>
</view>
</template>
<script>
import {
chooseAndUploadFile,
uploadCloudFiles
} from './choose-and-upload-file.js'
import {
get_file_ext,
get_extname,
get_files_and_is_max,
get_file_info,
get_file_data
} from './utils.js'
import uploadImage from './upload-image.vue'
import uploadFile from './upload-file.vue'
let fileInput = null
/**
* FilePicker 文件选择上传
* @description 文件选择上传组件,可以选择图片、视频等任意文件并上传到当前绑定的服务空间
* @tutorial https://ext.dcloud.net.cn/plugin?id=4079
* @property {Object|Array} value 组件数据,通常用来回显 ,类型由return-type属性决定
* @property {Boolean} disabled = [true|false] 组件禁用
* @value true 禁用
* @value false 取消禁用
* @property {Boolean} readonly = [true|false] 组件只读,不可选择,不显示进度,不显示删除按钮
* @value true 只读
* @value false 取消只读
* @property {String} return-type = [array|object] 限制 value 格式,当为 object 时 ,组件只能单选,且会覆盖
* @value array 规定 value 属性的类型为数组
* @value object 规定 value 属性的类型为对象
* @property {Boolean} disable-preview = [true|false] 禁用图片预览,仅 mode:grid 时生效
* @value true 禁用图片预览
* @value false 取消禁用图片预览
* @property {Boolean} del-icon = [true|false] 是否显示删除按钮
* @value true 显示删除按钮
* @value false 不显示删除按钮
* @property {Boolean} auto-upload = [true|false] 是否自动上传,值为true则只触发@select,可自行上传
* @value true 自动上传
* @value false 取消自动上传
* @property {Number|String} limit 最大选择个数 ,h5 会自动忽略多选的部分
* @property {String} title 组件标题,右侧显示上传计数
* @property {String} mode = [list|grid] 选择文件后的文件列表样式
* @value list 列表显示
* @value grid 宫格显示
* @property {String} file-mediatype = [image|video|all] 选择文件类型
* @value image 只选择图片
* @value video 只选择视频
* @value all 选择所有文件
* @property {Array} file-extname 选择文件后缀,根据 file-mediatype 属性而不同
* @property {Object} list-style mode:list 时的样式
* @property {Object} image-styles 选择文件后缀,根据 file-mediatype 属性而不同
* @event {Function} select 选择文件后触发
* @event {Function} progress 文件上传时触发
* @event {Function} success 上传成功触发
* @event {Function} fail 上传失败触发
* @event {Function} delete 文件从列表移除时触发
*/
export default {
name: 'uniFilePicker',
components: {
uploadImage,
uploadFile
},
options: {
virtualHost: true
},
emits: ['select', 'success', 'fail', 'progress', 'delete', 'update:modelValue', 'input'],
props: {
modelValue: {
type: [Array, Object],
default () {
return []
}
},
value: {
type: [Array, Object],
default () {
return []
}
},
disabled: {
type: Boolean,
default: false
},
disablePreview: {
type: Boolean,
default: false
},
delIcon: {
type: Boolean,
default: true
},
// 自动上传
autoUpload: {
type: Boolean,
default: true
},
// 最大选择个数 ,h5只能限制单选或是多选
limit: {
type: [Number, String],
default: 9
},
// 列表样式 grid | list | list-card
mode: {
type: String,
default: 'grid'
},
// 选择文件类型 image/video/all
fileMediatype: {
type: String,
default: 'image'
},
// 文件类型筛选
fileExtname: {
type: [Array, String],
default () {
return []
}
},
title: {
type: String,
default: ''
},
listStyles: {
type: Object,
default () {
return {
// 是否显示边框
border: true,
// 是否显示分隔线
dividline: true,
// 线条样式
borderStyle: {}
}
}
},
imageStyles: {
type: Object,
default () {
return {
width: 'auto',
height: 'auto'
}
}
},
readonly: {
type: Boolean,
default: false
},
returnType: {
type: String,
default: 'array'
},
sizeType: {
type: Array,
default () {
return ['original', 'compressed']
}
},
sourceType: {
type: Array,
default () {
return ['album', 'camera']
}
},
provider: {
type: String,
default: '' // 默认上传到 unicloud 内置存储 extStorage 扩展存储
},
dir: {
type: String,
default: '/'
}
},
data() {
return {
files: [],
localValue: [],
dirPath: '/'
}
},
watch: {
value: {
handler(newVal, oldVal) {
this.setValue(newVal, oldVal)
},
immediate: true
},
modelValue: {
handler(newVal, oldVal) {
this.setValue(newVal, oldVal)
},
immediate: true
},
dir: {
handler(newVal) {
this.dirPath = newVal
},
immediate: true
},
},
computed: {
filesList() {
let files = []
this.files.forEach(v => {
files.push(v)
})
return files
},
showType() {
if (this.fileMediatype === 'image') {
return this.mode
}
return 'list'
},
limitLength() {
if (this.returnType === 'object') {
return 1
}
if (!this.limit) {
return 1
}
if (this.limit >= 9) {
return 9
}
return this.limit
}
},
created() {
// TODO 兼容不开通服务空间的情况
if (!(uniCloud.config && uniCloud.config.provider)) {
this.noSpace = true
uniCloud.chooseAndUploadFile = chooseAndUploadFile
}
this.form = this.getForm('uniForms')
this.formItem = this.getForm('uniFormsItem')
if (this.form && this.formItem) {
if (this.formItem.name) {
this.rename = this.formItem.name
this.form.inputChildrens.push(this)
}
}
},
methods: {
/**
* 公开用户使用,清空文件
* @param {Object} index
*/
clearFiles(index) {
if (index !== 0 && !index) {
this.files = []
this.$nextTick(() => {
this.setEmit()
})
} else {
this.files.splice(index, 1)
}
this.$nextTick(() => {
this.setEmit()
})
},
/**
* 公开用户使用,继续上传
*/
upload() {
let files = []
this.files.forEach((v, index) => {
if (v.status === 'ready' || v.status === 'error') {
files.push(Object.assign({}, v))
}
})
return this.uploadFiles(files)
},
async setValue(newVal, oldVal) {
const newData = async (v) => {
const reg = /cloud:\/\/([\w.]+\/?)\S*/
let url = ''
if (v.fileID) {
url = v.fileID
} else {
url = v.url
}
if (reg.test(url)) {
v.fileID = url
v.url = await this.getTempFileURL(url)
}
if (v.url) v.path = v.url
return v
}
if (this.returnType === 'object') {
if (newVal) {
await newData(newVal)
} else {
newVal = {}
}
} else {
if (!newVal) newVal = []
for (let i = 0; i < newVal.length; i++) {
let v = newVal[i]
await newData(v)
}
}
this.localValue = newVal
if (this.form && this.formItem && !this.is_reset) {
this.is_reset = false
this.formItem.setValue(this.localValue)
}
let filesData = Object.keys(newVal).length > 0 ? newVal : [];
this.files = [].concat(filesData)
},
/**
* 选择文件
*/
choose() {
if (this.disabled) return
if (this.files.length >= Number(this.limitLength) && this.showType !== 'grid' && this.returnType ===
'array') {
uni.showToast({
title: `您最多选择 ${this.limitLength} 个文件`,
icon: 'none'
})
return
}
this.chooseFiles()
},
/**
* 选择文件并上传
*/
chooseFiles() {
const _extname = get_extname(this.fileExtname)
// 获取后缀
uniCloud
.chooseAndUploadFile({
type: this.fileMediatype,
compressed: false,
sizeType: this.sizeType,
sourceType: this.sourceType,
// TODO 如果为空,video 有问题
extension: _extname.length > 0 ? _extname : undefined,
count: this.limitLength - this.files.length, //默认9
onChooseFile: this.chooseFileCallback,
onUploadProgress: progressEvent => {
this.setProgress(progressEvent, progressEvent.index)
}
})
.then(result => {
this.setSuccessAndError(result.tempFiles)
})
.catch(err => {
console.log('选择失败', err)
})
},
/**
* 选择文件回调
* @param {Object} res
*/
async chooseFileCallback(res) {
const _extname = get_extname(this.fileExtname)
const is_one = (Number(this.limitLength) === 1 &&
this.disablePreview &&
!this.disabled) ||
this.returnType === 'object'
// 如果这有一个文件 ,需要清空本地缓存数据
if (is_one) {
this.files = []
}
let {
filePaths,
files
} = get_files_and_is_max(res, _extname)
if (!(_extname && _extname.length > 0)) {
filePaths = res.tempFilePaths
files = res.tempFiles
}
let currentData = []
for (let i = 0; i < files.length; i++) {
if (this.limitLength - this.files.length <= 0) break
files[i].uuid = Date.now()
let filedata = await get_file_data(files[i], this.fileMediatype)
filedata.progress = 0
filedata.status = 'ready'
// fix by mehaotian ,统一返回,删除也包含file对象
let fileTempData = {
...filedata,
file: files[i]
}
this.files.push(fileTempData)
currentData.push(fileTempData)
}
this.$emit('select', {
tempFiles: currentData,
tempFilePaths: filePaths
})
res.tempFiles = files
// 停止自动上传
if (!this.autoUpload || this.noSpace) {
res.tempFiles = []
}
res.tempFiles.map((fileItem, index) => {
this.provider && (fileItem.provider = this.provider);
const fileNameSplit = fileItem.name.split('.')
const ext = fileNameSplit.pop()
const fileName = fileNameSplit.join('.').replace(/[\s\/\?<>\\:\*\|":]/g, '_')
// 选择文件目录上传
let dir = this.dirPath || ''; // 防止用户传入的 dir 不正常
// 检查最后一个字符是否为 '/'(同时处理空字符串情况)
if (dir && dir[dir.length - 1] !== '/') {
dir += '/';
}
fileItem.cloudPath = dir + fileName + '_' + Date.now() + '_' + index + '.' + ext
fileItem.cloudPathAsRealPath = true
return fileItem
})
return res
},
/**
* 批传
* @param {Object} e
*/
uploadFiles(files) {
files = [].concat(files)
return uploadCloudFiles.call(this, files, 5, res => {
this.setProgress(res, res.index, true)
})
.then(result => {
this.setSuccessAndError(result)
return result;
})
.catch(err => {
console.log(err)
})
},
/**
* 成功或失败
*/
async setSuccessAndError(res, fn) {
let successData = []
let errorData = []
let tempFilePath = []
let errorTempFilePath = []
for (let i = 0; i < res.length; i++) {
const item = res[i]
const index = item.uuid ? this.files.findIndex(p => p.uuid === item.uuid) : item.index
if (index === -1 || !this.files) break
if (item.errMsg === 'request:fail') {
this.files[index].url = item.path
this.files[index].status = 'error'
this.files[index].errMsg = item.errMsg
// this.files[index].progress = -1
errorData.push(this.files[index])
errorTempFilePath.push(this.files[index].url)
} else {
this.files[index].errMsg = ''
this.files[index].fileID = item.url
const reg = /cloud:\/\/([\w.]+\/?)\S*/
if (reg.test(item.url)) {
this.files[index].url = await this.getTempFileURL(item.url)
} else {
this.files[index].url = item.url
}
this.files[index].status = 'success'
this.files[index].progress += 1
successData.push(this.files[index])
tempFilePath.push(this.files[index].fileID)
}
}
if (successData.length > 0) {
this.setEmit()
// 状态改变返回
this.$emit('success', {
tempFiles: this.backObject(successData),
tempFilePaths: tempFilePath
})
}
if (errorData.length > 0) {
this.$emit('fail', {
tempFiles: this.backObject(errorData),
tempFilePaths: errorTempFilePath
})
}
},
/**
* 获取进度
* @param {Object} progressEvent
* @param {Object} index
* @param {Object} type
*/
setProgress(progressEvent, index, type) {
const fileLenth = this.files.length
const percentNum = (index / fileLenth) * 100
const percentCompleted = Math.round((progressEvent.loaded * 100) / progressEvent.total)
let idx = index
if (!type) {
idx = this.files.findIndex(p => p.uuid === progressEvent.tempFile.uuid)
}
if (idx === -1 || !this.files[idx]) return
// fix by mehaotian 100 就会消失,-1 是为了让进度条消失
this.files[idx].progress = percentCompleted - 1
// 上传中
this.$emit('progress', {
index: idx,
progress: parseInt(percentCompleted),
tempFile: this.files[idx]
})
},
/**
* 删除文件
* @param {Object} index
*/
delFile(index) {
this.$emit('delete', {
index,
tempFile: this.files[index],
tempFilePath: this.files[index].url
})
this.files.splice(index, 1)
this.$nextTick(() => {
this.setEmit()
})
},
/**
* 获取文件名和后缀
* @param {Object} name
*/
getFileExt(name) {
const last_len = name.lastIndexOf('.')
const len = name.length
return {
name: name.substring(0, last_len),
ext: name.substring(last_len + 1, len)
}
},
/**
* 处理返回事件
*/
setEmit() {
let data = []
if (this.returnType === 'object') {
data = this.backObject(this.files)[0]
this.localValue = data ? data : null
} else {
data = this.backObject(this.files)
if (!this.localValue) {
this.localValue = []
}
this.localValue = [...data]
}
// #ifdef VUE3
this.$emit('update:modelValue', this.localValue)
// #endif
// #ifndef VUE3
this.$emit('input', this.localValue)
// #endif
},
/**
* 处理返回参数
* @param {Object} files
*/
backObject(files) {
let newFilesData = []
files.forEach(v => {
newFilesData.push({
extname: v.extname,
fileType: v.fileType,
image: v.image,
name: v.name,
path: v.path,
size: v.size,
fileID: v.fileID,
url: v.url,
// 修改删除一个文件后不能再上传的bug, #694
uuid: v.uuid,
status: v.status,
cloudPath: v.cloudPath
})
})
return newFilesData
},
async getTempFileURL(fileList) {
fileList = {
fileList: [].concat(fileList)
}
const urls = await uniCloud.getTempFileURL(fileList)
return urls.fileList[0].tempFileURL || ''
},
/**
* 获取父元素实例
*/
getForm(name = 'uniForms') {
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;
}
}
}
</script>
<style>
.uni-file-picker {
/* #ifndef APP-NVUE */
box-sizing: border-box;
overflow: hidden;
width: 100%;
/* #endif */
flex: 1;
}
.uni-file-picker__header {
padding-top: 5px;
padding-bottom: 10px;
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
justify-content: space-between;
}
.file-title {
font-size: 14px;
color: #333;
}
.file-count {
font-size: 14px;
color: #999;
}
.icon-add {
width: 50px;
height: 5px;
background-color: #f1f1f1;
border-radius: 2px;
}
.rotate {
position: absolute;
transform: rotate(90deg);
}
</style>
<template>
<view class="uni-file-picker__files">
<view v-if="!readonly" class="files-button" @click="choose">
<slot></slot>
</view>
<!-- :class="{'is-text-box':showType === 'list'}" -->
<view v-if="list.length > 0" class="uni-file-picker__lists is-text-box" :style="borderStyle">
<!-- ,'is-list-card':showType === 'list-card' -->
<view class="uni-file-picker__lists-box" v-for="(item ,index) in list" :key="index" :class="{
'files-border':index !== 0 && styles.dividline}" :style="index !== 0 && styles.dividline &&borderLineStyle">
<view class="uni-file-picker__item">
<!-- :class="{'is-text-image':showType === 'list'}" -->
<!-- <view class="files__image is-text-image">
<image class="header-image" :src="item.logo" mode="aspectFit"></image>
</view> -->
<view class="files__name">{{item.name}}</view>
<view v-if="delIcon&&!readonly" class="icon-del-box icon-files" @click="delFile(index)">
<view class="icon-del icon-files"></view>
<view class="icon-del rotate"></view>
</view>
</view>
<view v-if="(item.progress && item.progress !== 100) ||item.progress===0 " class="file-picker__progress">
<progress class="file-picker__progress-item" :percent="item.progress === -1?0:item.progress" stroke-width="4" :backgroundColor="item.errMsg?'#ff5a5f':'#EBEBEB'" />
</view>
<view v-if="item.status === 'error'" class="file-picker__mask" @click.stop="uploadFiles(item,index)">
点击重试
</view>
</view>
</view>
</view>
</template>
<script>
export default {
name: "uploadFile",
emits: ['uploadFiles', 'choose', 'delFile'],
props: {
filesList: {
type: Array,
default () {
return []
}
},
delIcon: {
type: Boolean,
default: true
},
limit: {
type: [Number, String],
default: 9
},
showType: {
type: String,
default: ''
},
listStyles: {
type: Object,
default () {
return {
// 是否显示边框
border: true,
// 是否显示分隔线
dividline: true,
// 线条样式
borderStyle: {}
}
}
},
readonly: {
type: Boolean,
default: false
}
},
computed: {
list() {
let files = []
this.filesList.forEach(v => {
files.push(v)
})
return files
},
styles() {
let styles = {
border: true,
dividline: true,
'border-style': {}
}
return Object.assign(styles, this.listStyles)
},
borderStyle() {
let {
borderStyle,
border
} = this.styles
let obj = {}
if (!border) {
obj.border = 'none'
} else {
let width = (borderStyle && borderStyle.width) || 1
width = this.value2px(width)
let radius = (borderStyle && borderStyle.radius) || 5
radius = this.value2px(radius)
obj = {
'border-width': width,
'border-style': (borderStyle && borderStyle.style) || 'solid',
'border-color': (borderStyle && borderStyle.color) || '#eee',
'border-radius': radius
}
}
let classles = ''
for (let i in obj) {
classles += `${i}:${obj[i]};`
}
return classles
},
borderLineStyle() {
let obj = {}
let {
borderStyle
} = this.styles
if (borderStyle && borderStyle.color) {
obj['border-color'] = borderStyle.color
}
if (borderStyle && borderStyle.width) {
let width = borderStyle && borderStyle.width || 1
let style = borderStyle && borderStyle.style || 0
if (typeof width === 'number') {
width += 'px'
} else {
width = width.indexOf('px') ? width : width + 'px'
}
obj['border-width'] = width
if (typeof style === 'number') {
style += 'px'
} else {
style = style.indexOf('px') ? style : style + 'px'
}
obj['border-top-style'] = style
}
let classles = ''
for (let i in obj) {
classles += `${i}:${obj[i]};`
}
return classles
}
},
methods: {
uploadFiles(item, index) {
this.$emit("uploadFiles", {
item,
index
})
},
choose() {
this.$emit("choose")
},
delFile(index) {
this.$emit('delFile', index)
},
value2px(value) {
if (typeof value === 'number') {
value += 'px'
} else {
value = value.indexOf('px') !== -1 ? value : value + 'px'
}
return value
}
}
}
</script>
<style lang="scss">
.uni-file-picker__files {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: column;
justify-content: flex-start;
}
.files-button {
// border: 1px red solid;
}
.uni-file-picker__lists {
position: relative;
margin-top: 5px;
overflow: hidden;
}
.file-picker__mask {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
justify-content: center;
align-items: center;
position: absolute;
right: 0;
top: 0;
bottom: 0;
left: 0;
color: #fff;
font-size: 14px;
background-color: rgba(0, 0, 0, 0.4);
}
.uni-file-picker__lists-box {
position: relative;
}
.uni-file-picker__item {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
align-items: center;
padding: 8px 10px;
padding-right: 5px;
padding-left: 10px;
}
.files-border {
border-top: 1px #eee solid;
}
.files__name {
flex: 1;
font-size: 14px;
color: #666;
margin-right: 25px;
/* #ifndef APP-NVUE */
word-break: break-all;
word-wrap: break-word;
/* #endif */
}
.icon-files {
/* #ifndef APP-NVUE */
position: static;
background-color: initial;
/* #endif */
}
// .icon-files .icon-del {
// background-color: #333;
// width: 12px;
// height: 1px;
// }
.is-list-card {
border: 1px #eee solid;
margin-bottom: 5px;
border-radius: 5px;
box-shadow: 0 0 2px 0px rgba(0, 0, 0, 0.1);
padding: 5px;
}
.files__image {
width: 40px;
height: 40px;
margin-right: 10px;
}
.header-image {
width: 100%;
height: 100%;
}
.is-text-box {
border: 1px #eee solid;
border-radius: 5px;
}
.is-text-image {
width: 25px;
height: 25px;
margin-left: 5px;
}
.rotate {
position: absolute;
transform: rotate(90deg);
}
.icon-del-box {
/* #ifndef APP-NVUE */
display: flex;
margin: auto 0;
/* #endif */
align-items: center;
justify-content: center;
position: absolute;
top: 0px;
bottom: 0;
right: 5px;
height: 26px;
width: 26px;
// border-radius: 50%;
// background-color: rgba(0, 0, 0, 0.5);
z-index: 2;
transform: rotate(-45deg);
}
.icon-del {
width: 15px;
height: 1px;
background-color: #333;
// border-radius: 1px;
}
/* #ifdef H5 */
@media all and (min-width: 768px) {
.uni-file-picker__files {
max-width: 375px;
}
}
/* #endif */
</style>
\ No newline at end of file
<template>
<view class="uni-file-picker__container">
<view class="file-picker__box" v-for="(item,index) in filesList" :key="index" :style="boxStyle">
<view class="file-picker__box-content" :style="borderStyle">
<image class="file-image" :src="item.url" mode="aspectFill" @click.stop="prviewImage(item,index)"></image>
<view v-if="delIcon && !readonly" class="icon-del-box" @click.stop="delFile(index)">
<view class="icon-del"></view>
<view class="icon-del rotate"></view>
</view>
<view v-if="(item.progress && item.progress !== 100) ||item.progress===0 " class="file-picker__progress">
<progress class="file-picker__progress-item" :percent="item.progress === -1?0:item.progress" stroke-width="4"
:backgroundColor="item.errMsg?'#ff5a5f':'#EBEBEB'" />
</view>
<view v-if="item.errMsg" class="file-picker__mask" @click.stop="uploadFiles(item,index)">
点击重试
</view>
</view>
</view>
<view v-if="filesList.length < limit" class="file-picker__box" :style="boxStyle">
<view class="file-picker__box-content is-add" :style="borderStyle" @click="choose">
<slot></slot>
</view>
</view>
</view>
</template>
<script>
export default {
name: "uploadImage",
emits:['uploadFiles','choose','delFile'],
props: {
filesList: {
type: Array,
default () {
return []
}
},
disabled:{
type: Boolean,
default: false
},
disablePreview: {
type: Boolean,
default: false
},
limit: {
type: [Number, String],
default: 9
},
imageStyles: {
type: Object,
default () {
return {
width: 'auto',
height: 'auto',
border: {}
}
}
},
delIcon: {
type: Boolean,
default: true
},
readonly:{
type:Boolean,
default:false
}
},
computed: {
styles() {
let styles = {
width: 'auto',
height: 'auto',
border: {}
}
return Object.assign(styles, this.imageStyles)
},
boxStyle() {
const {
width = 'auto',
height = 'auto'
} = this.styles
let obj = {}
if (height === 'auto') {
if (width !== 'auto') {
obj.height = this.value2px(width)
obj['padding-top'] = 0
} else {
obj.height = 0
}
} else {
obj.height = this.value2px(height)
obj['padding-top'] = 0
}
if (width === 'auto') {
if (height !== 'auto') {
obj.width = this.value2px(height)
} else {
obj.width = '33.3%'
}
} else {
obj.width = this.value2px(width)
}
let classles = ''
for(let i in obj){
classles+= `${i}:${obj[i]};`
}
return classles
},
borderStyle() {
let {
border
} = this.styles
let obj = {}
const widthDefaultValue = 1
const radiusDefaultValue = 3
if (typeof border === 'boolean') {
obj.border = border ? '1px #eee solid' : 'none'
} else {
let width = (border && border.width) || widthDefaultValue
width = this.value2px(width)
let radius = (border && border.radius) || radiusDefaultValue
radius = this.value2px(radius)
obj = {
'border-width': width,
'border-style': (border && border.style) || 'solid',
'border-color': (border && border.color) || '#eee',
'border-radius': radius
}
}
let classles = ''
for(let i in obj){
classles+= `${i}:${obj[i]};`
}
return classles
}
},
methods: {
uploadFiles(item, index) {
this.$emit("uploadFiles", item)
},
choose() {
if(this.readonly) return
this.$emit("choose")
},
delFile(index) {
if(this.readonly) return
this.$emit('delFile', index)
},
prviewImage(img, index) {
if(this.readonly) return
let urls = []
if(Number(this.limit) === 1&&this.disablePreview&&!this.disabled){
this.$emit("choose")
}
if(this.disablePreview) return
this.filesList.forEach(i => {
urls.push(i.url)
})
uni.previewImage({
urls: urls,
current: index
});
},
value2px(value) {
if (typeof value === 'number') {
value += 'px'
} else {
if (value.indexOf('%') === -1) {
value = value.indexOf('px') !== -1 ? value : value + 'px'
}
}
return value
}
}
}
</script>
<style lang="scss">
.uni-file-picker__container {
/* #ifndef APP-NVUE */
display: flex;
box-sizing: border-box;
/* #endif */
flex-wrap: wrap;
margin: -5px;
}
.file-picker__box {
position: relative;
// flex: 0 0 33.3%;
width: 33.3%;
height: 0;
padding-top: 33.33%;
/* #ifndef APP-NVUE */
box-sizing: border-box;
/* #endif */
}
.file-picker__box-content {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
margin: 5px;
border: 1px #eee solid;
border-radius: 5px;
overflow: hidden;
}
.file-picker__progress {
position: absolute;
bottom: 0;
left: 0;
right: 0;
/* border: 1px red solid; */
z-index: 2;
}
.file-picker__progress-item {
width: 100%;
}
.file-picker__mask {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
justify-content: center;
align-items: center;
position: absolute;
right: 0;
top: 0;
bottom: 0;
left: 0;
color: #fff;
font-size: 12px;
background-color: rgba(0, 0, 0, 0.4);
}
.file-image {
width: 100%;
height: 100%;
}
.is-add {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
align-items: center;
justify-content: center;
}
.rotate {
position: absolute;
transform: rotate(90deg);
}
.icon-del-box {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
align-items: center;
justify-content: center;
position: absolute;
top: 3px;
right: 3px;
height: 26px;
width: 26px;
border-radius: 50%;
background-color: rgba(0, 0, 0, 0.5);
z-index: 2;
transform: rotate(-45deg);
}
.icon-del {
width: 15px;
height: 2px;
background-color: #fff;
border-radius: 2px;
}
</style>
/**
* 获取文件名和后缀
* @param {String} name
*/
export const get_file_ext = (name) => {
const last_len = name.lastIndexOf('.')
const len = name.length
return {
name: name.substring(0, last_len),
ext: name.substring(last_len + 1, len)
}
}
/**
* 获取扩展名
* @param {Array} fileExtname
*/
export const get_extname = (fileExtname) => {
if (!Array.isArray(fileExtname)) {
let extname = fileExtname.replace(/(\[|\])/g, '')
return extname.split(',')
} else {
return fileExtname
}
return []
}
/**
* 获取文件和检测是否可选
*/
export const get_files_and_is_max = (res, _extname) => {
let filePaths = []
let files = []
if(!_extname || _extname.length === 0){
return {
filePaths,
files
}
}
res.tempFiles.forEach(v => {
let fileFullName = get_file_ext(v.name)
const extname = fileFullName.ext.toLowerCase()
if (_extname.indexOf(extname) !== -1) {
files.push(v)
filePaths.push(v.path)
}
})
if (files.length !== res.tempFiles.length) {
uni.showToast({
title: `当前选择了${res.tempFiles.length}个文件 ,${res.tempFiles.length - files.length} 个文件格式不正确`,
icon: 'none',
duration: 5000
})
}
return {
filePaths,
files
}
}
/**
* 获取图片信息
* @param {Object} filepath
*/
export const get_file_info = (filepath) => {
return new Promise((resolve, reject) => {
uni.getImageInfo({
src: filepath,
success(res) {
resolve(res)
},
fail(err) {
reject(err)
}
})
})
}
/**
* 获取封装数据
*/
export const get_file_data = async (files, type = 'image') => {
// 最终需要上传数据库的数据
let fileFullName = get_file_ext(files.name)
const extname = fileFullName.ext.toLowerCase()
let filedata = {
name: files.name,
uuid: files.uuid,
extname: extname || '',
cloudPath: files.cloudPath,
fileType: files.fileType,
thumbTempFilePath: files.thumbTempFilePath,
url: files.path || files.path,
size: files.size, //单位是字节
image: {},
path: files.path,
video: {}
}
if (type === 'image') {
const imageinfo = await get_file_info(files.path)
delete filedata.video
filedata.image.width = imageinfo.width
filedata.image.height = imageinfo.height
filedata.image.location = imageinfo.path
} else {
delete filedata.image
}
return filedata
}
{
"id": "uni-file-picker",
"displayName": "uni-file-picker 文件选择上传",
"version": "1.1.2",
"description": "文件选择上传组件,可以选择图片、视频等任意文件并上传到当前绑定的服务空间",
"keywords": [
"uni-ui",
"uniui",
"图片上传",
"文件上传"
],
"repository": "https://github.com/dcloudio/uni-ui",
"engines": {
"HBuilderX": "",
"uni-app": "^4.33",
"uni-app-x": ""
},
"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",
"darkmode": "x",
"i18n": "x",
"widescreen": "x"
},
"uni_modules": {
"dependencies": [
"uni-scss"
],
"encrypt": [],
"platforms": {
"cloud": {
"tcb": "√",
"aliyun": "√",
"alipay": "√"
},
"client": {
"uni-app": {
"vue": {
"vue2": "√",
"vue3": "√"
},
"web": {
"safari": "√",
"chrome": "√"
},
"app": {
"vue": "√",
"nvue": "-",
"android": "√",
"ios": "√",
"harmony": "√"
},
"mp": {
"weixin": "√",
"alipay": "√",
"toutiao": "√",
"baidu": "√",
"kuaishou": "√",
"jd": "-",
"harmony": "-",
"qq": "√",
"lark": "-"
},
"quickapp": {
"huawei": "√",
"union": "√"
}
},
"uni-app-x": {
"web": {
"safari": "-",
"chrome": "-"
},
"app": {
"android": "-",
"ios": "-",
"harmony": "-"
},
"mp": {
"weixin": "-"
}
}
}
}
}
}
\ No newline at end of file
## FilePicker 文件选择上传
> **组件名:uni-file-picker**
> 代码块: `uFilePicker`
文件选择上传组件,可以选择图片、视频等任意文件并上传到当前绑定的服务空间
### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-file-picker)
#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839
\ No newline at end of file
## 2.0.10(2024-06-07) ## 2.0.12(2025-08-26)
- 优化 uni-app x 中,size 属性的类型 - 优化 uni-app x 下 size 类型问题
## 2.0.11(2025-08-18)
- 修复 图标点击事件返回
## 2.0.9(2024-01-12) ## 2.0.9(2024-01-12)
fix: 修复图标大小默认值错误的问题 fix: 修复图标大小默认值错误的问题
## 2.0.8(2023-12-14) ## 2.0.8(2023-12-14)
......
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
* Icons 图标 * Icons 图标
* @description 用于展示 icon 图标 * @description 用于展示 icon 图标
* @tutorial https://ext.dcloud.net.cn/plugin?id=28 * @tutorial https://ext.dcloud.net.cn/plugin?id=28
* @property {Number,String} size 图标大小 * @property {Number} size 图标大小
* @property {String} type 图标图案,参考示例 * @property {String} type 图标图案,参考示例
* @property {String} color 图标颜色 * @property {String} color 图标颜色
* @property {String} customPrefix 自定义图标 * @property {String} customPrefix 自定义图标
......
...@@ -85,8 +85,8 @@ ...@@ -85,8 +85,8 @@
} }
}, },
methods: { methods: {
_onClick() { _onClick(e) {
this.$emit('click') this.$emit('click', e)
} }
} }
} }
......
{ {
"id": "uni-icons", "id": "uni-icons",
"displayName": "uni-icons 图标", "displayName": "uni-icons 图标",
"version": "2.0.10", "version": "2.0.12",
"description": "图标组件,用于展示移动端常见的图标,可自定义颜色、大小。", "description": "图标组件,用于展示移动端常见的图标,可自定义颜色、大小。",
"keywords": [ "keywords": [
"uni-ui", "uni-ui",
...@@ -11,12 +11,14 @@ ...@@ -11,12 +11,14 @@
], ],
"repository": "https://github.com/dcloudio/uni-ui", "repository": "https://github.com/dcloudio/uni-ui",
"engines": { "engines": {
"HBuilderX": "^3.2.14" "HBuilderX": "^3.2.14",
"uni-app": "^4.08",
"uni-app-x": "^4.61"
}, },
"directories": { "directories": {
"example": "../../temps/example_temps" "example": "../../temps/example_temps"
}, },
"dcloudext": { "dcloudext": {
"sale": { "sale": {
"regular": { "regular": {
"price": "0.00" "price": "0.00"
...@@ -34,54 +36,74 @@ ...@@ -34,54 +36,74 @@
"permissions": "无" "permissions": "无"
}, },
"npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui", "npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui",
"type": "component-vue" "type": "component-vue",
"darkmode": "x",
"i18n": "x",
"widescreen": "x"
}, },
"uni_modules": { "uni_modules": {
"dependencies": ["uni-scss"], "dependencies": [
"uni-scss"
],
"encrypt": [], "encrypt": [],
"platforms": { "platforms": {
"cloud": { "cloud": {
"tcb": "y", "tcb": "x",
"aliyun": "y", "aliyun": "x",
"alipay": "n" "alipay": "x"
}, },
"client": { "client": {
"App": { "uni-app": {
"app-vue": "y", "vue": {
"app-nvue": "y", "vue2": "√",
"app-uvue": "y" "vue3": "√"
}, },
"H5-mobile": { "web": {
"Safari": "y", "safari": "√",
"Android Browser": "y", "chrome": "√"
"微信浏览器(Android)": "y", },
"QQ浏览器(Android)": "y" "app": {
}, "vue": "√",
"H5-pc": { "nvue": "-",
"Chrome": "y", "android": {
"IE": "y", "extVersion": "",
"Edge": "y", "minVersion": "29"
"Firefox": "y", },
"Safari": "y" "ios": "√",
}, "harmony": "√"
"小程序": { },
"微信": "y", "mp": {
"阿里": "y", "weixin": "√",
"百度": "y", "alipay": "√",
"字节跳动": "y", "toutiao": "√",
"QQ": "y", "baidu": "√",
"钉钉": "y", "kuaishou": "-",
"快手": "y", "jd": "-",
"飞书": "y", "harmony": "-",
"京东": "y" "qq": "√",
}, "lark": "-"
"快应用": { },
"华为": "y", "quickapp": {
"联盟": "y" "huawei": "√",
}, "union": "√"
"Vue": { }
"vue2": "y", },
"vue3": "y" "uni-app-x": {
"web": {
"safari": "√",
"chrome": "√"
},
"app": {
"android": {
"extVersion": "",
"minVersion": "29"
},
"ios": "√",
"harmony": "√"
},
"mp": {
"weixin": "√"
}
} }
} }
} }
......
## 1.2.17(2025-08-20)
- 修复 右侧箭头类型错误的问题
## 1.2.16(2025-04-14)
- 修复 可触发点击反馈的 uni-list-item 没有hover效果的问题
## 1.2.15(2025-01-08)
- 修复 示例中过期图片地址
## 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 角标显示不正常的问题
<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>
/**
* 这里是 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;
<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 = [false|navigateTo|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>
<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="right" />
</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 === 3) {
const [topPadding, horizontalPadding, bottomPadding] = paddingArr;
this.padding = {
"top": topPadding,
"right": horizontalPadding,
"bottom": bottomPadding,
"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>
<template>
<!-- #ifndef APP-NVUE -->
<view class="uni-list uni-border-top-bottom">
<view v-if="borderTop" 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
},
borderTop: {
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>
<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>
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
}
{
"id": "uni-list",
"displayName": "uni-list 列表",
"version": "1.2.17",
"description": "List 组件 ,帮助使用者快速构建列表。",
"keywords": [
"",
"uni-ui",
"uniui",
"列表",
"",
"list"
],
"repository": "https://github.com/dcloudio/uni-ui",
"engines": {
"HBuilderX": "",
"uni-app": "^4.08",
"uni-app-x": ""
},
"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",
"darkmode": "x",
"i18n": "x",
"widescreen": "x"
},
"uni_modules": {
"dependencies": [
"uni-badge",
"uni-icons"
],
"encrypt": [],
"platforms": {
"cloud": {
"tcb": "x",
"aliyun": "x",
"alipay": "x"
},
"client": {
"uni-app": {
"vue": {
"vue2": "√",
"vue3": "√"
},
"web": {
"safari": "√",
"chrome": "√"
},
"app": {
"vue": "√",
"nvue": "-",
"android": "√",
"ios": "√",
"harmony": "√"
},
"mp": {
"weixin": "√",
"alipay": "√",
"toutiao": "√",
"baidu": "√",
"kuaishou": "-",
"jd": "-",
"harmony": "-",
"qq": "√",
"lark": "-"
},
"quickapp": {
"huawei": "√",
"union": "√"
}
},
"uni-app-x": {
"web": {
"safari": "-",
"chrome": "-"
},
"app": {
"android": "-",
"ios": "-",
"harmony": "-"
},
"mp": {
"weixin": "-"
}
}
}
}
}
}
\ No newline at end of file
## 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)
### [点击查看详细文档](https://uniapp.dcloud.io/component/uniui/uni-indexed-list)
#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839
## 基于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)
\ No newline at end of file
## 1.2.3(2024-04-02)
- 修复 修复在微信小程序下inactiveColor失效bug
## 1.2.2(2024-03-28)
- 修复 在vue2下:style动态绑定导致编译失败的bug
## 1.2.1(2024-03-20)
- 新增 inActiveColor属性,可供配置未激活时的颜色
## 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-segmented-control](https://uniapp.dcloud.io/component/uniui/uni-segmented-control)
## 1.1.0(2021-07-30)
- 组件兼容 vue3,如何创建vue3项目,详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834)
## 1.0.5(2021-05-12)
- 新增 项目示例地址
## 1.0.4(2021-02-05)
- 调整为uni_modules目录规范
<template>
<view :class="[styleType === 'text'?'segmented-control--text' : 'segmented-control--button' ]"
:style="{ borderColor: styleType === 'text' ? '' : activeColor }" class="segmented-control">
<view v-for="(item, index) in values" :class="[styleType === 'text' ? '' : 'segmented-control__item--button',
index === 0 && styleType === 'button' ? 'segmented-control__item--button--first' : '',
index === values.length - 1 && styleType === 'button' ? 'segmented-control__item--button--last':'']" :key="index"
:style="{backgroundColor: index === currentIndex && styleType === 'button' ? activeColor : styleType === 'button' ?inActiveColor:'transparent', borderColor: index === currentIndex && styleType === 'text' || styleType === 'button' ? activeColor : inActiveColor}"
class="segmented-control__item" @click="_onClick(index)">
<view>
<text
:style="{color:index === currentIndex? styleType === 'text'? activeColor: '#fff': styleType === 'text'? '#000': activeColor}"
class="segmented-control__text"
:class="styleType === 'text' && index === currentIndex ? 'segmented-control__item--text': ''">{{ item }}</text>
</view>
</view>
</view>
</template>
<script>
/**
* SegmentedControl 分段器
* @description 用作不同视图的显示
* @tutorial https://ext.dcloud.net.cn/plugin?id=54
* @property {Number} current 当前选中的tab索引值,从0计数
* @property {String} styleType = [button|text] 分段器样式类型
* @value button 按钮类型
* @value text 文字类型
* @property {String} activeColor 选中的标签背景色与边框颜色
* @property {String} inActiveColor 未选中的标签背景色与边框颜色
* @property {Array} values 选项数组
* @event {Function} clickItem 组件触发点击事件时触发,e={currentIndex}
*/
export default {
name: 'UniSegmentedControl',
emits: ['clickItem'],
props: {
current: {
type: Number,
default: 0
},
values: {
type: Array,
default () {
return []
}
},
activeColor: {
type: String,
default: '#2979FF'
},
inActiveColor: {
type: String,
default: 'transparent'
},
styleType: {
type: String,
default: 'button'
}
},
data() {
return {
currentIndex: 0
}
},
watch: {
current(val) {
if (val !== this.currentIndex) {
this.currentIndex = val
}
}
},
computed: {},
created() {
this.currentIndex = this.current
},
methods: {
_onClick(index) {
if (this.currentIndex !== index) {
this.currentIndex = index
this.$emit('clickItem', {
currentIndex: index
})
}
}
}
}
</script>
<style lang="scss" scoped>
.segmented-control {
/* #ifndef APP-NVUE */
display: flex;
box-sizing: border-box;
/* #endif */
flex-direction: row;
height: 36px;
overflow: hidden;
/* #ifdef H5 */
cursor: pointer;
/* #endif */
}
.segmented-control__item {
/* #ifndef APP-NVUE */
display: inline-flex;
box-sizing: border-box;
/* #endif */
position: relative;
flex: 1;
justify-content: center;
align-items: center;
}
.segmented-control__item--button {
border-style: solid;
border-top-width: 1px;
border-bottom-width: 1px;
border-right-width: 1px;
border-left-width: 0;
}
.segmented-control__item--button--first {
border-left-width: 1px;
border-top-left-radius: 5px;
border-bottom-left-radius: 5px;
}
.segmented-control__item--button--last {
border-top-right-radius: 5px;
border-bottom-right-radius: 5px;
}
.segmented-control__item--text {
border-bottom-style: solid;
border-bottom-width: 2px;
padding: 6px 0;
}
.segmented-control__text {
font-size: 14px;
line-height: 20px;
text-align: center;
}
</style>
{
"id": "uni-segmented-control",
"displayName": "uni-segmented-control 分段器",
"version": "1.2.3",
"description": "分段器由至少 2 个分段控件组成,用作不同视图的显示",
"keywords": [
"uni-ui",
"uniui",
"分段器",
"segement",
"顶部选择"
],
"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",
"alipay": "n"
},
"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"
}
}
}
}
}
\ No newline at end of file
## SegmentedControl 分段器
> **组件名:uni-segmented-control**
> 代码块: `uSegmentedControl`
用作不同视图的显示
### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-segmented-control)
#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839
...@@ -39,6 +39,7 @@ export function initJssdkShare(callback, url) { ...@@ -39,6 +39,7 @@ export function initJssdkShare(callback, url) {
// 设置微信分享内容(不自动覆盖,需手动调用) // 设置微信分享内容(不自动覆盖,需手动调用)
export function setWechatShare(data) { export function setWechatShare(data) {
console.log('分享data',data);
if (!jWeixin) { if (!jWeixin) {
console.error('微信SDK未初始化'); console.error('微信SDK未初始化');
return; return;
......
// import { apiURL } from "../environments/environment";
// /**
// * 优化后的图片上传方法(支持压缩 + 进度条)
// * @param {Object} params - 上传参数(同原版)
// * @returns {Promise} 返回上传结果
// */
// export function CommonUpload(params) {
// return new Promise((resolve, reject) => {
// // 1️⃣ 检查权限(仅APP端需要)
// // #ifdef APP-PLUS
// const imageCamera = uni.getStorageSync('imageCamera');
// if (!imageCamera || imageCamera !== '1') {
// uni.showModal({
// title: '权限说明',
// content: '我们需要访问您的相机和相册,以便您拍摄或上传图片。',
// confirmText: '同意',
// cancelText: '拒绝',
// success: (res) => {
// if (res.confirm) {
// uni.setStorageSync('imageCamera', '1');
// startUpload(params, resolve, reject); // 同意后开始上传
// } else {
// reject(new Error('用户拒绝了权限'));
// }
// }
// });
// } else {
// startUpload(params, resolve, reject); // 已有权限,直接上传
// }
// // #endif
// // 2️⃣ H5 端直接上传(无需权限)
// // #ifdef H5
// startUpload(params, resolve, reject);
// // #endif
// });
// }
// /**
// * 核心上传逻辑(选择图片 → 压缩 → 上传)
// * @param {Object} params - 上传参数
// * @param {Function} resolve - Promise resolve
// * @param {Function} reject - Promise reject
// */
// function startUpload(params, resolve, reject) {
// uni.chooseImage({
// count: 1,
// sizeType: ['compressed'],
// sourceType: ['album', 'camera'],
// success: (chooseRes) => {
// const tempFilePath = chooseRes.tempFilePaths[0];
// uni.showLoading({ title: '处理中...', mask: true });
// // #ifdef MP-WEIXIN
// uni.compressImage({
// src: tempFilePath,
// quality: 70,
// success: (compressRes) => {
// uploadFile(compressRes.tempFilePath, params, resolve, reject);
// },
// fail: (err) => {
// uni.hideLoading();
// reject(new Error('压缩失败: ' + JSON.stringify(err)));
// },
// });
// // #endif
// // #ifdef H5 || APP-PLUS
// uploadFile(tempFilePath, params, resolve, reject); // 或者用 canvas 压缩
// // #endif
// },
// fail: (err) => {
// reject(new Error('选择图片失败: ' + JSON.stringify(err)));
// },
// });
// }
// /**
// * 执行上传操作(带进度条)
// * @param {String} filePath - 压缩后的图片路径
// * @param {Object} params - 上传参数
// * @param {Function} resolve - Promise resolve
// * @param {Function} reject - Promise reject
// */
// function uploadFile(filePath, params, resolve, reject) {
// // 1. 替换原 loading 提示
// uni.showLoading({ title: '上传中...', mask: true });
// // 2. 创建上传任务(可监听进度)
// const uploadTask = uni.uploadFile({
// url: `${apiURL}/file/upload`,
// filePath: filePath,
// name: 'file',
// formData: { requestVO: JSON.stringify(params) },
// header: { 'X-Authorization': uni.getStorageSync('uni-token') || '' },
// success: (res) => {
// uni.hideLoading();
// try {
// const data = JSON.parse(res.data);
// if (data.success) {
// resolve(data); // 上传成功
// } else {
// reject(new Error(data.message || '上传失败'));
// }
// } catch (e) {
// reject(new Error('解析服务器响应失败'));
// }
// },
// fail: (err) => {
// uni.hideLoading();
// reject(new Error('上传失败: ' + JSON.stringify(err)));
// }
// });
// // 3. 监听上传进度(可选,适合大文件)
// uploadTask.onProgressUpdate((progress) => {
// console.log(`上传进度: ${progress.progress}%`);
// // 可以在这里更新 UI,比如:
// // uni.showToast({ title: `上传中 ${progress.progress}%`, icon: 'none' });
// });
// }
import request from "./request"; import request from "./request";
import authorizeUtils from "./authorizeUtils"; import authorizeUtils from "./authorizeUtils";
import { apiURL } from "../environments/environment"; import { apiURL } from "../environments/environment";
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment