This commit is contained in:
shijing 2022-07-28 15:17:37 +08:00
parent a4a1f35657
commit 9af8ccf328
111 changed files with 17507 additions and 534 deletions

14
App.vue
View File

@ -15,7 +15,7 @@
*/
//var that=this
//
uni.showLoading({
/* uni.showLoading({
title: '微信自动登录中...',
mask: true
})
@ -54,7 +54,17 @@
})
}
});
*/
let accessToken = this.$store.state.vuex_token;
if(accessToken){
uni.reLaunch({
url:'/pages/home/home_'
})
}else{
uni.reLaunch({
url:'/pages/login/login_'
})
}
},
}
</script>

View File

@ -17,6 +17,7 @@ const install = (Vue, vm) => {
let codeLogin = (data = {}) => vm.$u.post('/auth/login_sms_code/', data); //短信验证码登录
let login = (data = {}) => vm.$u.post('auth/token/', data); //账户密码登录
let loginOut = () => vm.$u.post('/auth/logout/'); //账户密码退出
// 将各个定义的接口名称统一放进对象挂载到vm.$u.api(因为vm就是this也即this.$u.api)下
let wxmplogin = (data = {}) => vm.$u.post('auth/login_wxmp/', data); //微信登录
@ -25,14 +26,39 @@ const install = (Vue, vm) => {
let unbindmp = (data = {}) => vm.$u.post('/system/user/unbind_wxmp/', data); //微信小程序解绑
let getDickey = (params={})=>vm.$u.get('/system/dict/', params);//查询字典
let getTickets = (params={})=>vm.$u.get('/wf/ticket/', params);//工单查询/wf/ticket/{id}/
let getTicketItem = (id)=>vm.$u.get(`/wf/ticket/${id}/`);//工单详情
let getTicketTransitions = (id)=>vm.$u.get(`/wf/ticket/${id}/transitions/`);//工单按钮查询
let getVisit = (id)=>vm.$u.get(`/vm/visit/${id}/`);//visit查询
let getRpj = (id)=>vm.$u.get(`/rpm/rpj/${id}`);//rpj查询
let getOpreation = (id)=>vm.$u.get(`/opm/operation/${id}/`);//rpj查询
let getOpl = (id)=>vm.$u.get(`/opm/opl/${id}/`);//opl作业许可证查询
vm.$u.api = {getUserInfo,
getCode,
codeLogin,
login,
loginOut,
wxmplogin,
bindmp,
unbindmp,
getDickey,
getTickets,
getTicketItem,
getTicketTransitions,
getVisit,
getRpj,
getOpreation,
getOpl
};
}

View File

@ -0,0 +1,203 @@
<template>
<view>
<view class="item" @click="goIntoDetail(approvalObj)">
<view v-if="approvalObj !== undefined && approvalObj !== null && approvalObj !== ''" class="item-content">
<!-- <view class="hander-img">
<image src="../../assets/common/avatar.png" mode="" class="img"></image>
</view> -->
<view class="apply-info">
<view v-if="approvalObj.itemName !== undefined && approvalObj.itemName !== null && approvalObj.itemName !== ''" class="apply-title">
<text class="apply-title-text">{{approvalObj.itemName}}</text>
<!-- <text class="apply-date">{{approvalObj.submissionTime}}</text> -->
</view>
<view v-if="approvalObj.applicationDeptName !== undefined && approvalObj.applicationDeptName !== null && approvalObj.applicationDeptName !== ''" class="">
<text>所属模块{{approvalObj.menuName}} </text>
</view>
<view v-if="approvalObj.submissionTime !== undefined && approvalObj.submissionTime !== null && approvalObj.submissionTime !== ''" class="">
<text>提交时间{{approvalObj.submissionTime}}</text>
</view>
<view v-if="approvalObj.applicantName !== undefined && approvalObj.applicantName !== null && approvalObj.applicantName !== ''" class="">
<text>申请人{{approvalObj.applicantName}}</text>
</view>
<view v-if="approvalObj.applicationDeptName !== undefined && approvalObj.applicationDeptName !== null && approvalObj.applicationDeptName !== ''" class="">
<text>所属部门{{approvalObj.applicationDeptName}} </text>
</view>
<!-- <view class="">
<text>审核状态{{approvalObj.eventStatusValue}}</text>
</view> -->
</view>
</view>
<view class="line"></view>
<view v-if="approvalObj !== undefined && approvalObj !== null && approvalObj !== ''" class="btns" >
<template v-if="approvalObj.eventStatus==3">
<view class="left">
<text>退回</text>
</view>
<view class="right">
<text>审批</text>
</view>
</template>
<view style="display: flex;justify-content: center;align-items: center;" class="shenhe-status tongyi" v-if="approvalObj.eventStatus==1">
<image class="" src="../../static/profile/my_apply/tongguo.png" mode=""></image>
<text>审核通过</text>
</view>
<view style="display: flex;justify-content: center;align-items: center;" class="shenhe-status tuihui" v-if="approvalObj.eventStatus==0">
<image class="" src="../../static/profile/my_apply/return.png" mode=""></image>
<text>已退回</text>
</view>
<view style="display: flex;justify-content: center;align-items: center;" class="shenhe-status zuofei" v-if="approvalObj.eventStatus==2">
<image class="" src="../../static/profile/my_apply/zuofei.png" mode=""></image>
<text>已作废</text>
</view>
</view>
</view>
</view>
</view>
</template>
<script>
import { routeArray } from '../../utils/correspondingRoute.js';
export default {
data() {
return {
}
},
props:{
approvalObj: {
type: Object,
default: null
},
},
methods: {
goIntoDetail(val){
const routeObj = routeArray.find(item=>{
return item.pcRoute == val.menuID;
})
if (routeObj !== undefined && routeObj !== null && routeObj !== "") {
// if(val.eventStatus != 0 && val.eventStatus != 2){
let eventStatus = val.eventStatus;
if(val.newEventStatus){
eventStatus = val.newEventStatus;
}
const params = `?eventStatus=${eventStatus}&execId=${val.execId}&pkId=${val.pkId}&itemId=${val.itemId}`;
uni.navigateTo({
url: routeObj.appDetail + params,
})
// }
}else {
uni.showToast({
title: "路由异常, 无法跳转, 请检查correspondingRoute.js中是否配置该详情路由",
icon: "none"
})
}
// this.$emit('goIntoDetail')
}
}
}
</script>
<style scoped>
.line {
width: 660rpx;
height: 1rpx;
background-color: #eeeeee;
margin: 0 auto;
}
.item {
background-color: #ffffff;
}
.item .item-content {
display: flex;
padding: 23rpx 20rpx;
}
.item .hander-img {
width: 55rpx;
height: 55rpx;
border-radius: 50%;
overflow: hidden;
}
.item .hander-img image{
width: 100%;
height: 100%;
}
.item .apply-info {
margin-left: 15rpx;
font-family: PingFang-SC-Medium;
font-size: 28rpx;
line-height: 50rpx;
letter-spacing: -2rpx;
color: #5b5b5b;
flex-grow: 1
}
.apply-title{
display: flex;
justify-content: space-between;
}
.item .apply-info .apply-title-text {
font-size: 30rpx;
letter-spacing: -2rpx;
color: #3d3d3d;
width: 400rpx;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.item .apply-info .apply-date{
font-family: PingFang-SC-Regular;
font-size: 24rpx;
letter-spacing: 0rpx;
color: #ababab;
}
.btns {
height: 83rpx;
display: flex;
text-align: center;
align-items: center;
font-size: 28rpx;
font-family: PingFang-SC-Medium;
overflow: hidden;
}
.btns view {
flex-grow: 1;
}
.btns .left {
color: #ea4871;
position: relative;
}
.btns .left::after {
content: "";
width: 1rpx;
height: 83rpx;
background-color: #eeeeee;
position: absolute;
top: -18rpx;
right: 0rpx;
}
.btns .right {
color: #34af27;
}
.btns .tongyi {
color: #34af27!important;
}
.btns .tuihui {
color: #ea4871!important;
}
.btns .zuofei {
color: #565656;
}
.shenhe-status image{
width: 26rpx;
height: 26rpx;
margin-right: 10rpx;
vertical-align: middle;
}
</style>

View File

@ -0,0 +1,549 @@
<template>
<view class="custom-banner">
<view class="tabbar-title">
<view class="search-body">
<image class="left-img" src="../../static/project_manegment/fangdajing.png" mode=""></image>
<input class="search-input" type="text" v-model="itemName" placeholder="请输入事项名称" />
<view class="right-btn" @click="caseSearch">
搜索
</view>
</view>
<!-- <view class="right-pick" @click="showDrawer">
<image class="right-img" src="../../static/project_manegment/shaixuan.png" mode=""></image>
<text>筛选</text>
</view> -->
</view>
<u-popup v-model="show" mode="right" :zoom='true' width="600rpx" :mask='true' :closeable='false'
:safe-area-inset-bottom='true'>
<scroll-view style="height: 100%;padding-top:20rpx" scroll-y="true">
<view class="hetong-drawer">
<view class="top-search">
<view class="top-title">
<text>筛选</text>
<uni-icons class="close-btn" @click="closeDrawer" type="closeempty" size="25" color="#d7d7d7">
</uni-icons>
</view>
<!-- 合同状态 -->
<view class="hetong-status">
<view class="search-title">
合同状态
</view>
<view class="search-content">
<view :class="{'search-content-item-status':true,'active':eventStatus==''}"
@click="getCurrentStatus()">
全部
</view>
<view :class="{'search-content-item-status':true,'active':eventStatus=='3'}"
@click="getCurrentStatus('3')">
审核中
</view>
<view :class="{'search-content-item-status':true,'active':eventStatus=='0'}"
@click="getCurrentStatus('0')">
已退回
</view>
<view :class="{'search-content-item-status':true,'active': eventStatus=='1'}"
@click="getCurrentStatus('1')">
审核通过
</view>
<view :class="{'search-content-item-status':true,'active': eventStatus=='2'}"
@click="getCurrentStatus('2')">
已作废
</view>
<view :class="{'search-content-item-status':true,'active': eventStatus=='4'}"
@click="getCurrentStatus('4')">
未提交
</view>
</view>
</view>
<!-- 提交时间 -->
<!-- <view class="hetong-time">
<view class="search-title">
提交时间
</view>
<view class="search-content-time">
<view class="search-content-item-time">
<uni-datetime-picker type="daterange" :value="beginTime" :border="false"
:clear-icon="false" @change="changeBeginTime" />
</view>
</view>
</view>
--><!-- 所属模块 -->
<!-- <view class="hetong-type">
<view class="search-title">
所属模块
</view>
<view class="search-content-type">
<view @click="changeModule(-1)" class="search-content-item-type">
<text :class="{'active': currentId==-1}">全部</text>
</view>
<view v-for="(val,index) in moduleMenu" :key="val.id" @click="changeModule(index)"
class="search-content-item-type">
<text :class="{'active': currentId==val.id}">{{val.label}}</text>
</view>
</view>
</view>
-->
<view class="empty-view">
</view>
</view>
<view class="bottom-btn" @click="resetSearch">
<view class="reset">
重置
</view>
<view class="queding" @click="quedingSearch">
确定
</view>
</view>
</view>
</scroll-view>
</u-popup>
</view>
</template>
<script>
export default {
name: "customTitleBanner",
data() {
return {
itemName: "",
eventStatus: "",
submissionTimeFrom: "", //
submissionTimeFromTo: "", //
moduleId: "",
moduleMenu: [],
show:false,
beginTime:'',
currentId: -1,
}
},
props: {
obj:{
type: Object,
default:null
}
},
created() {
this._getModuleMenu()
},
// mounted() {
// this.getSystemInfo()
// },
methods: {
// getSystemInfo(){
// let _this = this;
// uni.getSystemInfo({
// success(res){
// let statusBarHeight = res.statusBarHeight;
// }
// })
// },
caseSearch() {
this.$emit("caseSearch", this.itemName)
},
handleModuleMenus(arr) {
for (let val of arr) {
this.moduleMenu.push({
id: val.id,
label: val.label,
children:val.children || [],
})
if (val.children) {
this.handleModuleMenus(val.children)
}
}
},
/* 查询所属模块 */
_getModuleMenu() {
getModuleMenu().then(res => {
if (res.statusCode === 200) {
this.moduleMenu = [];
let moduleMenus = res.data.data;
this.handleModuleMenus(moduleMenus)
} else {
uni.showToast({
title: res.data.message,
icon: 'none'
})
}
}).catch(err => {
uni.showToast({
title: '网络异常, 请求失败',
icon: 'none'
})
})
},
_handleData(arr){
for(let val of arr){
this.moduleId +=val.id +",";
if(val.children && val.children.length> 0){
this._handleData(val.children)
}
}
},
changeModule(index) {
let val = this.moduleMenu[index];
if (index!==-1) {
this.currentId = val.id;
this.moduleId = val.id +",";
if(val.children && val.children.length> 0){
this._handleData(val.children)
}
this.moduleId = this.moduleId.slice(0,this.moduleId.length-1);
} else {
this.moduleId = "";
this.currentId = -1;
}
},
/* 打开弹框 */
showDrawer() {
this.eventStatus = this.obj.eventStatus;
this.moduleId = this.obj.moduleId;
this.currentId = this.obj.moduleId;
if(this.obj.moduleId && this.obj.moduleId.indexOf(",")!==-1){
this.currentId = this.obj.moduleId.split(",")[0];
}
if(this.moduleId===""){
this.currentId = -1;
}
this.submissionTimeFrom = this.obj.submissionTimeFrom;
this.submissionTimeFromTo = this.obj.submissionTimeFromTo;
// this.$refs.showRight.open();
this.show = true;
},
closeDrawer() {
this.show = false;
// this.$refs.showRight.close();
},
/* 重置 */
resetSearch() {
this.eventStatus = "";
this.moduleId = "";
this.currentId = -1;
this.submissionTimeFrom = "";
this.submissionTimeFromTo = "";
},
/* 确认 */
quedingSearch() {
let queryData = {};
if (this.eventStatus) {
queryData.eventStatus = this.eventStatus;
}
if (this.moduleId) {
queryData.moduleId = this.moduleId;
}
if (this.submissionTimeFrom && this.submissionTimeFromTo) {
queryData.submissionTimeFrom = this.submissionTimeFrom;
queryData.submissionTimeFromTo = this.submissionTimeFromTo;
}
this.$emit('quedingSearch', queryData);
this.closeDrawer();
},
/* 处理合同查询参数 */
getCurrentStatus(status) {
if (status) {
this.eventStatus = status;
} else {
this.eventStatus = "";
}
},
changeBeginTime(time) {
this.submissionTimeFrom = time[0] + ' 00:00:00';
this.submissionTimeFromTo = time[1] + ' 00:00:00';
},
}
}
</script>
<style scoped>
.search-body {
width: 560rpx;
height: 78rpx;
background-color: #ffffff;
border-radius: 39rpx;
border: 1rpx solid #EEEEEE;
padding: 13rpx;
padding-left: 20rpx;
box-sizing: border-box;
display: flex;
align-items: center;
}
.search-body .search-input {
height: 100%;
flex: 1;
padding-left: 12rpx;
font-size: 28rpx;
display: table-cell;
vertical-align: middle;
box-sizing: border-box;
}
.left-img {
width: 24rpx;
height: 24rpx;
}
.right-img {
width: 32rpx;
height: 31rpx;
vertical-align: middle;
margin-right: 9rpx;
}
.right-btn {
width: 110rpx;
height: 58rpx;
line-height: 58rpx;
background-image: linear-gradient(0deg,
#2da0f3 0%,
#54bcff 100%);
border-radius: 29rpx;
font-size: 28rpx;
color: #ffffff;
text-align: center;
}
>>>.uni-navbar-btn-text text {
font-size: 32rpx !important;
}
.tabbar-title {
background-color: #FFFFFF;
height: 100rpx;
display: flex;
justify-content: space-between;
font-size: 32rpx;
line-height: 74rpx;
color: #505050;
padding-top: 27rpx;
padding-left: 27rpx;
padding-right: 27rpx;
}
.text-title {
position: relative;
}
.active.text-title::after {
content: "";
display: block;
width: 60%;
height: 6rpx;
background-color: #215ece;
border-radius: 6rpx;
position: absolute;
bottom: 20rpx;
left: 50%;
transform: translateX(-50%);
}
/* 筛选框 */
.right-drawer {
position: relative;
}
>>>.uni-drawer__content {
width: 600rpx !important;
}
/* >>>.uni-drawer {
top: 290rpx!important;
} */
.top-search {
padding: 35rpx;
}
.top-title {
display: flex;
justify-content: space-between;
}
.top-title text {
color: #333333;
}
.close-btn>>>.uni-icons {
width: 23rpx;
height: 23rpx;
}
.search-title {
font-size: 28rpx;
color: #676767;
padding-bottom: 29rpx;
}
.search-content {
display: flex;
justify-content: flex-start;
flex-wrap: wrap;
}
/* 合同状态 */
.hetong-status {
padding-top: 30rpx;
}
.search-content-item-status {
width: 130rpx;
height: 48rpx;
background-color: #f7f7f7;
color: #9e9e9e;
border-radius: 24rpx;
font-size: 24rpx;
line-height: 48rpx;
text-align: center;
margin-right: 22rpx;
margin-bottom: 25rpx;
}
.search-content-item-status.active {
background-image: linear-gradient(#2c6fd9,
#2c6fd9),
linear-gradient(#029ef3,
#029ef3);
background-blend-mode: normal,
normal;
color: #ffffff;
}
/* 合同时间 */
.hetong-time {
padding-top: 37rpx;
}
.search-content-time {
display: flex;
justify-content: flex-start;
align-items: center;
}
.search-content-time>>>.uni-date-x {
height: 54rpx;
background-color: #f7f7f7;
border-radius: 27rpx;
font-size: 24rpx;
color: #797979;
}
.search-content-item-time>>>uni-icons {
display: none;
}
.center-line {
width: 36rpx;
height: 1rpx;
background-color: #b3b3b3;
margin: 0 12rpx;
}
/* 合同类型 */
.hetong-type {
padding-top: 50rpx;
}
.search-content-type {
display: flex;
flex-wrap: wrap;
}
.search-content-item-type {
margin-right: 20rpx;
margin-bottom: 20rpx;
}
.search-content-item-type text {
min-width: 130rpx;
display: block;
border-radius: 24rpx;
font-size: 24rpx;
line-height: 48rpx;
background-color: #f7f7f7;
color: #9e9e9e;
height: 48rpx;
box-sizing: border-box;
text-align: center;
padding: 0 20rpx;
}
.search-content-item-type text.active {
background-image: linear-gradient(#2c6fd9,
#2c6fd9),
linear-gradient(#029ef3,
#029ef3);
background-blend-mode: normal,
normal;
color: #ffffff;
}
.bottom-btn {
display: flex;
height: 88rpx;
position: fixed;
left: 0;
right: 0;
bottom: 0;
}
.bottom-btn view {
flex: 1;
font-size: 32rpx;
line-height: 88rpx;
text-align: center;
}
.reset {
background-color: #f2f2f2;
color: #888888;
}
.queding {
background-image: linear-gradient(#2c6fd9,
#2c6fd9),
linear-gradient(#029ef3,
#029ef3);
background-blend-mode: normal, normal;
color: #ffffff;
}
.empty-view {
height: 100rpx;
}
</style>

View File

@ -10,4 +10,4 @@
"UI框架",
"uni-app"
]
}
}

View File

@ -10,71 +10,141 @@
// "query": "uuid=c4bba940-f69e-11ea-a419-6bafda9d095e&__id__=1" //onLoad
// }]
// },
"pages": [
{
"path" : "pages/login/login_password",
"style" :
{
"navigationBarTitleText": "密码登录",
"enablePullDownRefresh": false
}
"pages": [{
"path": "pages/login/login_",
"style": {
"navigationBarTitleText": "密码登录",
"enablePullDownRefresh": false
}
},
{
"path" : "pages/login/login",
"style" :
{
"navigationBarTitleText": "验证码登录",
"enablePullDownRefresh": false
}
"path": "pages/login/login",
"style": {
"navigationBarTitleText": "验证码登录",
"enablePullDownRefresh": false
}
},
{
"path" : "pages/home/home",
"style" :
{
"navigationBarTitleText": "曲阳金隅智慧安全",
"enablePullDownRefresh": false
}
"path": "pages/home/home_",
"style": {
"navigationBarTitleText": "主页",
"enablePullDownRefresh": false
}
},
{
"path" : "pages/my/my",
"style" :
{
"navigationBarTitleText": "个人中心",
"enablePullDownRefresh": false
}
}
],
{
"path": "pages/home/list/ticket",
"style": {
"navigationBarTitleText": "代办事件",
"navigationStyle": "custom"
}
},
{
"path": "pages/home/list/warning",
"style": {
"navigationBarTitleText": "实时报警",
"navigationStyle": "custom",
"enablePullDownRefresh": false
}
},
{
"path": "pages/home/detail/ticketHandle",
"style": {
"navigationBarTitleText": "工作流审批",
"navigationStyle": "custom",
"enablePullDownRefresh": false
}
},
{
"path": "pages/home/detail/addNode",
"style": {
"navigationBarTitleText": "加签",
"navigationStyle": "custom",
"enablePullDownRefresh": false
}
},
{
"path": "pages/home/detail/warningHandle",
"style": {
"navigationBarTitleText": "报警处理",
"navigationStyle": "custom",
"enablePullDownRefresh": false
}
},
{
"path": "pages/workSpace/workSpace",
"style": {
"navigationBarTitleText": "工作台",
"enablePullDownRefresh": false
}
},
{
"path": "pages/workSpace/newWork/work",
"style": {
"navigationBarTitleText": "作业管理",
"navigationStyle": "custom",
"enablePullDownRefresh": false
}
},
{
"path": "pages/workSpace/newWork/relevant",
"style": {
"navigationBarTitleText": "入厂项目",
"navigationStyle": "custom",
"enablePullDownRefresh": false
}
},
{
"path": "pages/workSpace/newWork/visit",
"style": {
"navigationBarTitleText": "来访项目",
"navigationStyle": "custom",
"enablePullDownRefresh": false
}
},
{
"path": "pages/my/my",
"style": {
"navigationBarTitleText": "个人中心",
"enablePullDownRefresh": false
}
},
{
"path": "pages/my/myInfo",
"style": {
"navigationBarTitleText": "个人信息",
"navigationStyle": "custom",
"enablePullDownRefresh": false
}
}
],
"globalStyle": {
"navigationBarTextStyle": "black",
"navigationBarTitleText": "曲阳金隅智慧安全",
"navigationBarBackgroundColor": "#F8F8F8",
// "navigationStyle": "custom",
"backgroundColor": "#F8F8F8"
},
"tabBar": {
"color": "#909399",
"selectedColor": "#909399",
"backgroundColor": "#FFFFFF",
"color": "#a6a6a6",
"selectedColor": "#2c6fd9",
"borderStyle": "black",
"backgroundColor": "#ffffff",
"list": [{
"pagePath": "pages/home/home",
"iconPath": "static/common/home.png",
"selectedIconPath": "static/common/homec.png",
"pagePath": "pages/home/home_",
"iconPath": "static/tabbar/shouye.png",
"selectedIconPath": "static/tabbar/shouye-select.png",
"text": "主页"
},
/* {
"pagePath": "pages/vod/video",
"iconPath": "static/common/play.png",
"selectedIconPath": "static/common/playc.png",
"text": "点播"
}, */
{
"pagePath": "pages/workSpace/workSpace",
"iconPath": "static/tabbar/gongzuotai.png",
"selectedIconPath": "static/tabbar/gongzuotai-select.png",
"text": "工作台"
},
{
"pagePath": "pages/my/my",
"iconPath": "static/common/me.png",
"selectedIconPath": "static/common/mec.png",
"iconPath": "static/tabbar/wode.png",
"selectedIconPath": "static/tabbar/wode-select.png",
"text": "个人中心"
}
]

View File

@ -0,0 +1,41 @@
<template>
<view class="ticket-handle">
<uni-nav-bar @clickLeft="goBack()" class="nav-bar" height="110rpx" leftWidth="200rpx" leftText="加签"
leftIcon="left" border backgroundColor="#2cade8" color="#fff" fixed statusBar shadow></uni-nav-bar>
<view class="ticket-info">
<view class="form-item" style="height: 300rpx;">
<view class="form-left-text">
<text class="star">*</text>
<text>加签原因</text>
</view>
<textarea class="apply-reason-text" v-model="form.name" maxlength="250" placeholder="请输入" />
</view>
<view class="btn" style="display: flex;justify-content: space-between;">
<button class="handleBtn" type="primary" @click="addNode">提交</button>
</view>
</view>
</view>
</template>
<script>
</script>
<style>
.ticket-handle {
background-color: #f3fbff;
padding-bottom: 227rpx;
}
.ticket-info {
width: 720rpx;
margin: 0 auto;
background-color: #FFFFFF;
border-radius: 10rpx;
padding: 25rpx 32rpx;
box-sizing: border-box;
margin-top: 24rpx;
}
.fixed-assets-list .ticket-info {
padding-top: 0rpx;
}
</style>

View File

@ -0,0 +1,948 @@
<template>
<view class="ticket-handle">
<uni-nav-bar @clickLeft="goBack()" class="nav-bar" height="110rpx" leftWidth="200rpx" leftText="工单审批"
leftIcon="left" border backgroundColor="#2cade8" color="#fff" fixed statusBar shadow></uni-nav-bar>
<block v-if="cateType==='visit'">
<view class="ticket-info">
<view class="form-item border-bottom">
<view class="form-left">
<text class="form-left-text">工单流水号</text>
</view>
<view class="form-right">
<input type="text" v-model="ticketDetail.sn" maxlength="50" placeholder="请输入" />
</view>
</view>
</view>
<view class="ticket-info">
<view class="form-content ">
<view class="form-item border-bottom">
<view class="form-left">
<text class="form-left-text">作业名称</text>
</view>
<view class="form-right">
<input type="text" v-model="oplDetail.name" maxlength="50" placeholder="请输入" />
</view>
</view>
<view class="form-item border-bottom">
<view class="form-left">
<text class="form-left-text">开始时间</text>
</view>
<view class="form-right form-date">
<picker mode="date" :value="formData.start_time" @change="bindStartDateChange">
<view class="uni-input">{{formData.start_time}}</view>
</picker>
</view>
</view>
<view class="form-item border-bottom">
<view class="form-left">
<text class="form-left-text">结束时间</text>
</view>
<view class="form-right form-date">
<picker mode="date" :value="formData.end_time" @change="bindEndDateChange">
<view class="uni-input">{{formData.end_time}}</view>
</picker>
</view>
</view>
<view class="form-item border-bottom">
<view class="form-left">
<text class="form-left-text">状态</text>
</view>
<view class="form-right">
<input type="text" v-model="formData.place" maxlength="50" placeholder="请输入" />
</view>
</view>
<view class="form-item border-bottom">
<view class="form-left">
<text class="form-left-text">作业区域</text>
</view>
<view class="form-right">
<input type="text" v-model="formData.place" maxlength="50" placeholder="请输入" />
</view>
</view>
<view class="form-item border-bottom">
<view class="form-left">
<text class="form-left-text">业务部门</text>
</view>
<view class="form-right">
<input type="text" v-model="formData.place" maxlength="50" placeholder="请输入" />
</view>
</view>
<view class="form-item border-bottom">
<view class="form-left">
<text class="form-left-text">部门协调员</text>
</view>
<view class="form-right">
<input type="text" v-model="formData.place" maxlength="50" placeholder="请输入" />
</view>
</view>
<view class="form-item border-bottom">
<view class="form-left">
<text class="form-left-text">属地部门</text>
</view>
<view class="form-right">
<input type="text" v-model="formData.place" maxlength="50" placeholder="请输入" />
</view>
</view>
<view class="form-item border-bottom">
<view class="form-left-text">
<text class="star">*</text>
<text>审批意见</text>
</view>
<textarea class="apply-reason-text" v-model="formData.name" maxlength="250" placeholder="请输入" />
</view>
<view class="btn">
<button type="default" class="save-btn">同意</button>
</view>
</view>
</view>
</block>
<block v-if="cateType==='rparty'">
<view class="ticket-info">
<view class="form-item border-bottom">
<view class="form-left">
<text class="form-left-text">工单流水号</text>
</view>
<view class="form-right">
<input type="text" v-model="ticketDetail.sn" maxlength="50" placeholder="请输入" />
</view>
</view>
</view>
<view class="ticket-info">
<view class="form-content ">
<view class="form-item border-bottom">
<view class="form-left">
<text class="form-left-text">作业名称</text>
</view>
<view class="form-right">
<input type="text" v-model="oplDetail.name" maxlength="50" placeholder="请输入" />
</view>
</view>
<view class="form-item border-bottom">
<view class="form-left">
<text class="form-left-text">开始时间</text>
</view>
<view class="form-right form-date">
<picker mode="date" :value="formData.start_time" @change="bindStartDateChange">
<view class="uni-input">{{formData.start_time}}</view>
</picker>
</view>
</view>
<view class="form-item border-bottom">
<view class="form-left">
<text class="form-left-text">结束时间</text>
</view>
<view class="form-right form-date">
<picker mode="date" :value="formData.end_time" @change="bindEndDateChange">
<view class="uni-input">{{formData.end_time}}</view>
</picker>
</view>
</view>
<view class="form-item border-bottom">
<view class="form-left">
<text class="form-left-text">状态</text>
</view>
<view class="form-right">
<input type="text" v-model="formData.place" maxlength="50" placeholder="请输入" />
</view>
</view>
<view class="form-item border-bottom">
<view class="form-left">
<text class="form-left-text">作业区域</text>
</view>
<view class="form-right">
<input type="text" v-model="formData.place" maxlength="50" placeholder="请输入" />
</view>
</view>
<view class="form-item border-bottom">
<view class="form-left">
<text class="form-left-text">业务部门</text>
</view>
<view class="form-right">
<input type="text" v-model="formData.place" maxlength="50" placeholder="请输入" />
</view>
</view>
<view class="form-item border-bottom">
<view class="form-left">
<text class="form-left-text">部门协调员</text>
</view>
<view class="form-right">
<input type="text" v-model="formData.place" maxlength="50" placeholder="请输入" />
</view>
</view>
<view class="form-item border-bottom">
<view class="form-left">
<text class="form-left-text">属地部门</text>
</view>
<view class="form-right">
<input type="text" v-model="formData.place" maxlength="50" placeholder="请输入" />
</view>
</view>
<view class="form-item border-bottom">
<view class="form-left-text">
<text class="star">*</text>
<text>审批意见</text>
</view>
<textarea class="apply-reason-text" v-model="formData.name" maxlength="250" placeholder="请输入" />
</view>
<view class="btn">
<button type="default" class="save-btn">同意</button>
</view>
</view>
</view>
</block>
<block v-else>
<view class="ticket-info">
<view class="form-item border-bottom">
<view class="form-left">
<text class="form-left-text">工单流水号</text>
</view>
<view class="form-right">
<view>{{ticketDetail.sn}}</view>
</view>
</view>
<view class="form-item border-bottom">
<view class="form-left">
<text class="form-left-text">工单名称</text>
</view>
<view class="form-right">
<view>{{oplDetail.ticket_.title}}</view>
</view>
</view>
<view class="form-item">
<view class="form-left">
<text class="form-left-text">工单状态</text>
</view>
<view class="form-right">
<view>{{oplDetail.ticket_.state_.name}}</view>
</view>
</view>
</view>
<view class="ticket-info">
<view class="form-item border-bottom">
<view class="form-left">
<text class="form-left-text">作业名称</text>
</view>
<view class="form-right">
<view>{{oplDetail.operation_.name}}</view>
</view>
</view>
<view class="form-item border-bottom">
<view class="form-left">
<text class="form-left-text">具体地点</text>
</view>
<view class="form-right">
<view>{{oplDetail.operation_.place}}</view>
</view>
</view>
<view class="form-item border-bottom">
<view class="form-left">
<text class="form-left-text">作业状态</text>
</view>
<view class="form-right">
<view>{{state_[oplDetail.operation_.state]}}</view>
</view>
</view>
<view class="form-item border-bottom">
<view class="form-left">
<text class="form-left-text">生产状态</text>
</view>
<view class="form-right">
<view>{{oplDetail.operation_.state_work }}</view>
</view>
</view>
<view class="form-item border-bottom">
<view class="form-left">
<text class="form-left-text">作业区域</text>
</view>
<view class="form-right">
<view>{{oplDetail.operation_.area_.name}}</view>
</view>
</view>
<view class="form-item border-bottom">
<view class="form-left">
<text class="form-left-text">业务部门</text>
</view>
<view class="form-right">
<view>{{oplDetail.operation_.dept_bus_.name}}</view>
</view>
</view>
<view class="form-item border-bottom">
<view class="form-left">
<text class="form-left-text">属地部门</text>
</view>
<view class="form-right">
<view>{{oplDetail.operation_.dept_ter_.name}}</view>
</view>
</view>
<view class="form-item ">
<view class="form-left">
<text class="form-left-text">部门协调员</text>
</view>
<view class="form-right">
<view>{{oplDetail.operation_.coordinator_.name}}</view>
</view>
</view>
</view>
<view class="ticket-info">
<view class="form-content ">
<view class="form-item border-bottom">
<view class="form-left">
<text class="form-left-text">开始时间</text>
</view>
<view class="form-right form-date">
<view>{{oplDetail.start_time}}</view>
</view>
</view>
<view class="form-item border-bottom">
<view class="form-left">
<text class="form-left-text">结束时间</text>
</view>
<view class="form-right form-date">
<view>{{oplDetail.end_time}}</view>
</view>
</view>
<view class="form-item border-bottom">
<view class="form-left">
<text class="form-left-text">作业级别</text>
</view>
<view class="form-right">
<view>{{oplDetail.level}}</view>
</view>
</view>
<view class="form-item border-bottom">
<view class="form-left">
<text class="form-left-text">作业部门</text>
</view>
<view class="form-right">
<view>{{oplDetail.dept_do_.name}}</view>
</view>
</view>
<view class="form-item border-bottom">
<view class="form-left">
<text class="form-left-text">作业负责人</text>
</view>
<view class="form-right">
<view>{{oplDetail.charger_.name}}</view>
</view>
</view>
<view class="form-item border-bottom">
<view class="form-left">
<text class="form-left-text">作业监护人</text>
</view>
<view class="form-right">
<view>{{oplDetail.monitor_.name}}</view>
</view>
</view>
<view class="form-item border-bottom">
<view class="form-left">
<text class="form-left-text">风险分析</text>
</view>
<view class="form-right">
<text v-for="item in oplDetail.risks_checked_" :key="item.id">{{ item.name}}|</text>
</view>
</view>
<view class="form-item">
<view class="form-left">
<text class="form-left-text">控制措施</text>
</view>
<view class="form-right">
<text v-for="item in oplDetail.measures_checked_" :key="item.id">{{ item.name}}|</text>
</view>
</view>
</view>
</view>
</block>
<view class="ticket-info">
<view class="form-item" style="height: 300rpx;">
<view class="form-left-text">
<text class="star">*</text>
<text>审批意见</text>
</view>
<textarea class="apply-reason-text" v-model="form.name" maxlength="250" placeholder="请输入" />
</view>
<view class="btn" style="display: flex;justify-content: space-between;">
<view class="left-content">
<button class="handleBtn" type="primary" @click="addNode">加签</button>
<button class="handleBtn" v-if="ticketDetail.state_&&ticketDetail.state_.enable_deliver"
type="primary" plain @click="deliverNode">转交
</button>
</view>
<view class="right-time">
<button v-for="item in operationBtn" :key="item.id" class="handleBtn"
:type="item.attribute_type===2?'danger':'primary'" @click="operationSubmit(item.id)">
{{item.name}}
</button>
</view>
<!-- <button type="default" class="save-btn">同意</button> -->
</view>
</view>
</view>
</template>
<script>
var that;
var promise;
export default {
name: "fafangbaogao_apply",
watch: {
/* 文件下载监听 */
lsDownLoadImg(newVal, oldVal) {
let val = newVal;
if (String(newVal).indexOf(",") > -1) {
val = String(newVal).split(",")[0] === "true";
}
this.$set(this.downFiles, 'downLoadImg' + this.lsFileId, val)
},
/* 文件下载监听 */
principal(newVal, oldVal) {
if (!this.itemId) {
if (oldVal.roleId === undefined && newVal.roleId !== undefined) {
this.formData.itemInfo.applicationDept = newVal.deptId
this.formData.applicationDept = newVal.deptId
}
}
},
},
data() {
const currentDate = this.getDate({
format: true
})
return {
form: {
suggestion: '',
close_note: '',
close_dos: ''
},
ticketId: null,
cateType: null,
operation: null,
projectId: null,
date: currentDate,
detail: false,
isDisabled: false,
btnShow: true,
lsId: "",
sta: null,
eventStatus: "",
execId: '',
// 2022320
result: [],
//
imgFlag: false,
//
downFiles: {},
timeShow: false,
//
releaseWeb: [],
ticketDetail: {},
visitDetail: {},
rpjDetail: {},
oplDetail: {},
opreationDetail: {},
operationBtn: {},
createTimeFromShow: false,
createTimeFromList: [],
createTimeFromCon: '',
depRange: [{
label: "name1",
id: 1
}, {
label: "name2",
id: 2
}],
range: [{
value: 0,
text: "运行"
},
{
value: 1,
text: "停机"
},
{
value: 2,
text: "检修"
},
],
dataTree: [{
text: "曲阳金隅",
value: "1",
children: [{
text: "设计部",
value: "11",
children: [{
text: "设计一部",
value: "111"
},
{
text: "设计一部",
value: "112"
}
]
},
{
text: "12生产部",
value: "12"
}
]
}],
purpose_: {
10: "参观",
20: "拜访",
30: "面试",
40: "开会"
},
rpjType_: {
10: "建筑施工",
20: "设备设施检维修",
30: "保安保洁服务",
40: "其他",
},
state_: {
10: "创建中",
20: "审批中",
30: "待入厂",
40: "进行中",
50: "已完成",
},
}
},
computed: {
startDate() {
return this.getDate('start');
},
endDate() {
return this.getDate('end');
}
},
onLoad(params) {
// debugger;
console.log(params)
that = this;
that.ticketId = params.ticketId;
that.projectId = params.projectId;
that.cateType = params.cateType;
that.operation = params.operation;
},
onShow() {
if (this.cateType === 'visit') {
this.getVisit();
} else if (this.cateType === 'rparty') {
this.getRpj();
} else {
if (this.operation !== null) {
this.getOperation();
this.getOpl();
} else {
this.getOpl();
}
// this.getCloseDos();
}
this.getticketItem();
this.getBtns();
},
methods: {
//
getticketItem() {
this.$u.api.getTicketItem(this.ticketId).then((res) => {
this.ticketDetail = res;
});
},
//访
getVisit() {
this.$u.api.getVisit(this.ticketId).then(res => {
this.visitDetail = res;
})
},
//
getRpj() {
this.$u.api.getRpj(this.projectId).then((res) => {
// debugger;
this.rpjDetail = res;
});
},
//
getOperation() {
// debugger;
this.$u.api.getOpreation(this.operation).then((res) => {
// debugger;
this.opreationDetail = res;
});
},
//
getOpl() {
this.$u.api.getOpl(this.projectId).then((res) => {
// debugger;
this.oplDetail = res;
});
},
//
getBtns() {
this.$u.api.getTicketTransitions(this.ticketId).then(res => {
this.operationBtn = res;
})
},
onnodeclick(e) {
console.log(e);
},
onpopupopened(e) {
console.log('popupopened');
},
onpopupclosed(e) {
console.log('popupclosed');
},
onchange(e) {
console.log('onchange:', e);
},
getDate(type) {
const date = new Date();
let year = date.getFullYear();
let month = date.getMonth() + 1;
let day = date.getDate();
if (type === 'start') {
year = year - 60;
} else if (type === 'end') {
year = year + 2;
}
month = month > 9 ? month : '0' + month;
day = day > 9 ? day : '0' + day;
return `${year}-${month}-${day}`;
},
bindStartDateChange: function(e) {
this.formData.start_time = e.detail.value
},
bindEndDateChange: function(e) {
this.formData.end_time = e.detail.value
},
happenTimeFun(num) { //
let date = new Date(num);
//10*1000131000
let y = date.getFullYear();
let MM = date.getMonth() + 1;
MM = MM < 10 ? ('0' + MM) : MM; //0
let d = date.getDate();
d = d < 10 ? ('0' + d) : d; //0
let h = date.getHours();
h = h < 10 ? ('0' + h) : h; //0
let m = date.getMinutes();
m = m < 10 ? ('0' + m) : m; //0
let s = date.getSeconds();
s = s < 10 ? ('0' + s) : s; //0
//         return y + '-' + MM + '-' + d + ' ' + h + ':' + m+ ':' + s;
return y + '-' + MM + '-' + d;
},
createTimeToFn(e) {
that.formData.createTimeTo = e.year + '-' + e.month + '-' + e.day;
},
createTimeFromYesFn(e) {
console.log(e)
var index = e[0]
that.formData.createTimeFrom = that.createTimeFromList[index].id
that.createTimeFromCon = that.createTimeFromList[index].label
},
onSubmit(type) {
if (!this.paramsCheck()) return;
if (this.detail && !this.formData.id) {
uni.showToast({
title: '缺少pkid',
icon: "none"
})
return;
}
this._updatePrintList(this.formData, type);
},
publishChange(e) {
var i = e.detail.value;
that.publishRangeCon = that.publishRange[i].name;
that.formData.scopeOfPublication = that.publishRange[i].id;
},
goBack() {
uni.navigateBack({
delta: 1
})
},
operationSubmit(id) {
let params = new Object();
params.transition = id;
params.ticket_data = {};
params.suggestion = this.form.suggestion;
if (this.ticketDetail.state_.name === '作业负责人关闭') {
params.ticket_data.close_note = this.form.close_note;
params.ticket_data.close_dos = this.form.close_dos;
}
this.$API.wf.ticket.ticketHandle.req(this.ticketId, params).then(res => {
if (res.err_msg) {} else {
this.$router.push("dutywork");
}
})
},
}
}
</script>
<style scoped>
.handleBtn {
height: 80rpx;
line-height: 80rpx;
font-size: 32rpx;
}
.ticket-handle {
background-color: #f3fbff;
padding-bottom: 227rpx;
}
/*
>>>.uni-status-bar {
height: 0 !important;
} */
>>>.uni-navbar-btn-text text {
font-size: 32rpx !important;
}
.ticket-info {
width: 720rpx;
margin: 0 auto;
background-color: #FFFFFF;
border-radius: 10rpx;
padding: 25rpx 32rpx;
box-sizing: border-box;
margin-top: 24rpx;
}
.border-bottom {
border-bottom: 1rpx solid #eeeeee;
}
.star {
color: red;
}
.top-title-text {
padding-left: 24rpx;
position: relative;
font-family: PingFang-SC-Medium;
font-size: 34rpx;
line-height: 72rpx;
color: #383838;
}
.top-title-text::before {
content: "";
width: 6rpx;
height: 29rpx;
background-image: linear-gradient(90deg, #164cc3 0%, #2c6fd9 100%);
border-radius: 3rpx;
display: block;
position: absolute;
left: -4rpx;
top: 22rpx;
}
.form-item {
/* display: flex; */
font-family: PingFang-SC-Medium;
font-size: 30rpx;
/* line-height: 97rpx; */
min-height: 100rpx;
display: flex;
flex-wrap: wrap;
align-items: center;
}
.form-left-text {
color: #212121;
margin-bottom: 33rpx;
}
.form-left {
/* min-width: 160rpx; */
/* width: 100%; */
}
.form-right {
margin-left: 20rpx;
flex: 1;
color: #414141;
}
.form-right input {
/* height: 100%; */
/* height: 60rpx; */
font-size: 30rpx;
}
.form-date>>>.uni-date__x-input {
height: 97rpx;
font-size: 30rpx;
}
.form-date>>>.uni-icons {
display: none;
}
.ticket-handle>>>uni-input {
/* height: 100%; */
font-size: 30rpx;
}
.apply-reason-text {
width: 653rpx;
height: 179rpx;
background-color: #f6f8fc;
border: solid 1rpx #e5e5e5;
margin-top: 21rpx;
padding: 14rpx 24rpx;
font-size: 26rpx;
box-sizing: border-box;
}
.apply_require {
margin-top: 0rpx !important;
}
.file-list {
display: flex;
flex-wrap: wrap;
justify-content: flex-start;
padding-top: 13rpx;
}
.file-wrap {
margin-top: 20rpx;
margin-right: 20rpx;
}
.file-item {
width: 155rpx;
height: 155rpx;
border: solid 1rpx #e5e5e5;
text-align: center;
display: flex;
align-items: center;
position: relative;
}
.file-content {
width: 100%;
}
.file-item .file-icon {
width: 37rpx;
height: 37rpx;
}
.file-item .file-name {
font-family: PingFang-SC-Regular;
font-size: 20rpx;
line-height: 17rpx;
color: #313131;
margin-top: 11rpx;
padding: 10rpx;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.file-item>>>.uni-icons {
width: 26rpx;
height: 26rpx;
position: absolute;
right: -8rpx;
top: -22rpx;
/*
background-color: #d81e06;
border-radius: 50%;
font-size: 20rpx !important;
padding: 5rpx;
*/
box-sizing: border-box;
}
.form-right {
flex: 1;
color: #414141;
}
/*部门*/
uni-data-picker {
width: 100%;
border: none !important;
}
.my-data-picker>>>.input-value-border {
border: none !important;
}
>>>.input-value {
font-size: 30rpx !important;
;
}
.my-data-picker uni-data-picker {
width: 100% !important;
}
.my-data-picker {
width: 100%;
display: flex;
align-items: center;
margin-left: -10rpx;
}
/* 主体 */
>>>.uni-navbar__header,
>>>.uni-status-bar {
background-image: linear-gradient(90deg, #164cc3 0%, #2c6fd9 100%), linear-gradient(#e60012, #e60012) !important;
}
.title {
font-size: 14px;
font-weight: bold;
margin: 20px 0 5px 0;
}
.data-pickerview {
height: 400px;
border: 1px #e5e5e5 solid;
}
.popper__arrow {
top: -6px;
left: 50%;
margin-right: 3px;
border-top-width: 0;
border-bottom-color: #EBEEF5;
}
.popper__arrow {
top: -6px;
left: 50%;
margin-right: 3px;
border-top-width: 0;
border-bottom-color: #EBEEF5;
}
</style>

View File

@ -0,0 +1,8 @@
<template>
</template>
<script>
</script>
<style>
</style>

View File

@ -1,112 +1,281 @@
<template>
<view class="wrap">
<u-swiper @change="change" :height="250" :list="swiper_list" :title="title" :effect3d="effect3d" :indicator-pos="indicatorPos"
:mode="mode" :interval="3000" @click="click"></u-swiper>
<u-cell-group title-bg-color="rgb(243, 244, 246)" :title="item.groupName" v-for="(item, index) in list" :key="index">
<u-cell-item :titleStyle="{fontWeight: 500}" @click="openPage(item1.path)" :title="item1.title" v-for="(item1, index1) in item.list"
:key="index1">
<image slot="icon" class="u-cell-icon" :src="getIcon(item1.icon)" mode="widthFix"></image>
</u-cell-item>
</u-cell-group>
<view class="index">
<view>
<view
style="height: 290rpx;background-image: url('../../static/home/index-top-img.png');background-position: center bottom;background-size: 100%;">
</view>
<view class="navigate-title">
<view @click="goIntoTargetPage('daiban')"
style="width: 25%;height: 100%;display: flex;flex-direction: column;justify-content: center;">
<text class="text">2</text>
<view class="status" >待办工单
</view>
</view>
<view @click="goIntoTargetPage('warning')"
style="width: 25%;height: 100%;display: flex;flex-direction: column;justify-content: center;">
<text class="text">1</text>
<view class="status">
实时报警
</view>
</view>
</view>
<view class="daiban">
<view class="daiban01">
<view @click="goInto('daiban')" class="title">
<view class="left-content">
<view class="img-view">
<image src="../../static/home/daiban.png" mode="" class="img"></image>
</view>
<text class="title-text-left">待审批</text>
</view>
<view class="">
<text class="title-text-right">查看更多</text>
<uni-icons type="right" :size="11" color="#ababab"></uni-icons>
</view>
</view>
<view class="line"></view>
</view>
<view class="daiban02">
</view>
</view>
<view class="tongzhi">
<view class="title">
<view class="left-content">
<view class="img-view">
<image src="../../static/home/tongzhi.png" mode="" class="img"></image>
</view>
<text class="title-text-left">实时报警</text>
</view>
<view class="" @click="xinwenList">
<text class="title-text-right">查看更多</text>
<uni-icons type="right" :size="11" color="#ababab"></uni-icons>
</view>
</view>
<view class="line"></view>
</view>
</view>
</view>
</template>
<script>
export default {
data() {
return {
swiper_list: [{
image: 'https://cdn.uviewui.com/uview/swiper/1.jpg',
title: '昨夜星辰昨夜风,画楼西畔桂堂东'
},
{
image: 'https://cdn.uviewui.com/uview/swiper/2.jpg',
title: '身无彩凤双飞翼,心有灵犀一点通'
},
{
image: 'https://cdn.uviewui.com/uview/swiper/3.jpg',
title: '谁念西风独自凉,萧萧黄叶闭疏窗,沉思往事立残阳'
}
],
title: false,
mode: 'round',
indicatorPos: 'bottomCenter',
effect3d: true,
test: '',
list: [{
groupName: '个人辐射信息',
list: [{
path: '/pages/example/components',
icon: 'color',
title: '个人培训记录',
},
{
path: '/pages/example/components',
icon: 'color',
title: '个人剂量检测',
}]
},
{
groupName: '单位辐射信息',
list: [{
path: '/pages/example/js',
icon: 'color',
title: '员工台账',
},
{
path: '/pages/example/components',
icon: 'color',
title: '放射源台账',
}]
}
]
tzList: [],
// top-obj4
topObj: {},
approvalObj1: null,
approvalObj2: null,
// 2022218
mytopimg: require("@/static/home/bgimg-top.jpg"),
}
},
computed: {
getIcon() {
return path => {
return 'https://cdn.uviewui.com/uview/example/' + path + '.png';
}
},
},
onLoad() {
},
onShow() {
this.getUserInfo();
},
methods: {
getUserInfo() {
this.$u.api.getUserInfo().then(res => {
}).catch(e=>{})
goIntoTargetPage(type) {
if (type == "daiban") {
uni.navigateTo({
url: "./list/ticket"
})
}
if (type == "warning") {
uni.navigateTo({
url: "./list/warning"
})
}
},
openPage(path) {
this.$u.route({
url: path
})
},
change() {
},
click() {
}
}
}
</script>
<style>
page {
background-color: #ededed;
<style scoped>
.index {
background-color: #edf8ff;
padding-bottom: 45rpx;
position: relative;
}
</style>
<style lang="scss" scoped>
.u-cell-icon {
width: 36rpx;
height: 36rpx;
margin-right: 8rpx;
.nav-bar {
height: 401rpx;
background-color: #2cade8;
background-size: cover;
color: #FFFFFF;
padding-top: 26rpx;
padding-left: 18rpx;
}
.nav-bar-text {
font-size: 38rpx;
color: #ffffff;
font-weight: 400;
}
.navigate-title {
width: 720rpx;
height: 160rpx;
background-color: #ffffff;
box-shadow: 0px 2px 24px 0px rgba(213, 237, 255, 0.53);
border-radius: 10px;
display: flex;
justify-content: space-around;
align-items: center;
text-align: center;
position: absolute;
left: 50%;
top: 196rpx;
transform: translateX(-50%);
z-index: 1;
}
.navigate-title .text+.status {
font-weight: normal;
font-stretch: normal;
letter-spacing: 0rpx;
}
.navigate-title .text {
font-family: PingFang-SC-Bold;
font-size: 48rpx;
font-weight: 600;
color: #2c6fd9;
}
.navigate-title .status {
font-family: PingFang-SC-Medium;
font-size: 26rpx;
color: #383838;
}
.daiban01 {
width: 720rpx;
background-color: #ffffff;
border-radius: 10rpx;
margin: 0 auto;
margin-top: 88rpx;
}
.title {
display: flex;
justify-content: space-between;
padding: 20rpx 20rpx;
height: 79rpx;
align-items: center;
}
.left-content {
display: flex;
align-items: center;
}
.img-view {
width: 30rpx;
height: 30rpx;
}
.img-view .img {
width: 100%;
height: 100%;
}
.title-text-left {
font-size: 34rpx;
color: #383838;
padding-left: 10rpx;
}
.title-text-right {
font-family: PingFang-SC-Medium;
font-size: 24rpx;
font-weight: normal;
font-stretch: normal;
line-height: 72rpx;
color: #ababab;
}
.line {
width: 660rpx;
height: 1rpx;
background-color: #eeeeee;
margin: 0 auto;
}
.daiban02 {
width: 720rpx;
background-color: #ffffff;
border-radius: 10rpx;
margin: 0 auto;
margin-top: 18rpx;
}
/* 通知样式 */
.tongzhi {
width: 720rpx;
background-color: #ffffff;
border-radius: 10rpx;
margin: 0 auto;
margin-top: 20rpx;
padding-bottom: 20rpx;
}
.tongzhi .content {
display: flex;
padding: 0 20rpx;
margin-top: 41rpx;
}
.tongzhi-img image {
width: 55rpx;
height: 55rpx;
border-radius: 50%;
}
.tongzhi .tongzhi-info {
margin-left: 15rpx;
flex: 1;
}
.tongzhi-info .tongzhi-title {
font-size: 30rpx;
color: #3d3d3d;
}
.tongzhi-info .tongzhi-content {
font-family: PingFang-SC-Medium;
font-size: 28rpx;
line-height: 50rpx;
color: #5b5b5b;
overflow: hidden;
text-overflow: ellipsis;
display: box;
display: -webkit-box;
line-clamp: 2;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
word-break:break-all;
}
.tongzhi .bottom-content {
font-family: PingFang-SC-Regular;
font-size: 24rpx;
line-height: 72rpx;
letter-spacing: 0rpx;
color: #ababab;
text-align: right;
padding: 0 20rpx;
}
.bottom-content .liulan {
margin-right: 40rpx;
}
</style>

269
pages/home/list/ticket.vue Normal file
View File

@ -0,0 +1,269 @@
<template>
<view class="my_duty">
<uni-nav-bar @clickLeft="goBack()" height="110rpx" leftWidth="200rpx" leftText="我的代办" leftIcon="left" border
backgroundColor="#2cade8" color="#fff" fixed statusBar shadow></uni-nav-bar>
<view class="my-top-search-nav">
<view class="search-wrap">
<view class="search-body">
<image class="left-img" src="../../../static/home/searchIcon.png" mode=""></image>
<input class="search-input" type="text" v-model="search" placeholder="请输入" />
<image class="right-img" src="../../../static/my/my_apply/zuofei.png" mode="" @click="resetSearch">
</image>
<view class="right-btn" @click="searchHandle">搜索</view>
</view>
</view>
</view>
<view class="empty-view"></view>
<view class="content">
<view class="item-wrap" v-for="(val,index) in ticketList" :key="val.id">
<view class="duty-item">
<view class="top-info">
<view class="info-title">{{val.title}}</view>
</view>
<view class="center-info">
<view class="info-details">所属工作流{{val.workflow_.name}}</view>
<view class="info-details">工单状态{{val.state_.name}}</view>
<view class="info-details">提交时间{{val.create_time}} </view>
<view class="info-details">更新时间{{val.update_time}} </view>
</view>
<view class="bottom-btns">
<view class="shenhezhong shenhe-status" @click="ticketHandle(val)">
<image src="../../../static/my/my_apply/blue-time.png" mode=""></image>
处理
</view>
</view>
</view>
</view>
</view>
</view>
</template>
<script>
export default {
name: 'ticket',
data() {
return {
search: '',
pageSize: 10,
pageNum: 1,
totalNum: 0,
ticketList: [],
}
},
//
onReachBottom() {
const totalPage = Math.ceil(this.totalNum / this.pageSize);
if (this.pageNum < totalPage) {
this.pageNum += 1;
this._getMyApplyList(false);
} else {
uni.showToast({
title: "已全部加载",
icon: 'none'
})
}
},
onShow() {
this.ticketList = [];
this.getTicketLists();
},
//
onPullDownRefresh() {
this.pageNum = 1;
this.ticketList = [];
this.getTicketLists();
},
methods: {
getTicketLists() {
let that = this;
let obj = {};
obj.category = 'duty';
obj.pageNum = this.pageNum;
obj.pageSize = this.pageSize;
if (that.search !== '') {
obj.search = that.search;
}
obj.pageSize = this.pageSize;
that.$u.api.getTickets(obj).then(res => {
that.ticketList = that.ticketList.concat(res.results);
this.totalNum = res.count;
})
},
ticketHandle(val) {
let projectId = '',//Id
operation = null;//id
let catetype = val.workflow_.key;
if (catetype === 'visit') {
projectId = val.ticket_data.visit;
} else if (catetype === 'Fire') {
projectId = val.ticket_data.opl;
operation = val.ticket_data.operation ? val.ticket_data.operation : null;
}
const params = `?ticketId=${val.id}&projectId=${projectId}&cateType=${catetype}&operation=${operation}`;
uni.navigateTo({
url: '../detail/ticketHandle' + params,
})
},
goBack() {
uni.navigateBack({
delta: 1
})
},
searchHandle() {
this.pageNum = 1;
this.ticketList = [];
this.getTicketLists()
},
resetSearch() {
this.pageNum = 1;
this.search = "";
this.ticketList = [];
this.getTicketLists();
},
}
}
</script>
<style scoped>
.empty-view {
height: 120rpx;
}
>>>.uni-navbar__header,
>>>.uni-status-bar {
background-image: linear-gradient(254deg,
#0ca7ee 0%,
#005aff 100%,
#2a8cff 100%,
#54bdff 100%),
linear-gradient(#e60012,
#e60012);
}
.my_duty {
background-color: #f3fbff;
}
.my_duty>>>.uni-navbar-btn-text text {
font-size: 32rpx !important;
}
.content {
padding: 14rpx;
}
.item-wrap {
margin-bottom: 14rpx;
}
.duty-item {
width: 720rpx;
background-color: #ffffff;
border-radius: 10rpx;
margin: 0 auto;
padding: 24rpx 21rpx;
box-sizing: border-box;
}
.info-title {
font-family: PingFang-SC-Medium;
font-size: 30rpx;
line-height: 72rpx;
color: #3d3d3d;
flex: 1;
}
.right-time {
font-size: 24rpx;
line-height: 72rpx;
color: #ababab;
}
.center-info {
padding-bottom: 30rpx;
border-bottom: 1rpx solid #eeeeee;
}
.info-details {
font-size: 28rpx;
line-height: 40rpx;
color: #5b5b5b;
}
.bottom-btns {
text-align: center;
font-family: PingFang-SC-Medium;
font-size: 28rpx;
line-height: 83rpx;
}
.shenhezhong {
color: #2c6fd9;
}
.shenhe-status image {
width: 26rpx;
height: 26rpx;
margin-right: 10rpx;
vertical-align: middle;
}
.my-top-search-nav {
position: fixed;
left: 0;
right: 0;
z-index: 999;
}
.search-wrap {
background-blend-mode: normal,
normal;
padding-bottom: 44rpx;
padding-top: 20rpx;
}
.search-body {
width: 715rpx;
height: 78rpx;
background-color: #ffffff;
border-radius: 39rpx;
margin: 0 auto;
padding: 13rpx;
padding-left: 25rpx;
box-sizing: border-box;
display: flex;
align-items: center;
}
.search-body .search-input {
height: 100%;
flex: 1;
padding-left: 12rpx;
box-sizing: border-box;
}
.left-img {
width: 26rpx;
height: 26rpx;
}
.right-img {
width: 30rpx;
height: 30rpx;
margin-right: 10rpx;
}
.right-btn {
width: 110rpx;
height: 58rpx;
line-height: 58rpx;
background-image: linear-gradient(0deg,
#2da0f3 0%,
#54bcff 100%);
border-radius: 29rpx;
font-size: 28rpx;
color: #ffffff;
text-align: center;
}
</style>

369
pages/home/list/warning.vue Normal file
View File

@ -0,0 +1,369 @@
<template>
<view class="my-apply">
<uni-nav-bar @clickLeft="goBack()" height="110rpx" leftWidth="200rpx" leftText="实时报警" leftIcon="left" border
backgroundColor="#2cade8" color="#fff" fixed statusBar shadow></uni-nav-bar>
<view class="my-top-search-nav">
<view class="search-wrap">
<view class="search-body">
<image class="left-img" src="/static/home/searchIcon.png" mode=""></image>
<input class="search-input" v-show="isHetongShow" type="text" v-model="contractCode"
placeholder="请输入合同编号" />
<input class="search-input" v-show="!isHetongShow" type="text" v-model="incomeGeneratingProjectCode"
placeholder="请输入项目代码" />
<view class="right-btn" @click="search">
搜索
</view>
</view>
</view>
</view>
<view class="empty-view"></view>
<view class="content">
<view class="item-wrap" @click="intoUpdatePage(val)" v-for="(val,index) in applyList" :key="val.pkId">
<view class="apply-item">
<view class="top-info">
<!-- <image class="left-img" src="../../../static/common/avatar.png" mode=""></image> -->
<view class="info-title">{{val.itemName}}</view>
<!-- <view class="right-time">
2021.10.06
</view> -->
</view>
<view class="center-info">
<view class="info-details">所属模块{{val.menuName}}</view>
<view class="info-details">申请人{{val.applicantName}}</view>
<view class="info-details">所属部门{{val.applicationDeptName}}</view>
<view class="info-details" v-if="val.eventStatus != 4">提交时间{{val.submissionTime}} </view>
</view>
<view class="bottom-btns">
<view v-if="val.eventStatus == 3" class="shenhezhong shenhe-status">
<image src="/static/profile/my_apply/blue-time.png" mode=""></image>
审核中
</view>
<view v-if="val.eventStatus == 4" class="no-submit shenhe-status">
<image class="" src="/static/profile/my_apply/orange-time.png" mode=""></image>
未提交
</view>
<view v-if="val.eventStatus == 1" class="tongguo shenhe-status">
<image class="" src="/static/profile/my_apply/tongguo.png" mode=""></image>
审核通过
</view>
<view v-if="val.eventStatus == 2" class="zuofei shenhe-status">
<image class="" src="/static/profile/my_apply/zuofei.png" mode=""></image>
已作废
</view>
<view v-if="val.eventStatus == 0" class="return shenhe-status">
<image class="" src="/static/profile/my_apply/return.png" mode=""></image>
已退回
</view>
</view>
</view>
</view>
</view>
</view>
</template>
<script>
export default {
name: 'warning',
data() {
return {
itemName: "",
moduleId: "",
submissionTimeFrom: "",
submissionTimeFromTo: "",
eventStatus: "",
pageSize: 10,
pageNum: 1,
totalNum: 0,
applyList: [],
obj: {
eventStatus: '',
moduleId: '',
submissionTimeFrom: '',
submissionTimeFromTo: ''
}
}
},
//
onReachBottom() {
const totalPage = Math.ceil(this.totalNum / this.pageSize);
if (this.pageNum < totalPage) {
this.pageNum += 1;
this._getMyApplyList(false);
} else {
uni.showToast({
title: "已全部加载",
icon: 'none'
})
}
},
onShow() {
// this._getMyApplyList(true);
},
//
onPullDownRefresh() {
this.pageNum = 1;
this._getMyApplyList(true);
},
methods: {
intoUpdatePage(val) {
// this.$store.commit("clearAllData"); /* */
const routeObj = routeArray.find(item => {
return item.pcRoute == val.menuID;
})
if (routeObj !== undefined && routeObj !== null && routeObj !== "") {
const params =
`?pkId=${val.pkId}&itemId=${val.itemId}&execId=${val.execId}&eventStatus=${val.eventStatus}&detail=${true}`;
uni.navigateTo({
url: routeObj.appAdd + params,
})
} else {
uni.showToast({
icon: "none",
title: "路由异常, 无法跳转, 请检查correspondingRoute.js中是否配置"
})
}
},
goBack() {
uni.navigateBack({
delta: 1
})
},
caseSearch(itemName) {
this.pageNum = 1;
this.eventStatus = "";
this.moduleId = "";
this.submissionTimeFrom = '';
this.submissionTimeFromTo = "";
this.itemName = itemName;
this._getMyApplyList(true);
},
quedingSearch(queryData) {
this.pageNum = 1;
this.itemName = "";
this.obj = {
eventStatus: queryData.eventStatus,
moduleId: queryData.moduleId,
submissionTimeFrom: queryData.submissionTimeFrom,
submissionTimeFromTo: queryData.submissionTimeFromTo
}
this.eventStatus = queryData.eventStatus;
this.moduleId = queryData.moduleId;
this.submissionTimeFrom = queryData.submissionTimeFrom;
this.submissionTimeFromTo = queryData.submissionTimeFromTo;
this._getMyApplyList(true);
},
_getMyApplyList(flag) {
const params = {
myApplyApproval: {
isMyApplyOrApproval: 0,
moduleId: ""
},
queryRequest: {
pageSize: this.pageSize,
pageNum: this.pageNum,
}
}
if (this.itemName) {
params.myApplyApproval.itemName = this.itemName;
}
if (this.eventStatus) {
params.myApplyApproval.eventStatus = this.eventStatus;
}
if (this.moduleId) {
params.myApplyApproval.moduleId = this.moduleId;
}
if (this.submissionTimeFrom && this.submissionTimeFromTo) {
params.myApplyApproval.submissionTimeFrom = this.submissionTimeFrom;
params.myApplyApproval.submissionTimeFromTo = this.submissionTimeFromTo;
}
getMyApplyList(params).then(res => {
if (res.statusCode === 200) {
const data = res.data.data.rows;
this.totalNum = res.data.data.total;
if (flag === true) {
this.applyList = data;
} else {
this.applyList = this.applyList.concat(data);
}
} else {
this.applyList = [];
uni.showToast({
title: res.data.message,
icon: 'none'
})
}
}).catch(err => {
this.applyList = [];
uni.showToast({
title: '网络异常, 请求失败',
icon: 'none'
})
})
}
}
}
</script>
<style scoped>
.empty-view {
height: 120rpx;
}
>>>.uni-navbar__header,
>>>.uni-status-bar {
background-image: linear-gradient(254deg,
#0ca7ee 0%,
#005aff 100%,
#2a8cff 100%,
#54bdff 100%),
linear-gradient(#e60012,
#e60012);
}
.my-apply {
background-color: #f3fbff;
}
.my-apply>>>.uni-navbar-btn-text text {
font-size: 32rpx !important;
}
.content {
padding: 14rpx;
}
.item-wrap {
margin-bottom: 14rpx;
}
.apply-item {
width: 720rpx;
background-color: #ffffff;
border-radius: 10rpx;
margin: 0 auto;
padding: 24rpx 21rpx;
box-sizing: border-box;
}
.info-title {
font-family: PingFang-SC-Medium;
font-size: 30rpx;
line-height: 72rpx;
color: #3d3d3d;
flex: 1;
}
.right-time {
font-size: 24rpx;
line-height: 72rpx;
color: #ababab;
}
.center-info {
padding-bottom: 30rpx;
border-bottom: 1rpx solid #eeeeee;
}
.info-details {
font-size: 28rpx;
line-height: 40rpx;
color: #5b5b5b;
}
.bottom-btns {
text-align: center;
font-family: PingFang-SC-Medium;
font-size: 28rpx;
line-height: 83rpx;
}
.shenhezhong {
color: #2c6fd9;
}
.shenhe-status image {
width: 26rpx;
height: 26rpx;
margin-right: 10rpx;
vertical-align: middle;
}
.no-submit {
color: #f7870f;
}
.tongguo {
color: #15a306;
}
.zuofei {
color: #565656;
}
.return {
color: #e2053e;
}
.my-top-search-nav {
position: fixed;
left: 0;
right: 0;
z-index: 999;
}
.search-wrap {
background-blend-mode: normal,
normal;
padding-bottom: 44rpx;
padding-top: 20rpx;
}
.search-body {
width: 715rpx;
height: 78rpx;
background-color: #ffffff;
border-radius: 39rpx;
margin: 0 auto;
padding: 13rpx;
padding-left: 25rpx;
box-sizing: border-box;
display: flex;
align-items: center;
}
.search-body .search-input {
height: 100%;
flex: 1;
padding-left: 12rpx;
box-sizing: border-box;
}
.left-img {
width: 26rpx;
height: 26rpx;
}
.right-btn {
width: 110rpx;
height: 58rpx;
line-height: 58rpx;
background-image: linear-gradient(0deg,
#2da0f3 0%,
#54bcff 100%);
border-radius: 29rpx;
font-size: 28rpx;
color: #ffffff;
text-align: center;
}
</style>

View File

@ -1,130 +1,438 @@
<template>
<view class="wrap">
<view class="top"></view>
<view class="content">
<view class="title">欢迎登录美团</view>
<input class="u-border-bottom" type="number" v-model="tel" placeholder="请输入手机号" />
<view class="tips">未注册的手机号验证后自动创建美团账号</view>
<button @tap="submit" :style="[inputStyle]" class="getCaptcha">获取短信验证码</button>
<view class="alternative">
<view class="password">密码登录</view>
<view class="issue">遇到问题</view>
</view>
<view class="login_register">
<view class="nav-bar" style="position: relative;">
<image style="display: block;width: 100%;height: 100%;" :src="myTopBgSrc"></image>
</view>
<view class="buttom">
<view class="loginType">
<view class="wechat item">
<view class="icon"><u-icon size="70" name="weixin-fill" color="rgb(83,194,64)"></u-icon></view>
微信
<view class="handle-area">
<view class="handle-type">
<text class="text" :class="{active: isShow}">登录</text>
</view>
<view class="login-area">
<form style="display: block;" @submit="formSubmit">
<view class="login-item">
<image class="login-icon" src="../../static/login/avatar.png" mode=""></image>
<input placeholder-style="color: #2c6fd9;" style="color: #2c6fd9;" class="my-phone" type="text"
name="username" placeholder="请输入您的账号" />
</view>
<view class="login-item">
<image class="login-icon" src="../../static/login/password.png" mode=""></image>
<input placeholder-style="color: #2c6fd9;" style="color: #2c6fd9;" class="my-psd" type="text"
name="password" password placeholder="请输入您的密码" />
</view>
<view class="privacy">
<view class="privacyIn">
<u-checkbox-group>
<u-checkbox @change="checkboxChange" v-model="checkedShow"></u-checkbox>
</u-checkbox-group>
<view class="privacyCon">
我已阅读并同意<text style="color: #2d8cff;" @click="agreementFn(1)">用户协议</text><text
style="color: #2d8cff;" @click="agreementFn(2)">隐私政策</text>
</view>
</view>
</view>
<view class="">
<button type="default" form-type="submit" class="login-btn">立即登录</button>
</view>
</form>
</view>
<view class="wxBig" v-if="wxShow == true">
<view class="Wxtitle">
<view class="WxtitleIn">
第三方登录
</view>
</view>
<view class="QQ item">
<view class="icon"><u-icon size="70" name="qq-fill" color="rgb(17,183,233)"></u-icon></view>
QQ
<view class="wx" @click="loginFn">
<image src="/static/login/weixin.png" mode=""></image>
</view>
</view>
<view class="hint">
登录代表同意
<text class="link">美团点评用户协议隐私政策</text>
并授权使用您的美团点评账号信息如昵称头像收获地址以便您统一管理
</view>
</view>
<u-popup v-model="agreement" mode='center' :mask='true' border-radius='20' width='85%' height='75%'
:closeable='true'>
<view style="padding: 30rpx;" v-html="content">{{content}}</view>
</u-popup>
</view>
</template>
<script>
export default {
data() {
return {
tel: ''
}
},
computed: {
inputStyle() {
let style = {};
if(this.tel) {
style.color = "#fff";
style.backgroundColor = this.$u.color['warning'];
var that;
export default {
data() {
return {
agreement: false,
checkedShow: false,
key: "",
img: "",
username: '',
password: '',
code: "",
isShow: true,
myTopBgSrc: require("../../static/login/my-bg.jpg"),
content: '',
userContent: '',
privacyContent: '',
wxShow: false,
}
return style;
}
},
methods: {
submit() {
if(this.$u.test.mobile(this.tel)) {
this.$u.route({
url: 'pages/template/login/code'
},
onLoad() {
that = this;
},
methods: {
checkboxChange(e) {
uni.setStorageSync('privacyShow', e.value)
},
//
loginFn() {
if (that.checkedShow == false) {
uni.showToast({
title: '请勾选用户协议和隐私政策',
icon: 'none',
duration: 2000
})
return false;
}
uni.login({
provider: 'weixin',
success(res) {
if (res.authResult.unionid) {
appLogin(res.authResult.unionid).then(res1 => {
console.log(res1)
if (res1.statusCode == 200) {
if (res1.data.massage == 1) {
uni.navigateTo({
url: 'BangWx?unionid=' + res.authResult.unionid
})
} else {
uni.setStorageSync('my_token', res1.data.oAuth2AccessToken
.access_token);
that.updateCidFn(res1.data.userName);
}
} else {
uni.showToast({
title: '登录失败',
duration: 2000,
icon: 'none',
})
}
}).catch(err => {
console.log(err)
uni.showToast({
title: "请求失败",
icon: 'none'
})
})
} else {
uni.showToast({
title: '登录失败请重新登录',
duration: 2000,
icon: 'none',
})
}
}
})
},
//
updateCidFn(username) {
var data = {
userCid: uni.getStorageSync('setcid'),
username: username
}
updateCid(data).then(res => {
console.log(res, 'zhiixngle ')
if (res.statusCode == 200) {
uni.showToast({
title: '登录成功',
duration: 2000,
icon: 'none',
})
setTimeout(() => {
uni.reLaunch({
url: '../../index/index'
})
}, 2000)
}
}).catch(err => {
uni.showToast({
title: '请求失败',
icon: 'none'
})
})
},
//form
checkedParams(obj) {
/*
Azuma
1234qwer
*/
if (obj.username == "" || obj.username == undefined || obj.username == null) {
myShowToast('用户名不能为空');
return false;
};
if (obj.password == "" || obj.password == undefined || obj.password == null) {
myShowToast('密码不能为空');
return false;
};
if (that.checkedShow == false) {
myShowToast('请勾选用户协议和隐私政策');
return false;
}
function myShowToast(text) {
uni.showToast({
title: text,
icon: 'none'
})
};
return true;
},
formSubmit(e) {
var that = this;
const obj = e.target.value;
if (!that.checkedParams(obj)) return;
debugger;
console.log(obj)
that.$u.api.login(obj).then(res=>{
that.$u.vuex('vuex_token', res.access)
that.$u.vuex('vuex_refresh', res.refresh)
// let data = {openid: uni.getStorageSync('wxmp_openid')}
// that.$u.api.bindmp(data).then(res=>{})
that.$u.api.getUserInfo().then(res=>{
that.$u.vuex('vuex_user', res)
//
})
uni.reLaunch({
url:'/pages/home/home_'
})
}
).catch(e=>{
console.log(e)
uni.showToast({
title:'账户密码错误',
icon:'none'
})
})
}
}
}
};
</script>
<style lang="scss" scoped>
.wrap {
font-size: 28rpx;
.content {
width: 600rpx;
margin: 80rpx auto 0;
<style scoped lang="less">
.privacy {
width: 100%;
height: 40rpx;
padding: 0 40rpx;
margin-bottom: 25rpx;
.title {
text-align: left;
font-size: 60rpx;
font-weight: 500;
margin-bottom: 100rpx;
}
input {
text-align: left;
margin-bottom: 10rpx;
padding-bottom: 6rpx;
}
.tips {
color: $u-type-info;
margin-bottom: 60rpx;
margin-top: 8rpx;
}
.getCaptcha {
background-color: rgb(253, 243, 208);
color: $u-tips-color;
border: none;
font-size: 30rpx;
padding: 12rpx 0;
&::after {
border: none;
}
}
.alternative {
color: $u-tips-color;
.privacyIn {
width: 100%;
height: 100%;
display: flex;
justify-content: space-between;
margin-top: 30rpx;
}
}
.buttom {
.loginType {
display: flex;
padding: 350rpx 150rpx 150rpx 150rpx;
justify-content:space-between;
.item {
display: flex;
flex-direction: column;
align-items: center;
color: $u-content-color;
font-size: 28rpx;
}
}
.hint {
padding: 20rpx 40rpx;
font-size: 20rpx;
color: $u-tips-color;
.link {
color: $u-type-warning;
align-items: center;
.privacyCon {
font-size: 26rpx;
}
}
}
}
.wxBig {
width: 100%;
height: auto;
margin-top: 100rpx;
display: flex;
align-items: center;
flex-wrap: wrap;
justify-content: center;
.Wxtitle {
text-align: center;
width: 100%;
padding: 0 50rpx;
.WxtitleIn {
width: 100%;
font-size: 26rpx;
color: #808080;
position: relative;
}
.WxtitleIn::after {
content: '';
width: 217rpx;
height: 2rpx;
background-color: #f6f6f6;
position: absolute;
right: 0;
top: 18rpx;
}
.WxtitleIn::before {
content: '';
width: 217rpx;
height: 2rpx;
background-color: #f6f6f6;
position: absolute;
left: 0;
top: 18rpx;
}
}
.wx {
width: 70rpx;
height: 70rpx;
margin-top: 50rpx;
image {
width: 100%;
height: 100%;
}
}
}
.login_register {
position: relative;
background-color: #f3fbff;
min-height: 100vh;
}
.nav-bar {
height: 494rpx;
background-color: #2cade8;
color: #FFFFFF;
}
.handle-area {
width: 705rpx;
height: auto;
background-color: #FFFFFF;
border-radius: 10rpx;
position: absolute;
top: 340rpx;
left: 50%;
padding-bottom: 30rpx;
transform: translateX(-50%);
}
.handle-type {
font-family: PingFang-SC-Medium;
font-size: 30rpx;
line-height: 72rpx;
color: #1e1e1e;
padding: 62rpx;
}
.active {
font-size: 38rpx;
line-height: 72rpx;
color: #2c6fd9;
font-weight: bold;
position: relative;
}
.active::after {
display: block;
content: "";
width: 42rpx;
height: 6rpx;
background-color: #2c6fd9;
border-radius: 3rpx;
position: absolute;
left: 50%;
bottom: -8rpx;
transform: translateX(-50%);
}
.login-item {
width: 635rpx;
height: 88rpx;
border-radius: 88rpx;
margin: 0 auto;
background-color: #ebf6ff;
padding-left: 72rpx;
box-sizing: border-box;
position: relative;
margin-bottom: 56rpx;
}
.code-img-item {
padding-left: 72rpx;
}
.login-item .login-icon {
width: 22rpx;
height: 28rpx;
position: absolute;
top: 50%;
left: 35rpx;
transform: translateY(-50%);
}
.login-item input {
height: 100%;
line-height: 88rpx;
font-family: PingFang-SC-Medium;
font-size: 26rpx;
}
.my-code-input {
width: 300rpx;
}
.code-img {
width: 155rpx;
height: 53rpx;
position: absolute;
top: 50%;
right: 20rpx;
transform: translateY(-50%);
background-color: #EEEEEE;
}
.login-btn,
.register-btn {
width: 635rpx;
height: 88rpx;
border-radius: 88rpx;
margin: 0 auto;
background-color: #1d7ef3;
font-family: AdobeHeitiStd-Regular;
font-size: 30rpx;
line-height: 88rpx;
color: #ffffff;
}
.to-login {
font-family: AdobeHeitiStd-Regular;
font-size: 24rpx;
line-height: 72rpx;
color: #2c6fd9 !important;
border: none !important;
margin-top: 20rpx;
}
.code-item {
position: relative;
}
.my-code {
width: 376rpx;
}
.code {
width: 155rpx;
height: 53rpx;
background-color: #0075ff;
border-radius: 27rpx;
font-family: PingFang-SC-Medium;
font-size: 20rpx !important;
line-height: 53rpx;
color: #fefeff;
position: absolute;
top: 50%;
right: 20rpx;
transform: translateY(-50%);
padding-left: 12rpx;
padding-right: 12rpx;
}
</style>

View File

@ -1,62 +1,48 @@
<template>
<view>
<!-- <u-navbar :is-back="false" title=" " :border-bottom="false">
<view class="u-flex u-row-right" style="width: 100%;">
<view class="camera u-flex u-row-center">
<u-icon name="camera-fill" color="#000000" size="48"></u-icon>
</view>
</view>
</u-navbar> -->
<view class="u-flex user-box u-p-l-30 u-p-r-20 u-p-b-30">
<view class="u-m-r-10">
<!-- #ifdef MP-WEIXIN -->
<view class="avatarImg">
<open-data type="userAvatarUrl" default-avatar="/static/other/timg.jpg"></open-data>
</view>
<!-- #endif -->
<!-- #ifndef MP-WEIXIN -->
<u-avatar :src="vuex_user.avatar" size="140"></u-avatar>
<!-- #endif -->
</view>
<view class="u-flex-1">
<view class="u-font-18 u-p-b-20">
{{vuex_user.name}}
<u-tag text="企业员工" v-if="vuex_user.type == 'employee'"/>
<u-tag text="相关方" v-if="vuex_user.type == 'remployee'"/>
<u-tag text="访客" v-if="vuex_user.type == 'visitor'"/>
</view>
<view class="u-font-14 u-type-info">{{vuex_user.username}}-{{vuex_user.belong_dept_name}}-{{vuex_user.post_name}}</view>
<view class="u-font-14 u-type-info" v-if="vuex_user.wxmp_openid">已绑定微信小程序</view>
<view class="u-font-14 u-type-info" v-if="vuex_user.wx_openid">已绑定公众号通知</view>
</view>
<!-- <view class="u-m-l-10 u-p-10">
<u-icon name="scan" color="#969799" size="28"></u-icon>
</view>
<view class="u-m-l-10 u-p-10">
<u-icon name="arrow-right" color="#969799" size="28"></u-icon>
</view> -->
<view class="profile">
<view class="nav-bar" style="position: relative;">
<image style="position: absolute;left: 0;top: 0;display: block;width: 100%;height: 100%;z-index: 1;"
:src="myTopBgSrc" mode=""></image>
</view>
<!-- <view class="u-m-t-20">
<u-cell-group>
<u-cell-item icon="rmb-circle" title="支付"></u-cell-item>
</u-cell-group>
<view class="num-info" style="position: relative;z-index: 3;">
<view class="user-info" style="z-index: 2;">
<view class="user-head">
<!-- #ifdef MP-WEIXIN -->
<view class="avatarImg">
<open-data type="userAvatarUrl" default-avatar="/static/other/timg.jpg"></open-data>
</view>
<!-- #endif -->
<!-- #ifndef MP-WEIXIN -->
<u-avatar :src="vuex_user.avatar" size="140"></u-avatar>
<!-- #endif -->
</view>
<view>
<view style="font-weight: bold;" class="user-name">{{vuex_user.name}}</view>
<view class="user-phone">{{vuex_user.type}}</view>
</view>
<button type="default" class="modify-info" @click="goInto('myData')">完善资料</button>
</view>
</view>
<view class="u-m-t-20">
<u-cell-group>
<u-cell-item icon="star" title="收藏"></u-cell-item>
<u-cell-item icon="photo" title="相册"></u-cell-item>
<u-cell-item icon="coupon" title="卡券"></u-cell-item>
<u-cell-item icon="heart" title="关注"></u-cell-item>
</u-cell-group>
</view> -->
<view class="u-m-t-20">
<u-cell-group>
<u-cell-item icon="weixin-fill" title="绑定微信" :arrow="false" @click="bindMP" v-if="!vuex_user.wxmp_openid"></u-cell-item>
<u-cell-item icon="close" title="退出账号" @click="Logout"></u-cell-item>
</u-cell-group>
<view class="enter-list">
<view class="enter-item" @click="goInto('myApply')">
<image class="left-icon" src="../../static/my/wodeshenqing.png" mode=""></image>
<text class="title-text">我的申请</text>
<uni-icons size="13" color="#b9b9b9" class="right-icon" type="right"></uni-icons>
</view>
<view class="enter-item" @click="goInto('daiban')">
<image class="left-icon" src="../../static/my/wodeshenpi.png" mode=""></image>
<text class="title-text">我的审批</text>
<uni-icons size="13" color="#b9b9b9" class="right-icon" type="right"></uni-icons>
</view>
<view class="enter-item" @click="goInto('myData')">
<image style="width: 34rpx;height: 30rpx;" class="left-icon" src="../../static/my/wodeziliao.png"
mode=""></image>
<text class="title-text">我的资料</text>
<uni-icons size="13" color="#b9b9b9" class="right-icon" type="right"></uni-icons>
</view>
</view>
<view class="sign-out">
<button type="default" @click="signoutFn" class="sign-out-btn">退出</button>
</view>
</view>
</template>
@ -65,65 +51,362 @@
export default {
data() {
return {
pic:'https://uviewui.com/common/logo.png',
show:true
username: '用户名',
mobile: '1478585',
head: '',
userName: '',
userId: '',
getBusinessTripDayTimeCon: '',
getLeaveTimePaidLeaveCon: '',
getLeaveTimeCon: '',
myTopBgSrc: require("../../static/my/my-bg.jpg"),
imageUrl: '',
isHaveLookApply: false,
annualLeaveDay: 0.00, //
}
},
onLoad() {
onShow() {
// this.getUserInfo();
//
// this.getBusinessTripDayTimeFn();
//
// this.getLeaveTimeFn();
// ()
// this.getLeaveTimePaidLeaveFn();
//
// this._getSystemHomePageTabChart();
},
methods: {
Logout(){
this.$u.api.unbindmp().then(res=>{
this.$u.vuex('vuex_token', '')
uni.redirectTo({
url: '/pages/login/login'
});
}
)
/* 查询年假剩余天数 */
_getSystemHomePageTabChart() {
systemHomePageTabChart().then((res) => {
if (res.statusCode === 200) {
if (res.data.data !== undefined && res.data.data !== null && res.data.data !== "") {
this.annualLeaveDay = res.data.data.annualLeaveDay || 0.00;
} else {
this.annualLeaveDay = 0.00;
}
} else {
this.annualLeaveDay = 0.00;
uni.showToast({
title: res.data.message,
icon: 'none'
})
}
}).catch(() => {
this.annualLeaveDay = 0.00
uni.showToast({
title: '网络异常, 请求失败',
icon: 'none'
})
})
},
bindMP(){
let data = {openid: uni.getStorageSync('wxmp_openid')}
this.$u.api.bindmp(data).then(res=>{})
// uni.login({
// provider: 'weixin',
// success: (loginRes)=>{
// this.$u.api.bindmp({code:loginRes.code}).then(res=>{
// this.$u.toast('');
// this.$u.vuex('vuex_user.wxmp_openid', res.data.wxmp_openid)
// uni.reLaunch({
// url:'/pages/my/my'
// })
// }).catch(e=>{})
// }
// });
getLeaveTimePaidLeaveFn() {
getLeaveTimePaidLeave().then(res => {
if (res.statusCode === 200) {
this.getLeaveTimePaidLeaveCon = res.data.data.b_leave_days;
} else {
uni.showToast({
title: '获取用户累计请假天数失败',
icon: 'none'
})
}
}).catch(err => {
uni.showToast({
title: '请求失败',
icon: 'none'
})
})
},
getLeaveTimeFn() {
getLeaveTime().then(res => {
if (res.statusCode === 200) {
this.getLeaveTimeCon = res.data.data.b_leave_days;
} else {
uni.showToast({
title: '获取用户累计调休天数失败',
icon: 'none'
})
}
}).catch(err => {
uni.showToast({
title: '请求失败',
icon: 'none'
})
})
},
getBusinessTripDayTimeFn() {
getBusinessTripDayTime().then(res => {
if (res.statusCode === 200) {
this.getBusinessTripDayTimeCon = res.data.data.b_leave_days;
} else {
uni.showToast({
title: '获取用户累计出差天数失败',
icon: 'none'
})
}
}).catch(err => {
uni.showToast({
title: '请求失败',
icon: 'none'
})
})
},
goInto(type) {
if (type == "myApply") {
uni.navigateTo({
url: '/pages/profile/my_apply/my_apply'
})
}
if (type == "daiban") {
uni.navigateTo({
url: '/pages/index/daiban_management/daiban_management'
})
}
if (type == "myData") {
uni.navigateTo({
url: '/pages/my/myInfo'
})
}
if (type == "problem") {
uni.navigateTo({
url: '/pages/profile/common_problem/common_problem'
})
}
},
getUserInfo() {
var promise;
var that = this;
promise = new Promise(function(resolve, reject) {
authUser().then(res => {
if (res.statusCode === 200) {
const principal = res.data.principal;
that.username = principal.realname;
that.mobile = principal.mobile || '';
that.userName = principal.username;
that.userId = principal.userId;
that.$store.commit("SET_AUTHORITIES", res.data.authorities);
//
// this.wxUserImg(principal.username);
resolve()
} else {
uni.showToast({
title: '获取用户信息失败',
icon: 'none'
})
}
}).catch(err => {
uni.showToast({
title: 'user请求失败',
icon: 'none'
})
})
})
promise.then(function() {
userConnection(that.userName).then(res => {
that.imageUrl = res.data.data.imageUrl;
}).catch(err => {
uni.showToast({
title: '微信头像请求失败',
icon: 'none'
})
})
//
getCurrentUserRoute(that.userName).then(res => {
if (res.statusCode === 200) {
const routes = res.data.data.routes;
const obj = routes.find(item => {
return item.path === '/new_apply_approval'
})
if (obj) {
that.isHaveLookApply = Boolean(obj.children.find(item => {
return item.path === 'look_apply'; //
}))
}
} else {
uni.showToast({
title: '获取当前用户路由失败',
icon: 'none'
})
}
}).catch(err => {
uni.showToast({
title: '获取路由失败',
icon: 'none'
})
})
})
},
signoutFn() {
var that = this;
this.$u.api.loginOut().then(()=>{
that.$u.vuex('vuex_token', null);
uni.reLaunch({
url:'/pages/login/login_'
})
})
}
}
}
</script>
<style lang="scss">
page{
background-color: #ededed;
}
.camera{
width: 54px;
height: 44px;
&:active{
background-color: #ededed;
}
}
.user-box{
background-color: #fff;
padding-top:24rpx;
}
.avatarImg {
width: 148rpx;
height: 148rpx;
border-radius: 20rpx;
overflow: hidden;
<style>
page {
background-color: #f3fbff;
}
</style>
<style scoped>
.profile {
position: relative;
background-color: #f3fbff;
padding-bottom: 70rpx;
}
.nav-bar {
height: 210rpx;
background-color: #2cade8;
color: #FFFFFF;
display: flex;
align-items: center;
}
.user-info {
width: 680rpx;
height: 122rpx;
display: flex;
align-items: center;
margin: 0 auto;
}
.user-head {
width: 114rpx;
height: 114rpx;
border-radius: 50%;
overflow: hidden;
margin-right: 30rpx;
}
.user-head image {
width: 114rpx;
height: 114rpx;
}
.user-name {
font-family: PingFang-SC-Bold;
font-size: 34rpx;
color: #666666;
}
.user-phone {
font-family: AdobeHeitiStd-Regular;
font-size: 22rpx;
color: #b7d3fa;
}
.modify-info {
width: 136rpx;
height: 50rpx;
background-image: linear-gradient(253deg, #febe3d 0%, #ff890a 100%);
border-radius: 25rpx;
font-family: PingFang-SC-Medium;
font-size: 24rpx !important;
line-height: 50rpx;
padding-right: 0rpx;
padding-left: 0rpx;
color: #ffffff;
margin-right: 0rpx;
}
.num-info {
display: flex;
justify-content: space-around;
align-items: center;
width: 720rpx;
height: 199rpx;
background-color: #ffffff;
box-shadow: 0rpx 0rpx 24rpx 0rpx rgba(101, 176, 249, 0.41);
border-radius: 10rpx;
margin: 0 auto;
margin-top: -130rpx;
text-align: center;
}
.num-content {
font-size: 40rpx;
color: #2c6fd9;
font-weight: bold;
}
.text-content {
font-family: PingFang-SC-Medium;
font-size: 26rpx;
color: #333333;
}
.enter-list {
padding: 0 11rpx;
box-sizing: border-box;
width: 720rpx;
/* height: 405rpx; */
background-color: #ffffff;
border-radius: 10rpx;
margin: 0 auto;
margin-top: 28rpx;
}
.enter-item {
position: relative;
border-bottom: 1rpx solid #f8f8f8;
}
.title-text {
margin-left: 78rpx;
line-height: 102rpx;
font-family: PingFang-SC-Medium;
font-size: 28rpx;
color: #666666;
}
.enter-item .left-icon {
width: 29rpx;
height: 32rpx;
position: absolute;
top: 50%;
left: 26rpx;
transform: translateY(-50%);
}
.enter-item .right-icon {
position: absolute;
top: 50%;
right: 20rpx;
transform: translateY(-50%);
font-size: 36rpx !important;
}
.sign-out-btn {
width: 711rpx;
height: 90rpx;
background-color: #ffffff;
border-radius: 10rpx;
margin: 0 auto;
margin-top: 28rpx;
font-family: PingFang-SC-Medium;
font-size: 28rpx;
line-height: 90rpx;
color: #d30101;
}
.sign-out-btn:after {
border: none !important;
}
</style>

233
pages/my/myInfo.vue Normal file
View File

@ -0,0 +1,233 @@
<template>
<view class="my-data">
<uni-nav-bar @clickLeft="goBack()" class="nav-bar" height="110rpx" leftWidth="200rpx" leftText="个人信息"
leftIcon="left" border backgroundColor="#2cade8" color="#fff" fixed statusBar shadow></uni-nav-bar>
<view class="wrap-view">
<view class="item">
<view class="title">所属部门</view>
<picker class="content" mode="selector" :range="deptRange" @change="deptChange" range-key="name">
<view class="">
{{deptGender}}
</view>
</picker>
</view>
</view>
<view class="wrap-view">
<view class="item">
<view class="title">姓名</view>
<view class="content">
<input type="text" v-model="principal.mobile" maxlength="20" placeholder="请输入" />
</view>
</view>
<view class="item">
<view class="title">手机号</view>
<view class="content">
<input type="text" v-model="principal.mobile" maxlength="20" placeholder="请输入" />
</view>
</view>
<view class="item">
<view class="title">身份证号</view>
<view class="content">
<input type="text" v-model="principal.mobile" maxlength="20" placeholder="请输入" />
</view>
</view>
<view class="item">
<view class="title">人员编号</view>
<view class="content">
<input type="text" v-model="principal.mobile" maxlength="20" placeholder="请输入" />
</view>
</view>
<view class="item">
<view class="title">性别</view>
<picker class="content" mode="selector" :range="genderRange" @change="genderChange" range-key="name">
<view class="">
{{selectedGender}}
</view>
</picker>
</view>
<view class="item">
<view class="title">邮箱</view>
<view class="content">
<input type="text" v-model="principal.email" maxlength="20" placeholder="请输入" />
</view>
</view>
<view class="item" style="height: fit-content;">
<view class="title">证件照</view>
<view style="flex: 3;">
<uni-file-picker
v-model="principal.mobile"
file-mediatype="image"
mode="grid"
file-extname="png,jpg"
:limit="5"
ref="files"
:auto-upload="false"
@select="select"
/>
</view>
</view>
</view>
<view class="btn">
<button type="default" class="save-btn">保存</button>
</view>
</view>
</template>
<script>
export default {
data() {
return {
principal: {},
realname: "",
userId: "",
mobile: "",
selectedGender: '男',
genderRange: [{
id: 0,
name: '男'
},
{
id: 1,
name: '女'
}
],
deptGender: '设计部',
deptRange: [{
id: 10,
name: '设计部'
},
{
id: 11,
name: '生产部'
}
]
}
},
onShow() {
// this.getUserInfo();
},
methods: {
getUserInfo() {
authUser().then((res) => {
if (res.statusCode === 200) {
const principal = res.data.principal;
this.principal = principal;
this.realname = principal.realname;
this.userId = principal.userId;
this.mobile = principal.mobile || '';
} else {
this.principal = {};
this.realname = "";
this.userId = "";
this.mobile = "";
uni.showToast({
title: '获取用户信息失败',
icon: 'none'
})
}
}).catch(() => {
this.principal = {};
this.realname = "";
this.userId = "";
this.mobile = "";
uni.showToast({
title: '请求失败',
icon: 'none'
})
})
},
goBack() {
uni.navigateBack({
delta: 1
})
},
genderChange(e) {
const idx = e.detail.value;
this.selectedGender = this.genderRange[idx].name;
},
deptChange(e) {
const idx = e.detail.value;
this.deptGender = this.deptRange[idx].name;
},
}
}
</script>
<style scoped>
>>>.uni-navbar__header,>>>.uni-status-bar {
background-image: linear-gradient(254deg,
#0ca7ee 0%,
#005aff 100%,
#2a8cff 100%,
#54bdff 100%),
linear-gradient(#e60012,
#e60012);
}
.my-data {
background-color: #f3fbff;
padding-bottom: 227rpx;
}
.nav-bar>>>.uni-navbar-btn-text text {
font-size: 32rpx !important;
}
.wrap-view {
width: 720rpx;
margin: 0 auto;
background-color: #ffffff;
border-radius: 10rpx;
line-height: 94rpx;
font-family: PingFang-SC-Medium;
font-size: 30rpx;
}
.item {
border-bottom: 1rpx solid #eeeeee;
margin: 0rpx 32rpx;
display: flex;
margin-top: 20rpx;
}
.title {
color: #212121;
flex: 1;
}
.content {
flex: 3;
color: #414141;
}
.content input {
height: 100%;
}
.save-btn {
width: 400rpx;
height: 80rpx;
background-color: #2c6fd9;
border-radius: 40rpx;
font-size: 30rpx;
line-height: 80rpx;
color: #f3fbff;
margin-top: 21rpx;
}
</style>

101
pages/my/my_.vue Normal file
View File

@ -0,0 +1,101 @@
<template>
<view>
<view class="u-flex user-box u-p-l-30 u-p-r-20 u-p-b-30">
<view class="u-m-r-10">
<!-- #ifdef MP-WEIXIN -->
<view class="avatarImg">
<open-data type="userAvatarUrl" default-avatar="/static/other/timg.jpg"></open-data>
</view>
<!-- #endif -->
<!-- #ifndef MP-WEIXIN -->
<u-avatar :src="vuex_user.avatar" size="140"></u-avatar>
<!-- #endif -->
</view>
<view class="u-flex-1">
<view class="u-font-18 u-p-b-20">
{{vuex_user.name}}
<u-tag text="企业员工" v-if="vuex_user.type == 'employee'"/>
<u-tag text="相关方" v-if="vuex_user.type == 'remployee'"/>
<u-tag text="访客" v-if="vuex_user.type == 'visitor'"/>
</view>
<view class="u-font-14 u-type-info">{{vuex_user.username}}-{{vuex_user.belong_dept_name}}-{{vuex_user.post_name}}</view>
<view class="u-font-14 u-type-info" v-if="vuex_user.wxmp_openid">已绑定微信小程序</view>
<view class="u-font-14 u-type-info" v-if="vuex_user.wx_openid">已绑定公众号通知</view>
</view>
</view>
<view class="u-m-t-20">
<u-cell-group>
<u-cell-item icon="weixin-fill" title="绑定微信" :arrow="false" @click="bindMP" v-if="!vuex_user.wxmp_openid"></u-cell-item>
<u-cell-item icon="close" title="退出账号" @click="Logout"></u-cell-item>
</u-cell-group>
</view>
</view>
</template>
<script>
export default {
data() {
return {
pic:'https://uviewui.com/common/logo.png',
show:true
}
},
onLoad() {
},
methods: {
Logout(){
this.$u.api.unbindmp().then(res=>{
this.$u.vuex('vuex_token', '')
uni.redirectTo({
url: '/pages/login/login'
});
}
)
},
bindMP(){
let data = {openid: uni.getStorageSync('wxmp_openid')}
this.$u.api.bindmp(data).then(res=>{})
// uni.login({
// provider: 'weixin',
// success: (loginRes)=>{
// this.$u.api.bindmp({code:loginRes.code}).then(res=>{
// this.$u.toast('');
// this.$u.vuex('vuex_user.wxmp_openid', res.data.wxmp_openid)
// uni.reLaunch({
// url:'/pages/my/my'
// })
// }).catch(e=>{})
// }
// });
}
}
}
</script>
<style lang="scss">
page{
background-color: #ededed;
}
.camera{
width: 54px;
height: 44px;
&:active{
background-color: #ededed;
}
}
.user-box{
background-color: #fff;
padding-top:24rpx;
}
.avatarImg {
width: 148rpx;
height: 148rpx;
border-radius: 20rpx;
overflow: hidden;
}
</style>
c

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,784 @@
<template>
<view class="workbench">
<view style="position: relative;overflow: hidden;">
<view style="position: absolute;top:0;left:0;bottom:0;right:0;height: 290rpx;background-image: url(../../static/workSpace/bgimg.png);background-position: center bottom;background-size: 100%;">
</view>
<view class="top-title" style="display: flex;">
<block v-for="(item,index) in routerList" :key="item.index">
<!-- <view class="title-item" v-if="item.children">
<view class="title-icon" >
<image :src="require('@/static/worSpace/'+item.icon+'')" mode="widthFix"></image>
</view>
<text class="title-text" >{{item.name}}</text>
<picker mode="selector" :range="item.childItems" @change="intoAddPage($event,item.childUrls)" range-key="name">
<view class="workbench-picker">
{{name}}
</view>
</picker>
</view> -->
<view class="title-item" @click="goInto(index)">
<view class="title-icon">
<image :src="require('@/static/workSpace/'+item.icon+'')" mode="widthFix"></image>
</view>
<text class="title-text">{{item.name}}</text>
</view>
</block>
</view>
</view>
<view style="height: 22rpx;">
</view>
<view class="my-apply">
<view class="title">
<view class="">
<image src="../../static/home/daiban.png" mode="widthFix" class="img"></image>
<text class="title-text-left">作业管理</text>
</view>
<view class="" @click="goIntoMoreApply()">
<text class="title-text-right">查看更多</text>
<uni-icons type="right" :size="15" color="#ababab"></uni-icons>
</view>
</view>
<view class="line"></view>
<view class="apply-item" v-for="(val,index) in myApplyArray" :key="val.pkId" @click="intoUpdataPage(val)">
<view style="display: flex;">
<view class="apply-title">
{{val.itemName}}
</view>
<view class="apply-status" :style="{color: val.statusColor}">
{{val.eventStatusValue}}
</view>
<!-- <image src="../../static/logo.png" mode="" class="image"></image> -->
</view>
<view class="apply-content">
所属模块{{val.menuName}}
</view>
<view style="display: flex;">
<view class="apply-content">
申请人{{val.applicantName}}
</view>
<view class="apply-time">
{{val.submissionTime}}
</view>
</view>
</view>
</view>
<view class="my-apply">
<view class="title">
<view class="">
<image src="../../static/home/daiban.png" mode="widthFix" class="img"></image>
<text class="title-text-left">入场项目</text>
</view>
<view class="" @click="goIntoMoreApply()">
<text class="title-text-right">查看更多</text>
<uni-icons type="right" :size="15" color="#ababab"></uni-icons>
</view>
</view>
<view class="line"></view>
<view class="apply-item" v-for="(val,index) in myApplyArray" :key="val.pkId" @click="intoUpdataPage(val)">
<view style="display: flex;">
<view class="apply-title">
{{val.itemName}}
</view>
<view class="apply-status" :style="{color: val.statusColor}">
{{val.eventStatusValue}}
</view>
<!-- <image src="../../static/logo.png" mode="" class="image"></image> -->
</view>
<view class="apply-content">
所属模块{{val.menuName}}
</view>
<view style="display: flex;">
<view class="apply-content">
申请人{{val.applicantName}}
</view>
<view class="apply-time">
{{val.submissionTime}}
</view>
</view>
</view>
</view>
<view class="my-apply">
<view class="title">
<view class="">
<image src="../../static/home/daiban.png" mode="widthFix" class="img"></image>
<text class="title-text-left">来访项目</text>
</view>
<view class="" @click="goIntoMoreApply()">
<text class="title-text-right">查看更多</text>
<uni-icons type="right" :size="15" color="#ababab"></uni-icons>
</view>
</view>
<view class="line"></view>
<view class="apply-item" v-for="(val,index) in myApplyArray" :key="val.pkId" @click="intoUpdataPage(val)">
<view style="display: flex;">
<view class="apply-title">
{{val.itemName}}
</view>
<view class="apply-status" :style="{color: val.statusColor}">
{{val.eventStatusValue}}
</view>
<!-- <image src="../../static/logo.png" mode="" class="image"></image> -->
</view>
<view class="apply-content">
所属模块{{val.menuName}}
</view>
<view style="display: flex;">
<view class="apply-content">
申请人{{val.applicantName}}
</view>
<view class="apply-time">
{{val.submissionTime}}
</view>
</view>
</view>
</view>
</view>
</template>
<script>
export default {
data() {
return {
name: "",
username:"",
routerList:[
{name:'作业管理',
icon:'specialmatter.png',
path:'index',
childItems : [
{
name: "请假申请"
},
{
name: "公出申请"
},
{
name: "出差申请"
},
{
name: "值班申请"
},
{
name: "未打卡说明"
}
],
childUrls : [
"/pages/workSpace/new_apply/del",
"/pages/workSpace/new_apply/del",
"/pages/workSpace/new_apply/del",
"/pages/workSpace/new_apply/del",
"/pages/workSpace/new_apply/del",
]},
{name:'入厂项目',icon:'hetong.png',path:'index'},
{name:'来访项目',icon:'renli.png',path:'index'},
],
myApplyArray: [],
mytopimg: require("@/static/workSpace/bgimg-top.jpg"),
}
},
onShow() {
// this._getMyApply();
// this.getUserInfo();
},
methods: {
goInto(index){
if (index == 0) {
uni.navigateTo({
url: '/pages/workSpace/newWork/work'
})
}else if (index == 1) {
uni.navigateTo({
url: '/pages/workSpace/newWork/relevant'
})
}else if (index == 2) {
uni.navigateTo({
url: '/pages/workSpace/newWork/visit'
})
}
},
getUserInfo() {
var promise;
var that = this;
promise = new Promise(function(resolve, reject) {
authUser().then(res => {
if (res.statusCode === 200) {
const principal = res.data.principal;
that.username = principal.username;
resolve()
} else {
uni.showToast({
title: '获取用户信息失败',
icon: 'none'
})
}
}).catch(err => {
uni.showToast({
title: 'user请求失败',
icon: 'none'
})
})
})
promise.then(function(){
//
getCurrentUserRoute(that.username).then(res => {
if (res.statusCode === 200) {
const routes = res.data.data.routes;
that.initList(routes);
} else {
uni.showToast({
title: '获取当前用户路由失败',
icon: 'none'
})
}
}).catch(err => {
uni.showToast({
title: '获取路由失败',
icon: 'none'
})
})
})
},
initList(routes){
const obj =routes.find(item=>{
return item.path === '/apply'
})
//
const project =routes.find(item=>{
return item.path === '/project_management'
})
//
const inform =routes.find(item=>{
return item.path === '/press'
})
let projectObj;
let informObj;
if(project){ //
projectObj = project.children.find(item=>{
return item.path == "hetongxinxi_shoukuan";
})
}
if(inform){ //
informObj = inform.children.find(item=>{
return item.path == "index";
})
}
if(obj){
const newObj = JSON.parse(JSON.stringify(obj));
let arr = newObj.children;
const index = arr.findIndex(item=>{
return item.path == "index";
});
if(index!==-1){
arr.splice(index,1); // index
}
if(informObj){
const newInformObj = JSON.parse(JSON.stringify(informObj));
arr.splice(arr.length,0,newInformObj); //
}
let htBackItem;
for(let val of arr){
if(val.path=="yewufeiyong"){
htBackItem = val;
break;
}
else if(val.path=="jiesuanguanli"){
htBackItem = val;
break;
}
else if(val.path=="index_detail_xinwen"){
htBackItem = val;
break;
}
else if(val.path=="special_matter"){
htBackItem = val;
break;
}
else if(val.path=="issue_report"){
htBackItem = val;
break;
}
else if(val.path=="index"){
htBackItem = val;
break;
}
}
if(projectObj){
const newProjectObj = JSON.parse(JSON.stringify(projectObj));
newProjectObj.name = "创建合同";
if(htBackItem){
const backIndex = arr.findIndex(item=>{
return item==htBackItem;
})
if(backIndex!==-1){
arr.splice(backIndex,0,newProjectObj); //
}else{
arr.push(newProjectObj) //
}
} else{
arr.push(newProjectObj)
}
}
this.routerList = arr.map(item=>{
item.childItems =[];
item.childUrls =[];
item.icon = "kaoqin.png";
if(item.path=="kqgl"){
item.icon = "kaoqin.png";
item.childItems = [
{
name: "请假申请"
},
{
name: "公出申请"
},
{
name: "出差申请"
},
{
name: "值班申请"
},
{
name: "未打卡说明"
}
];
item.childUrls = [
"/pages/workSpace/new_apply/kaoqin_management/qingjia_apply",
"/pages/workSpace/new_apply/kaoqin_management/gongchu_apply",
"/pages/workSpace/new_apply/kaoqin_management/chuchai_apply",
"/pages/workSpace/new_apply/kaoqin_management/zhiban_apply",
"/pages/workSpace/new_apply/kaoqin_management/weidaka_apply",
]
}
else if(item.path=="cl"){
item.icon = "cheliang.png";
item.childItems = [
{
name: "车辆维修、保养"
},
{
name: "私车公用申请"
},
{
name: "车辆使用登记"
},
];
item.childUrls = [
"/pages/workSpace/new_apply/car_management/repair_car_apply",
"/pages/workSpace/new_apply/car_management/private_car_public",
"/pages/workSpace/new_apply/car_management/paicheshenqing",
]
}
else if(item.path=="cg"){
item.icon = "caigou.png";
item.childItems = [
{
name: "印刷品清单"
},
{
name: "办公用品采购申请表"
},
{
name: "固定资产采购申请表"
},
{
name: "低值易耗品购置申请表"
}
];
item.childUrls = [
"/pages/workSpace/new_apply/caigou_management/print_list_apply",
"/pages/workSpace/new_apply/caigou_management/office_supplies_apply",
"/pages/workSpace/new_apply/caigou_management/fixed_assets_apply",
"/pages/workSpace/new_apply/caigou_management/low_value_products_apply"
];
}
else if(item.path=="gdzc"){
item.icon = "fixedassets.png";
item.childItems = [
{
name: "验收记录"
},
{
name: "内部调拨记录表"
},
{
name: "报废申请表"
},
{
name: "维修申请表"
}
];
item.childUrls = [
"/pages/workSpace/new_apply/fixed_assets_management/yanshoujilu",
"/pages/workSpace/new_apply/fixed_assets_management/neibu_diaobo_apply",
"/pages/workSpace/new_apply/fixed_assets_management/baofeishenqing",
"/pages/workSpace/new_apply/fixed_assets_management/weixiushenqing"
];
}
else if(item.path=="jiesuanguanli"){
item.icon = "jiesuan.png";
}
else if(item.path=="xinziguanli"){
item.icon = "xinzi.png";
}
else if(item.path=="yewufeiyong"){
item.icon = "yewu.png";
}
else if(item.path=="hetongxinxi_shoukuan"){
item.icon = "hetong.png";
}
else if(item.path=="yzgl"){
item.icon = "yinzhang.png";
item.childItems = [
{
name: "刻章申请表"
},
{
name: "重要文件/印鉴借用"
},
{
name:'销毁印鉴申请表'
},
{
name: "印章申请表"
}
];
item.childUrls = [
"/pages/workSpace/new_apply/yinzhang__management/kedushenqingbiao",
"/pages/workSpace/new_apply/yinzhang__management/zhongyaowenjian",
"/pages/workSpace/new_apply/yinzhang__management/xiaohuiyinjian",
"/pages/workSpace/new_apply/yinzhang__management/yinzhangshenqingbiao"
];
}
else if(item.path=="zdwj"){
item.name = "制度文件";
item.icon = "zhidu.png";
item.childItems = [
{
name: "红头文件审批"
},
{
name: "红头文件审批(涉及财务)"
},
];
item.childUrls = [
"/pages/workSpace/new_apply/zhiduwenjian_management/hongtouwenjian",
"/pages/workSpace/new_apply/zhiduwenjian_management/hongtouwenjian_cw"
];
}
else if(item.path=="issue_report"){
item.icon = "fafang.png"
}
else if(item.path=="special_matter"){
item.icon = "specialmatter.png"
}
else if(item.path=="index"){
item.name = "通知公告";
item.icon = "tongzhigonggao.png"
}
return item;
})
}
},
/* 跳转详情页 */
intoUpdataPage(val) {
this.$store.commit("clearAllStoreData"); /* 清空选择人员时留存的数据 */
const routeObj = routeArray.find(item => {
return item.pcRoute == val.menuID;
})
const params = `?pkId=${val.pkId}&itemId=${val.itemId}&execId=${val.execId}&eventStatus=${val.eventStatus}&detail=${true}`;
uni.navigateTo({
url: routeObj.appAdd + params,
})
},
/* 获取列表数据 */
_getMyApply() {
getMyApply().then(res => {
if (res.statusCode === 200) {
let list = res.data.data.rows;
if (list && list.length > 0) {
list = list.slice(0, 3);
}
list = list.map(item => {
if (!item.submissionTime) {
item.submissionTime = "";
}
if (item.eventStatus == 3) { //
item.statusColor = '#2c6fd9';
}
if (item.eventStatus == 1) { //
item.statusColor = '#15a306';
}
if (item.eventStatus == 0) { //退
item.statusColor = '#e2053e';
}
return item;
});
this.myApplyArray = list;
} else {
this.myApplyArray = [];
uni.showToast({
title: res.data.message,
icon: 'none'
})
}
}).catch(err => {
this.myApplyArray = [];
uni.showToast({
title: '网络异常, 请求失败',
icon: 'none'
})
})
},
/* -----------------顶部模块页面跳转-----------------------------------------------*/
/* 没有子页面的模块 */
goSingleIntoPage(path) {
let url = "";
switch (path) {
case 'index':
url = '/pages/workbench/new_apply/xinwen_management/xinwen';
break;
}
uni.navigateTo({
url
})
},
/* 存在子页面的模块 。顺序与上边文字顺序一一对应*/
intoAddPage(e, urls) {
const i = parseInt(e.target.value);
let url = urls[i];
uni.navigateTo({
url
})
},
goIntoMoreApply() {
uni.navigateTo({
url: '/pages/profile/my_apply/my_apply'
})
}
}
}
</script>
<style scoped>
.my-nav-bar {}
.workbench-picker {
width: 100%;
height: 100%;
position: absolute;
top: 0;
left: 0;
background-color: transparent;
color: transparent;
}
.workbench {
position: relative;
background-color: #edf8ff;
padding-bottom: 17rpx;
}
.nav-bar {
height: 401rpx;
background-color: #2cade8;
background-size: cover;
color: #FFFFFF;
padding-top: 26rpx;
padding-left: 18rpx;
}
.nav-bar-text {
font-size: 38rpx;
color: #ffffff;
font-weight: 400;
}
.top-title {
width: 720rpx;
height: auto;
background-color: #FFFFFF;
border-radius: 10rpx;
margin-top:190rpx;
margin-left:50%;
transform: translateX(-50%);
display: flex;
justify-content: space-around;
flex-wrap: wrap;
padding-bottom: 20rpx;
}
.title-item {
width: 20%;
text-align: center;
padding-top: 20rpx;
box-sizing: border-box;
position: relative;
}
.title-icon image {
width: 77rpx;
border-radius: 50%;
}
.title-text {
font-size: 26rpx;
color: #383838;
}
.empty-view {
height: 390rpx;
}
.my-apply {
width: 720rpx;
margin: 0 auto;
border-radius: 10rpx;
}
.line {
width: 660rpx;
height: 1rpx;
background-color: #eeeeee;
margin: 0 auto;
}
.my-apply .title {
display: flex;
justify-content: space-between;
padding: 21rpx 21rpx;
background-color: #FFFFFF;
}
.my-apply .title .img {
width: 30rpx;
height: 30rpx;
margin-right: 10rpx;
}
.my-apply .title-text-left {
font-family: PingFang-SC-Medium;
font-size: 34rpx;
line-height: 72rpx;
letter-spacing: 0rpx;
color: #383838;
}
.my-apply .title-text-right {
font-family: PingFang-SC-Medium;
font-size: 24rpx;
line-height: 72rpx;
letter-spacing: 0rpx;
color: #ababab;
margin-right: 10rpx;
}
.apply-item {
line-height: 50rpx;
padding: 0 21rpx;
margin-bottom: 17rpx;
background-color: #FFFFFF;
}
.apply-item .image {
width: 55rpx;
height: 55rpx;
border-radius: 50%;
vertical-align: middle;
}
.apply-item .apply-title {
font-family: PingFang-SC-Medium;
font-size: 30rpx;
line-height: 72rpx;
letter-spacing: -2rpx;
color: #3d3d3d;
margin-left: 15rpx;
margin-right: 20rpx;
display: -webkit-box;
overflow: hidden;
text-overflow: ellipsis;
-webkit-box-orient: vertical;
-webkit-line-clamp: 1;
flex: 1;
}
.apply-item .apply-status {
font-family: PingFang-SC-Medium;
font-size: 26rpx;
line-height: 72rpx;
letter-spacing: -2rpx;
color: #2c6fd9;
}
.apply-item .apply-time {
font-family: PingFang-SC-Regular;
font-size: 24rpx;
letter-spacing: 0rpx;
color: #ababab;
}
.apply-item .apply-content {
flex: 1;
font-size: 28rpx;
letter-spacing: -2rpx;
margin-left: 15rpx;
color: #5b5b5b;
display: -webkit-box;
overflow: hidden;
text-overflow: ellipsis;
-webkit-box-orient: vertical;
-webkit-line-clamp: 1;
}
</style>

BIN
static/home/bgimg-top.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

BIN
static/home/daiban.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 533 B

BIN
static/home/gonggao02.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

BIN
static/home/searchIcon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

BIN
static/home/tongzhi.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 506 B

BIN
static/login/avatar.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 568 B

BIN
static/login/my-bg.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 131 KiB

BIN
static/login/my-code.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

BIN
static/login/password.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 596 B

BIN
static/login/weixin.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

BIN
static/my/my-bg.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

BIN
static/my/wodeshenpi.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

BIN
static/my/wodeshenqing.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

BIN
static/my/wodeziliao.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 898 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 886 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
static/tabbar/shouye.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
static/tabbar/wode.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

BIN
static/workSpace/bgimg.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 72 KiB

BIN
static/workSpace/hetong.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 465 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

BIN
static/workSpace/renli.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

View File

@ -33,9 +33,10 @@ const store = new Vuex.Store({
// 加上vuex_前缀是防止变量名冲突也让人一目了然
vuex_user: lifeData.vuex_user ? lifeData.vuex_user : {},
vuex_token: lifeData.vuex_token ? lifeData.vuex_token : '',
vuex_host: 'http://127.0.0.1:8000',
vuex_refresh: lifeData.vuex_refresh ? lifeData.vuex_refresh : '',
vuex_host: 'http://1.203.161.103:2800',
//vuex_api: 'http://47.95.0.242:9101/api',
vuex_api: 'http://127.0.0.1:8000/api',
vuex_api: 'http://1.203.161.103:2800/api',
// vuex_apifile: 'http://127.0.0.1:8000/api/file/',
// vuex_host: 'https://testsearch.ctc.ac.cn',

View File

@ -0,0 +1,64 @@
## 1.0.72022-07-06
- 优化 pc端图标位置不正确的问题
## 1.0.62022-07-05
- 优化 显示样式
## 1.0.52022-07-04
- 修复 uni-data-picker 在 uni-forms-item 中宽度不正确的bug
## 1.0.42022-04-19
- 修复 字节小程序 本地数据无法选择下一级的Bug
## 1.0.32022-02-25
- 修复 nvue 不支持的 v-show 的 bug
## 1.0.22022-02-25
- 修复 条件编译 nvue 不支持的 css 样式
## 1.0.12021-11-23
- 修复 由上个版本引发的map、v-model等属性不生效的bug
## 1.0.02021-11-19
- 优化 组件 UI并提供设计资源详见:[https://uniapp.dcloud.io/component/uniui/resource](https://uniapp.dcloud.io/component/uniui/resource)
- 文档迁移,详见:[https://uniapp.dcloud.io/component/uniui/uni-data-picker](https://uniapp.dcloud.io/component/uniui/uni-data-picker)
## 0.4.92021-10-28
- 修复 VUE2 v-model 概率无效的 bug
## 0.4.82021-10-27
- 修复 v-model 概率无效的 bug
## 0.4.72021-10-25
- 新增 属性 spaceInfo 服务空间配置 HBuilderX 3.2.11+
- 修复 树型 uniCloud 数据类型为 int 时报错的 bug
## 0.4.62021-10-19
- 修复 非 VUE3 v-model 为 0 时无法选中的 bug
## 0.4.52021-09-26
- 新增 清除已选项的功能(通过 clearIcon 属性配置是否显示按钮),同时提供 clear 方法以供调用,二者等效
- 修复 readonly 为 true 时报错的 bug
## 0.4.42021-09-26
- 修复 上一版本造成的 map 属性失效的 bug
- 新增 ellipsis 属性,支持配置 tab 选项长度过长时是否自动省略
## 0.4.32021-09-24
- 修复 某些情况下级联未触发的 bug
## 0.4.22021-09-23
- 新增 提供 show 和 hide 方法,开发者可以通过 ref 调用
- 新增 选项内容过长自动添加省略号
## 0.4.12021-09-15
- 新增 map 属性 字段映射,将 text/value 映射到数据中的其他字段
## 0.4.02021-07-13
- 组件兼容 vue3如何创建 vue3 项目,详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834)
## 0.3.52021-06-04
- 修复 无法加载云端数据的问题
## 0.3.42021-05-28
- 修复 v-model 无效问题
- 修复 loaddata 为空数据组时加载时间过长问题
- 修复 上个版本引出的本地数据无法选择带有 children 的 2 级节点
## 0.3.32021-05-12
- 新增 组件示例地址
## 0.3.22021-04-22
- 修复 非树形数据有 where 属性查询报错的问题
## 0.3.12021-04-15
- 修复 本地数据概率无法回显时问题
## 0.3.02021-04-07
- 新增 支持云端非树形表结构数据
- 修复 根节点 parent_field 字段等于 null 时选择界面错乱问题
## 0.2.02021-03-15
- 修复 nodeclick、popupopened、popupclosed 事件无法触发的问题
## 0.1.92021-03-09
- 修复 微信小程序某些情况下无法选择的问题
## 0.1.82021-02-05
- 优化 部分样式在 nvue 上的兼容表现
## 0.1.72021-02-05
- 调整为 uni_modules 目录规范

View File

@ -0,0 +1,45 @@
// #ifdef H5
export default {
name: 'Keypress',
props: {
disable: {
type: Boolean,
default: false
}
},
mounted () {
const keyNames = {
esc: ['Esc', 'Escape'],
tab: 'Tab',
enter: 'Enter',
space: [' ', 'Spacebar'],
up: ['Up', 'ArrowUp'],
left: ['Left', 'ArrowLeft'],
right: ['Right', 'ArrowRight'],
down: ['Down', 'ArrowDown'],
delete: ['Backspace', 'Delete', 'Del']
}
const listener = ($event) => {
if (this.disable) {
return
}
const keyName = Object.keys(keyNames).find(key => {
const keyName = $event.key
const value = keyNames[key]
return value === keyName || (Array.isArray(value) && value.includes(keyName))
})
if (keyName) {
// 避免和其他按键事件冲突
setTimeout(() => {
this.$emit(keyName, {})
}, 0)
}
}
document.addEventListener('keyup', listener)
this.$once('hook:beforeDestroy', () => {
document.removeEventListener('keyup', listener)
})
},
render: () => {}
}
// #endif

View File

@ -0,0 +1,554 @@
<template>
<view class="uni-data-tree">
<view class="uni-data-tree-input" @click="handleInput">
<slot :options="options" :data="inputSelected" :error="errorMessage">
<view class="input-value" :class="{'input-value-border': border}">
<text v-if="errorMessage" class="selected-area error-text">{{errorMessage}}</text>
<view v-else-if="loading && !isOpened" class="selected-area">
<uni-load-more class="load-more" :contentText="loadMore" status="loading"></uni-load-more>
</view>
<scroll-view v-else-if="inputSelected.length" class="selected-area" scroll-x="true">
<view class="selected-list">
<view class="selected-item" v-for="(item,index) in inputSelected" :key="index">
<text class="text-color">{{item.text}}</text><text v-if="index<inputSelected.length-1"
class="input-split-line">{{split}}</text>
</view>
</view>
</scroll-view>
<text v-else class="selected-area placeholder">{{placeholder}}</text>
<view v-if="clearIcon && !readonly && inputSelected.length" class="icon-clear"
@click.stop="clear">
<uni-icons type="clear" color="#c0c4cc" size="24"></uni-icons>
</view>
<view class="arrow-area" v-if="(!clearIcon || !inputSelected.length) && !readonly ">
<view class="input-arrow"></view>
</view>
</view>
</slot>
</view>
<view class="uni-data-tree-cover" v-if="isOpened" @click="handleClose"></view>
<view class="uni-data-tree-dialog" v-if="isOpened">
<view class="uni-popper__arrow"></view>
<view class="dialog-caption">
<view class="title-area">
<text class="dialog-title">{{popupTitle}}</text>
</view>
<view class="dialog-close" @click="handleClose">
<view class="dialog-close-plus" data-id="close"></view>
<view class="dialog-close-plus dialog-close-rotate" data-id="close"></view>
</view>
</view>
<data-picker-view class="picker-view" ref="pickerView" v-model="dataValue" :localdata="localdata"
:preload="preload" :collection="collection" :field="field" :orderby="orderby" :where="where"
:step-searh="stepSearh" :self-field="selfField" :parent-field="parentField" :managed-mode="true"
:map="map" :ellipsis="ellipsis" @change="onchange" @datachange="ondatachange" @nodeclick="onnodeclick">
</data-picker-view>
</view>
</view>
</template>
<script>
import dataPicker from "../uni-data-pickerview/uni-data-picker.js"
import DataPickerView from "../uni-data-pickerview/uni-data-pickerview.vue"
/**
* DataPicker 级联选择
* @description 支持单列和多列级联选择列数没有限制如果屏幕显示不全顶部tab区域会左右滚动
* @tutorial https://ext.dcloud.net.cn/plugin?id=3796
* @property {String} popup-title 弹出窗口标题
* @property {Array} localdata 本地数据参考
* @property {Boolean} border = [true|false] 是否有边框
* @property {Boolean} readonly = [true|false] 是否仅读
* @property {Boolean} preload = [true|false] 是否预加载数据
* @value true 开启预加载数据点击弹出窗口后显示已加载数据
* @value false 关闭预加载数据点击弹出窗口后开始加载数据
* @property {Boolean} step-searh = [true|false] 是否分布查询
* @value true 启用分布查询仅查询当前选中节点
* @value false 关闭分布查询一次查询出所有数据
* @property {String|DBFieldString} self-field 分布查询当前字段名称
* @property {String|DBFieldString} parent-field 分布查询父字段名称
* @property {String|DBCollectionString} collection 表名
* @property {String|DBFieldString} field 查询字段多个字段用 `,` 分割
* @property {String} orderby 排序字段及正序倒叙设置
* @property {String|JQLString} where 查询条件
* @event {Function} popupshow 弹出的选择窗口打开时触发此事件
* @event {Function} popuphide 弹出的选择窗口关闭时触发此事件
*/
export default {
name: 'UniDataPicker',
emits: ['popupopened', 'popupclosed', 'nodeclick', 'input', 'change', 'update:modelValue'],
mixins: [dataPicker],
components: {
DataPickerView
},
props: {
options: {
type: [Object, Array],
default () {
return {}
}
},
popupTitle: {
type: String,
default: '请选择'
},
placeholder: {
type: String,
default: '请选择'
},
heightMobile: {
type: String,
default: ''
},
readonly: {
type: Boolean,
default: false
},
clearIcon: {
type: Boolean,
default: true
},
border: {
type: Boolean,
default: true
},
split: {
type: String,
default: '/'
},
ellipsis: {
type: Boolean,
default: true
}
},
data() {
return {
isOpened: false,
inputSelected: []
}
},
created() {
this.form = this.getForm('uniForms')
this.formItem = this.getForm('uniFormsItem')
if (this.formItem) {
if (this.formItem.name) {
this.rename = this.formItem.name
this.form.inputChildrens.push(this)
}
}
this.$nextTick(() => {
this.load()
})
},
methods: {
clear() {
this.inputSelected.splice(0)
this._dispatchEvent([])
},
onPropsChange() {
this._treeData = []
this.selectedIndex = 0
this.load()
},
load() {
if (this.readonly) {
this._processReadonly(this.localdata, this.dataValue)
return
}
if (this.isLocaldata) {
this.loadData()
this.inputSelected = this.selected.slice(0)
} else if (!this.parentField && !this.selfField && this.hasValue) {
this.getNodeData(() => {
this.inputSelected = this.selected.slice(0)
})
} else if (this.hasValue) {
this.getTreePath(() => {
this.inputSelected = this.selected.slice(0)
})
}
},
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;
},
show() {
this.isOpened = true
setTimeout(() => {
this.$refs.pickerView.updateData({
treeData: this._treeData,
selected: this.selected,
selectedIndex: this.selectedIndex
})
}, 200)
this.$emit('popupopened')
},
hide() {
this.isOpened = false
this.$emit('popupclosed')
},
handleInput() {
if (this.readonly) {
return
}
this.show()
},
handleClose(e) {
this.hide()
},
onnodeclick(e) {
this.$emit('nodeclick', e)
},
ondatachange(e) {
this._treeData = this.$refs.pickerView._treeData
},
onchange(e) {
this.hide()
this.$nextTick(() => {
this.inputSelected = e;
})
this._dispatchEvent(e)
},
_processReadonly(dataList, value) {
var isTree = dataList.findIndex((item) => {
return item.children
})
if (isTree > -1) {
let inputValue
if (Array.isArray(value)) {
inputValue = value[value.length - 1]
if (typeof inputValue === 'object' && inputValue.value) {
inputValue = inputValue.value
}
} else {
inputValue = value
}
this.inputSelected = this._findNodePath(inputValue, this.localdata)
return
}
if (!this.hasValue) {
this.inputSelected = []
return
}
let result = []
for (let i = 0; i < value.length; i++) {
var val = value[i]
var item = dataList.find((v) => {
return v.value == val
})
if (item) {
result.push(item)
}
}
if (result.length) {
this.inputSelected = result
}
},
_filterForArray(data, valueArray) {
var result = []
for (let i = 0; i < valueArray.length; i++) {
var value = valueArray[i]
var found = data.find((item) => {
return item.value == value
})
if (found) {
result.push(found)
}
}
return result
},
_dispatchEvent(selected) {
let item = {}
if (selected.length) {
var value = new Array(selected.length)
for (var i = 0; i < selected.length; i++) {
value[i] = selected[i].value
}
item = selected[selected.length - 1]
} else {
item.value = ''
}
if (this.formItem) {
this.formItem.setValue(item.value)
}
this.$emit('input', item.value)
this.$emit('update:modelValue', item.value)
this.$emit('change', {
detail: {
value: selected
}
})
}
}
}
</script>
<style >
.uni-data-tree {
flex: 1;
position: relative;
font-size: 14px;
}
.error-text {
color: #DD524D;
}
.input-value {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: row;
align-items: center;
flex-wrap: nowrap;
font-size: 14px;
/* line-height: 35px; */
padding: 0 10px;
padding-right: 5px;
overflow: hidden;
height: 35px;
/* #ifdef APP-NVUE */
/* #endif */
box-sizing: border-box;
}
.input-value-border {
border: 1px solid #e5e5e5;
border-radius: 5px;
}
.selected-area {
flex: 1;
overflow: hidden;
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: row;
}
.load-more {
/* #ifndef APP-NVUE */
margin-right: auto;
/* #endif */
/* #ifdef APP-NVUE */
width: 40px;
/* #endif */
}
.selected-list {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: row;
flex-wrap: nowrap;
/* padding: 0 5px; */
}
.selected-item {
flex-direction: row;
/* padding: 0 1px; */
/* #ifndef APP-NVUE */
white-space: nowrap;
/* #endif */
}
.text-color {
color: #333;
}
.placeholder {
color: grey;
font-size: 12px;
}
.input-split-line {
opacity: .5;
}
.arrow-area {
position: relative;
width: 20px;
/* #ifndef APP-NVUE */
margin-bottom: 5px;
margin-left: auto;
display: flex;
/* #endif */
justify-content: center;
transform: rotate(-45deg);
transform-origin: center;
}
.input-arrow {
width: 7px;
height: 7px;
border-left: 1px solid #999;
border-bottom: 1px solid #999;
}
.uni-data-tree-cover {
position: fixed;
left: 0;
top: 0;
right: 0;
bottom: 0;
background-color: rgba(0, 0, 0, .4);
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: column;
z-index: 100;
}
.uni-data-tree-dialog {
position: fixed;
left: 0;
top: 20%;
right: 0;
bottom: 0;
background-color: #FFFFFF;
border-top-left-radius: 10px;
border-top-right-radius: 10px;
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: column;
z-index: 102;
overflow: hidden;
/* #ifdef APP-NVUE */
width: 750rpx;
/* #endif */
}
.dialog-caption {
position: relative;
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: row;
/* border-bottom: 1px solid #f0f0f0; */
}
.title-area {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
align-items: center;
/* #ifndef APP-NVUE */
margin: auto;
/* #endif */
padding: 0 10px;
}
.dialog-title {
/* font-weight: bold; */
line-height: 44px;
}
.dialog-close {
position: absolute;
top: 0;
right: 0;
bottom: 0;
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: row;
align-items: center;
padding: 0 15px;
}
.dialog-close-plus {
width: 16px;
height: 2px;
background-color: #666;
border-radius: 2px;
transform: rotate(45deg);
}
.dialog-close-rotate {
position: absolute;
transform: rotate(-45deg);
}
.picker-view {
flex: 1;
overflow: hidden;
}
.icon-clear {
display: flex;
align-items: center;
}
/* #ifdef H5 */
@media all and (min-width: 768px) {
.uni-data-tree-cover {
background-color: transparent;
}
.uni-data-tree-dialog {
position: absolute;
top: 55px;
height: auto;
min-height: 400px;
max-height: 50vh;
background-color: #fff;
border: 1px solid #EBEEF5;
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
border-radius: 4px;
overflow: unset;
}
.dialog-caption {
display: none;
}
.icon-clear {
/* margin-right: 5px; */
}
}
/* #endif */
/* picker 弹出层通用的指示小三角, todo扩展至上下左右方向定位 */
/* #ifndef APP-NVUE */
.uni-popper__arrow,
.uni-popper__arrow::after {
position: absolute;
display: block;
width: 0;
height: 0;
border-color: transparent;
border-style: solid;
border-width: 6px;
}
.uni-popper__arrow {
filter: drop-shadow(0 2px 12px rgba(0, 0, 0, 0.03));
top: -6px;
left: 10%;
margin-right: 3px;
border-top-width: 0;
border-bottom-color: #EBEEF5;
}
.uni-popper__arrow::after {
content: " ";
top: 1px;
margin-left: -6px;
border-top-width: 0;
border-bottom-color: #fff;
}
/* #endif */
</style>

View File

@ -0,0 +1,563 @@
export default {
props: {
localdata: {
type: [Array, Object],
default () {
return []
}
},
spaceInfo: {
type: Object,
default () {
return {}
}
},
collection: {
type: String,
default: ''
},
action: {
type: String,
default: ''
},
field: {
type: String,
default: ''
},
orderby: {
type: String,
default: ''
},
where: {
type: [String, Object],
default: ''
},
pageData: {
type: String,
default: 'add'
},
pageCurrent: {
type: Number,
default: 1
},
pageSize: {
type: Number,
default: 20
},
getcount: {
type: [Boolean, String],
default: false
},
getone: {
type: [Boolean, String],
default: false
},
gettree: {
type: [Boolean, String],
default: false
},
manual: {
type: Boolean,
default: false
},
value: {
type: [Array, String, Number],
default () {
return []
}
},
modelValue: {
type: [Array, String, Number],
default () {
return []
}
},
preload: {
type: Boolean,
default: false
},
stepSearh: {
type: Boolean,
default: true
},
selfField: {
type: String,
default: ''
},
parentField: {
type: String,
default: ''
},
multiple: {
type: Boolean,
default: false
},
map: {
type: Object,
default() {
return {
text: "text",
value: "value"
}
}
}
},
data() {
return {
loading: false,
errorMessage: '',
loadMore: {
contentdown: '',
contentrefresh: '',
contentnomore: ''
},
dataList: [],
selected: [],
selectedIndex: 0,
page: {
current: this.pageCurrent,
size: this.pageSize,
count: 0
}
}
},
computed: {
isLocaldata() {
return !this.collection.length
},
postField() {
let fields = [this.field];
if (this.parentField) {
fields.push(`${this.parentField} as parent_value`);
}
return fields.join(',');
},
dataValue() {
let isModelValue = Array.isArray(this.modelValue) ? (this.modelValue.length > 0) : (this.modelValue !== null || this.modelValue !== undefined)
return isModelValue ? this.modelValue : this.value
},
hasValue() {
if (typeof this.dataValue === 'number') {
return true
}
return (this.dataValue != null) && (this.dataValue.length > 0)
}
},
created() {
this.$watch(() => {
var al = [];
['pageCurrent',
'pageSize',
'spaceInfo',
'value',
'modelValue',
'localdata',
'collection',
'action',
'field',
'orderby',
'where',
'getont',
'getcount',
'gettree'
].forEach(key => {
al.push(this[key])
});
return al
}, (newValue, oldValue) => {
let needReset = false
for (let i = 2; i < newValue.length; i++) {
if (newValue[i] != oldValue[i]) {
needReset = true
break
}
}
if (newValue[0] != oldValue[0]) {
this.page.current = this.pageCurrent
}
this.page.size = this.pageSize
this.onPropsChange()
})
this._treeData = []
},
methods: {
onPropsChange() {
this._treeData = []
},
getCommand(options = {}) {
/* eslint-disable no-undef */
let db = uniCloud.database(this.spaceInfo)
const action = options.action || this.action
if (action) {
db = db.action(action)
}
const collection = options.collection || this.collection
db = db.collection(collection)
const where = options.where || this.where
if (!(!where || !Object.keys(where).length)) {
db = db.where(where)
}
const field = options.field || this.field
if (field) {
db = db.field(field)
}
const orderby = options.orderby || this.orderby
if (orderby) {
db = db.orderBy(orderby)
}
const current = options.pageCurrent !== undefined ? options.pageCurrent : this.page.current
const size = options.pageSize !== undefined ? options.pageSize : this.page.size
const getCount = options.getcount !== undefined ? options.getcount : this.getcount
const getTree = options.gettree !== undefined ? options.gettree : this.gettree
const getOptions = {
getCount,
getTree
}
if (options.getTreePath) {
getOptions.getTreePath = options.getTreePath
}
db = db.skip(size * (current - 1)).limit(size).get(getOptions)
return db
},
getNodeData(callback) {
if (this.loading) {
return
}
this.loading = true
this.getCommand({
field: this.postField,
where: this._pathWhere()
}).then((res) => {
this.loading = false
this.selected = res.result.data
callback && callback()
}).catch((err) => {
this.loading = false
this.errorMessage = err
})
},
getTreePath(callback) {
if (this.loading) {
return
}
this.loading = true
this.getCommand({
field: this.postField,
getTreePath: {
startWith: `${this.selfField}=='${this.dataValue}'`
}
}).then((res) => {
this.loading = false
let treePath = []
this._extractTreePath(res.result.data, treePath)
this.selected = treePath
callback && callback()
}).catch((err) => {
this.loading = false
this.errorMessage = err
})
},
loadData() {
if (this.isLocaldata) {
this._processLocalData()
return
}
if (this.dataValue != null) {
this._loadNodeData((data) => {
this._treeData = data
this._updateBindData()
this._updateSelected()
})
return
}
if (this.stepSearh) {
this._loadNodeData((data) => {
this._treeData = data
this._updateBindData()
})
} else {
this._loadAllData((data) => {
this._treeData = []
this._extractTree(data, this._treeData, null)
this._updateBindData()
})
}
},
_loadAllData(callback) {
if (this.loading) {
return
}
this.loading = true
this.getCommand({
field: this.postField,
gettree: true,
startwith: `${this.selfField}=='${this.dataValue}'`
}).then((res) => {
this.loading = false
callback(res.result.data)
this.onDataChange()
}).catch((err) => {
this.loading = false
this.errorMessage = err
})
},
_loadNodeData(callback, pw) {
if (this.loading) {
return
}
this.loading = true
this.getCommand({
field: this.postField,
where: pw || this._postWhere(),
pageSize: 500
}).then((res) => {
this.loading = false
callback(res.result.data)
this.onDataChange()
}).catch((err) => {
this.loading = false
this.errorMessage = err
})
},
_pathWhere() {
let result = []
let where_field = this._getParentNameByField();
if (where_field) {
result.push(`${where_field} == '${this.dataValue}'`)
}
if (this.where) {
return `(${this.where}) && (${result.join(' || ')})`
}
return result.join(' || ')
},
_postWhere() {
let result = []
let selected = this.selected
let parentField = this.parentField
if (parentField) {
result.push(`${parentField} == null || ${parentField} == ""`)
}
if (selected.length) {
for (var i = 0; i < selected.length - 1; i++) {
result.push(`${parentField} == '${selected[i].value}'`)
}
}
let where = []
if (this.where) {
where.push(`(${this.where})`)
}
if (result.length) {
where.push(`(${result.join(' || ')})`)
}
return where.join(' && ')
},
_nodeWhere() {
let result = []
let selected = this.selected
if (selected.length) {
result.push(`${this.parentField} == '${selected[selected.length - 1].value}'`)
}
if (this.where) {
return `(${this.where}) && (${result.join(' || ')})`
}
return result.join(' || ')
},
_getParentNameByField() {
const fields = this.field.split(',');
let where_field = null;
for (let i = 0; i < fields.length; i++) {
const items = fields[i].split('as');
if (items.length < 2) {
continue;
}
if (items[1].trim() === 'value') {
where_field = items[0].trim();
break;
}
}
return where_field
},
_isTreeView() {
return (this.parentField && this.selfField)
},
_updateSelected() {
var dl = this.dataList
var sl = this.selected
let textField = this.map.text
let valueField = this.map.value
for (var i = 0; i < sl.length; i++) {
var value = sl[i].value
var dl2 = dl[i]
for (var j = 0; j < dl2.length; j++) {
var item2 = dl2[j]
if (item2[valueField] === value) {
sl[i].text = item2[textField]
break
}
}
}
},
_updateBindData(node) {
const {
dataList,
hasNodes
} = this._filterData(this._treeData, this.selected)
let isleaf = this._stepSearh === false && !hasNodes
if (node) {
node.isleaf = isleaf
}
this.dataList = dataList
this.selectedIndex = dataList.length - 1
if (!isleaf && this.selected.length < dataList.length) {
this.selected.push({
value: null,
text: "请选择"
})
}
return {
isleaf,
hasNodes
}
},
_filterData(data, paths) {
let dataList = []
let hasNodes = true
dataList.push(data.filter((item) => {
return (item.parent_value === null || item.parent_value === undefined || item.parent_value === '')
}))
for (let i = 0; i < paths.length; i++) {
var value = paths[i].value
var nodes = data.filter((item) => {
return item.parent_value === value
})
if (nodes.length) {
dataList.push(nodes)
} else {
hasNodes = false
}
}
return {
dataList,
hasNodes
}
},
_extractTree(nodes, result, parent_value) {
let list = result || []
let valueField = this.map.value
for (let i = 0; i < nodes.length; i++) {
let node = nodes[i]
let child = {}
for (let key in node) {
if (key !== 'children') {
child[key] = node[key]
}
}
if (parent_value !== null && parent_value !== undefined && parent_value !== '') {
child.parent_value = parent_value
}
result.push(child)
let children = node.children
if (children) {
this._extractTree(children, result, node[valueField])
}
}
},
_extractTreePath(nodes, result) {
let list = result || []
for (let i = 0; i < nodes.length; i++) {
let node = nodes[i]
let child = {}
for (let key in node) {
if (key !== 'children') {
child[key] = node[key]
}
}
result.push(child)
let children = node.children
if (children) {
this._extractTreePath(children, result)
}
}
},
_findNodePath(key, nodes, path = []) {
let textField = this.map.text
let valueField = this.map.value
for (let i = 0; i < nodes.length; i++) {
let node = nodes[i]
let children = node.children
let text = node[textField]
let value = node[valueField]
path.push({
value,
text
})
if (value === key) {
return path
}
if (children) {
const p = this._findNodePath(key, children, path)
if (p.length) {
return p
}
}
path.pop()
}
return []
},
_processLocalData() {
this._treeData = []
this._extractTree(this.localdata, this._treeData)
var inputValue = this.dataValue
if (inputValue === undefined) {
return
}
if (Array.isArray(inputValue)) {
inputValue = inputValue[inputValue.length - 1]
if (typeof inputValue === 'object' && inputValue[this.map.value]) {
inputValue = inputValue[this.map.value]
}
}
this.selected = this._findNodePath(inputValue, this.localdata)
}
}
}

View File

@ -0,0 +1,333 @@
<template>
<view class="uni-data-pickerview">
<scroll-view class="selected-area" scroll-x="true" scroll-y="false" :show-scrollbar="false">
<view class="selected-list">
<template v-for="(item,index) in selected">
<view class="selected-item"
:class="{'selected-item-active':index==selectedIndex, 'selected-item-text-overflow': ellipsis}"
v-if="item.text" @click="handleSelect(index)">
<text class="">{{item.text}}</text>
</view>
</template>
</view>
</scroll-view>
<view class="tab-c">
<template v-for="(child, i) in dataList" >
<scroll-view class="list" :key="i" v-if="i==selectedIndex" :scroll-y="true">
<view class="item" :class="{'is-disabled': !!item.disable}" v-for="(item, j) in child"
@click="handleNodeClick(item, i, j)">
<text class="item-text item-text-overflow">{{item[map.text]}}</text>
<view class="check" v-if="selected.length > i && item[map.value] == selected[i].value"></view>
</view>
</scroll-view>
</template>
<view class="loading-cover" v-if="loading">
<uni-load-more class="load-more" :contentText="loadMore" status="loading"></uni-load-more>
</view>
<view class="error-message" v-if="errorMessage">
<text class="error-text">{{errorMessage}}</text>
</view>
</view>
</view>
</template>
<script>
import dataPicker from "./uni-data-picker.js"
/**
* DataPickerview
* @description uni-data-pickerview
* @tutorial https://ext.dcloud.net.cn/plugin?id=3796
* @property {Array} localdata 本地数据参考
* @property {Boolean} step-searh = [true|false] 是否分布查询
* @value true 启用分布查询仅查询当前选中节点
* @value false 关闭分布查询一次查询出所有数据
* @property {String|DBFieldString} self-field 分布查询当前字段名称
* @property {String|DBFieldString} parent-field 分布查询父字段名称
* @property {String|DBCollectionString} collection 表名
* @property {String|DBFieldString} field 查询字段多个字段用 `,` 分割
* @property {String} orderby 排序字段及正序倒叙设置
* @property {String|JQLString} where 查询条件
*/
export default {
name: 'UniDataPickerView',
emits: ['nodeclick', 'change', 'datachange', 'update:modelValue'],
mixins: [dataPicker],
props: {
managedMode: {
type: Boolean,
default: false
},
ellipsis: {
type: Boolean,
default: true
}
},
data() {
return {}
},
created() {
if (this.managedMode) {
return
}
this.$nextTick(() => {
this.load()
})
},
methods: {
onPropsChange() {
this._treeData = []
this.selectedIndex = 0
this.load()
},
load() {
if (this.isLocaldata) {
this.loadData()
} else if (this.dataValue.length) {
this.getTreePath((res) => {
this.loadData()
})
}
},
handleSelect(index) {
this.selectedIndex = index
},
handleNodeClick(item, i, j) {
if (item.disable) {
return
}
const node = this.dataList[i][j]
const text = node[this.map.text]
const value = node[this.map.value]
if (i < this.selected.length - 1) {
this.selected.splice(i, this.selected.length - i)
this.selected.push({
text,
value
})
} else if (i === this.selected.length - 1) {
this.selected.splice(i, 1, {
text,
value
})
}
if (node.isleaf) {
this.onSelectedChange(node, node.isleaf)
return
}
const {
isleaf,
hasNodes
} = this._updateBindData()
if (!this._isTreeView() && !hasNodes) {
this.onSelectedChange(node, true)
return
}
if (this.isLocaldata && (!hasNodes || isleaf)) {
this.onSelectedChange(node, true)
return
}
if (!isleaf && !hasNodes) {
this._loadNodeData((data) => {
if (!data.length) {
node.isleaf = true
} else {
this._treeData.push(...data)
this._updateBindData(node)
}
this.onSelectedChange(node, node.isleaf)
}, this._nodeWhere())
return
}
this.onSelectedChange(node, false)
},
updateData(data) {
this._treeData = data.treeData
this.selected = data.selected
if (!this._treeData.length) {
this.loadData()
} else {
//this.selected = data.selected
this._updateBindData()
}
},
onDataChange() {
this.$emit('datachange')
},
onSelectedChange(node, isleaf) {
if (isleaf) {
this._dispatchEvent()
}
if (node) {
this.$emit('nodeclick', node)
}
},
_dispatchEvent() {
this.$emit('change', this.selected.slice(0))
}
}
}
</script>
<style >
.uni-data-pickerview {
flex: 1;
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: column;
overflow: hidden;
height: 100%;
}
.error-text {
color: #DD524D;
}
.loading-cover {
position: absolute;
left: 0;
top: 0;
right: 0;
bottom: 0;
background-color: rgba(255, 255, 255, .5);
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: column;
align-items: center;
z-index: 1001;
}
.load-more {
/* #ifndef APP-NVUE */
margin: auto;
/* #endif */
}
.error-message {
background-color: #fff;
position: absolute;
left: 0;
top: 0;
right: 0;
bottom: 0;
padding: 15px;
opacity: .9;
z-index: 102;
}
/* #ifdef APP-NVUE */
.selected-area {
width: 750rpx;
}
/* #endif */
.selected-list {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: row;
flex-wrap: nowrap;
padding: 0 5px;
border-bottom: 1px solid #f8f8f8;
}
.selected-item {
margin-left: 10px;
margin-right: 10px;
padding: 12px 0;
text-align: center;
/* #ifndef APP-NVUE */
white-space: nowrap;
/* #endif */
}
.selected-item-text-overflow {
width: 168px;
/* fix nvue */
overflow: hidden;
/* #ifndef APP-NVUE */
width: 6em;
white-space: nowrap;
text-overflow: ellipsis;
-o-text-overflow: ellipsis;
/* #endif */
}
.selected-item-active {
border-bottom: 2px solid #007aff;
}
.selected-item-text {
color: #007aff;
}
.tab-c {
position: relative;
flex: 1;
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: row;
overflow: hidden;
}
.list {
flex: 1;
}
.item {
padding: 12px 15px;
/* border-bottom: 1px solid #f0f0f0; */
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: row;
justify-content: space-between;
}
.is-disabled {
opacity: .5;
}
.item-text {
/* flex: 1; */
color: #333333;
}
.item-text-overflow {
width: 280px;
/* fix nvue */
overflow: hidden;
/* #ifndef APP-NVUE */
width: 20em;
white-space: nowrap;
text-overflow: ellipsis;
-o-text-overflow: ellipsis;
/* #endif */
}
.check {
margin-right: 5px;
border: 2px solid #007aff;
border-left: 0;
border-top: 0;
height: 12px;
width: 6px;
transform-origin: center;
/* #ifndef APP-NVUE */
transition: all 0.3s;
/* #endif */
transform: rotate(45deg);
}
</style>

View File

@ -0,0 +1,93 @@
{
"id": "uni-data-picker",
"displayName": "uni-data-picker 数据驱动的picker选择器",
"version": "1.0.7",
"description": "单列、多列级联选择器,常用于省市区城市选择、公司部门选择、多级分类等场景",
"keywords": [
"uni-ui",
"uniui",
"picker",
"级联",
"省市区",
""
],
"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-load-more",
"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",
"联盟": "u"
},
"Vue": {
"vue2": "y",
"vue3": "y"
}
}
}
}
}

View File

@ -0,0 +1,22 @@
## DataPicker 级联选择
> **组件名uni-data-picker**
> 代码块: `uDataPicker`
> 关联组件:`uni-data-pickerview`、`uni-load-more`。
`<uni-data-picker>` 是一个选择类[datacom组件](https://uniapp.dcloud.net.cn/component/datacom)。
支持单列、和多列级联选择。列数没有限制如果屏幕显示不全顶部tab区域会左右滚动。
候选数据支持一次性加载完毕,也支持懒加载,比如示例图中,选择了“北京”后,动态加载北京的区县数据。
`<uni-data-picker>` 组件尤其适用于地址选择、分类选择等选择类。
`<uni-data-picker>` 支持本地数据、云端静态数据(json)uniCloud云数据库数据。
`<uni-data-picker>` 可以通过JQL直连uniCloud云数据库配套[DB Schema](https://uniapp.dcloud.net.cn/uniCloud/schema)可在schema2code中自动生成前端页面还支持服务器端校验。
在uniCloud数据表中新建表“uni-id-address”和“opendb-city-china”这2个表的schema自带foreignKey关联。在“uni-id-address”表的表结构页面使用schema2code生成前端页面会自动生成地址管理的维护页面自动从“opendb-city-china”表包含的中国所有省市区信息里选择地址。
### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-data-picker)
#### 如使用过程中有任何问题或者您对uni-ui有一些好的建议欢迎加入 uni-ui 交流群871950839

View File

@ -0,0 +1,16 @@
## 0.1.62022-07-06
- 修复 pc端宽度异常的bug
## 0.1.5
- 修复 pc端宽度异常的bug
## 0.1.42022-07-05
- 优化 显示样式
## 0.1.32022-06-02
- 修复 localdata 赋值不生效的 bug
- 新增 支持 uni.scss 修改颜色
- 新增 支持选项禁用(数据选项设置 disabled: true 即禁用)
## 0.1.22022-05-08
- 修复 当 value 为 0 时选择不生效的 bug
## 0.1.12022-05-07
- 新增 记住上次的选项(仅 collection 存在时有效)
## 0.1.02022-04-22
- 初始化

View File

@ -0,0 +1,426 @@
<template>
<view class="uni-stat__select">
<span v-if="label" class="uni-label-text hide-on-phone">{{label + ''}}</span>
<view class="uni-stat-box" :class="{'uni-stat__actived': current}">
<view class="uni-select">
<view class="uni-select__input-box" @click="toggleSelector">
<view v-if="current" class="uni-select__input-text">{{current}}</view>
<view v-else class="uni-select__input-text uni-select__input-placeholder">{{typePlaceholder}}</view>
<uni-icons v-if="current && clear" type="clear" color="#c0c4cc" size="24" @click="clearVal" />
<uni-icons v-else :type="showSelector? 'top' : 'bottom'" size="14" color="#999" />
</view>
<view class="uni-select--mask" v-if="showSelector" @click="toggleSelector" />
<view class="uni-select__selector" v-if="showSelector">
<view class="uni-popper__arrow"></view>
<scroll-view scroll-y="true" class="uni-select__selector-scroll">
<view class="uni-select__selector-empty" v-if="mixinDatacomResData.length === 0">
<text>{{emptyTips}}</text>
</view>
<view v-else class="uni-select__selector-item" v-for="(item,index) in mixinDatacomResData"
:key="index" @click="change(item)">
<text
:class="{'uni-select__selector__disabled': item.disable}">{{formatItemName(item)}}</text>
</view>
</scroll-view>
</view>
</view>
</view>
</view>
</template>
<script>
/**
* DataChecklist 数据选择器
* @description 通过数据渲染的下拉框组件
* @tutorial https://uniapp.dcloud.io/component/uniui/uni-data-select
* @property {String} value 默认值
* @property {Array} localdata 本地数据 格式 [{text:'',value:''}]
* @property {Boolean} clear 是否可以清空已选项
* @property {Boolean} emptyText 没有数据时显示的文字 本地数据无效
* @property {String} label 左侧标题
* @property {String} placeholder 输入框的提示文字
* @event {Function} change 选中发生变化触发
*/
export default {
name: "uni-stat-select",
mixins: [uniCloud.mixinDatacom || {}],
data() {
return {
showSelector: false,
current: '',
mixinDatacomResData: [],
apps: [],
channels: []
};
},
props: {
localdata: {
type: Array,
default () {
return []
}
},
value: {
type: [String, Number],
default: ''
},
modelValue: {
type: [String, Number],
default: ''
},
label: {
type: String,
default: ''
},
placeholder: {
type: String,
default: '请选择'
},
emptyTips: {
type: String,
default: '无选项'
},
clear: {
type: Boolean,
default: true
},
defItem: {
type: Number,
default: 0
}
},
created() {
this.last = `${this.collection}_last_selected_option_value`
if (this.collection && !this.localdata.length) {
this.mixinDatacomEasyGet()
}
},
computed: {
typePlaceholder() {
const text = {
'opendb-stat-app-versions': '版本',
'opendb-app-channels': '渠道',
'opendb-app-list': '应用'
}
const common = this.placeholder
const placeholder = text[this.collection]
return placeholder ?
common + placeholder :
common
}
},
watch: {
localdata: {
immediate: true,
handler(val, old) {
if (Array.isArray(val) && old !== val) {
this.mixinDatacomResData = val
}
}
},
// #ifndef VUE3
value() {
this.initDefVal()
},
// #endif
// #ifdef VUE3
modelValue() {
this.initDefVal()
},
// #endif
mixinDatacomResData: {
immediate: true,
handler(val) {
if (val.length) {
this.initDefVal()
}
}
}
},
methods: {
initDefVal() {
let defValue = ''
if ((this.value || this.value === 0) && !this.isDisabled(this.value)) {
defValue = this.value
} else if ((this.modelValue || this.modelValue === 0) && !this.isDisabled(this.modelValue)) {
defValue = this.modelValue
} else {
let strogeValue
if (this.collection) {
strogeValue = uni.getStorageSync(this.last)
}
if (strogeValue || strogeValue === 0) {
defValue = strogeValue
} else {
let defItem = ''
if (this.defItem > 0 && this.defItem < this.mixinDatacomResData.length) {
defItem = this.mixinDatacomResData[this.defItem - 1].value
}
defValue = defItem
}
this.emit(defValue)
}
const def = this.mixinDatacomResData.find(item => item.value === defValue)
this.current = def ? this.formatItemName(def) : ''
},
/**
* @param {[String, Number]} value
* 判断用户给的 value 是否同时为禁用状态
*/
isDisabled(value) {
let isDisabled = false;
this.mixinDatacomResData.forEach(item => {
if (item.value === value) {
isDisabled = item.disable
}
})
return isDisabled;
},
clearVal() {
this.emit('')
if (this.collection) {
uni.removeStorageSync(this.last)
}
},
change(item) {
if (!item.disable) {
this.showSelector = false
this.current = this.formatItemName(item)
this.emit(item.value)
}
},
emit(val) {
this.$emit('change', val)
this.$emit('input', val)
this.$emit('update:modelValue', val)
if (this.collection) {
uni.setStorageSync(this.last, val)
}
},
toggleSelector() {
this.showSelector = !this.showSelector
},
formatItemName(item) {
let {
text,
value,
channel_code
} = item
channel_code = channel_code ? `(${channel_code})` : ''
return this.collection.indexOf('app-list') > 0 ?
`${text}(${value})` :
(
text ?
text :
`未命名${channel_code}`
)
}
}
}
</script>
<style lang="scss">
$uni-base-color: #6a6a6a !default;
$uni-main-color: #333 !default;
$uni-secondary-color: #909399 !default;
$uni-border-3: #e5e5e5;
/* #ifndef APP-NVUE */
@media screen and (max-width: 500px) {
.hide-on-phone {
display: none;
}
}
/* #endif */
.uni-stat__select {
display: flex;
align-items: center;
// padding: 15px;
cursor: pointer;
width: 100%;
flex: 1;
box-sizing: border-box;
}
.uni-stat-box {
width: 100%;
flex: 1;
}
.uni-stat__actived {
width: 100%;
flex: 1;
// outline: 1px solid #2979ff;
}
.uni-label-text {
font-size: 14px;
font-weight: bold;
color: $uni-base-color;
margin: auto 0;
margin-right: 5px;
}
.uni-select {
font-size: 14px;
border: 1px solid $uni-border-3;
box-sizing: border-box;
border-radius: 4px;
padding: 0 5px;
padding-left: 10px;
position: relative;
/* #ifndef APP-NVUE */
display: flex;
user-select: none;
/* #endif */
flex-direction: row;
align-items: center;
border-bottom: solid 1px $uni-border-3;
width: 100%;
flex: 1;
height: 35px;
}
.uni-select__label {
font-size: 16px;
// line-height: 22px;
height: 35px;
padding-right: 10px;
color: $uni-secondary-color;
}
.uni-select__input-box {
// height: 35px;
position: relative;
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex: 1;
flex-direction: row;
align-items: center;
}
.uni-select__input {
flex: 1;
font-size: 14px;
height: 22px;
line-height: 22px;
}
.uni-select__input-plac {
font-size: 14px;
color: $uni-secondary-color;
}
.uni-select__selector {
/* #ifndef APP-NVUE */
box-sizing: border-box;
/* #endif */
position: absolute;
top: calc(100% + 12px);
left: 0;
width: 100%;
background-color: #FFFFFF;
border: 1px solid #EBEEF5;
border-radius: 6px;
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
z-index: 2;
padding: 4px 0;
}
.uni-select__selector-scroll {
/* #ifndef APP-NVUE */
max-height: 200px;
box-sizing: border-box;
/* #endif */
}
.uni-select__selector-empty,
.uni-select__selector-item {
/* #ifndef APP-NVUE */
display: flex;
cursor: pointer;
/* #endif */
line-height: 35px;
font-size: 14px;
text-align: center;
/* border-bottom: solid 1px $uni-border-3; */
padding: 0px 10px;
}
.uni-select__selector-item:hover {
background-color: #f9f9f9;
}
.uni-select__selector-empty:last-child,
.uni-select__selector-item:last-child {
/* #ifndef APP-NVUE */
border-bottom: none;
/* #endif */
}
.uni-select__selector__disabled {
opacity: 0.4;
cursor: default;
}
/* picker 弹出层通用的指示小三角 */
.uni-popper__arrow,
.uni-popper__arrow::after {
position: absolute;
display: block;
width: 0;
height: 0;
border-color: transparent;
border-style: solid;
border-width: 6px;
}
.uni-popper__arrow {
filter: drop-shadow(0 2px 12px rgba(0, 0, 0, 0.03));
top: -6px;
left: 10%;
margin-right: 3px;
border-top-width: 0;
border-bottom-color: #EBEEF5;
}
.uni-popper__arrow::after {
content: " ";
top: 1px;
margin-left: -6px;
border-top-width: 0;
border-bottom-color: #fff;
}
.uni-select__input-text {
// width: 280px;
width: 100%;
color: $uni-main-color;
white-space: nowrap;
text-overflow: ellipsis;
-o-text-overflow: ellipsis;
overflow: hidden;
}
.uni-select__input-placeholder {
color: $uni-base-color;
font-size: 12px;
}
.uni-select--mask {
position: fixed;
top: 0;
bottom: 0;
right: 0;
left: 0;
}
</style>

View File

@ -0,0 +1,88 @@
{
"id": "uni-data-select",
"displayName": "uni-data-select 下拉框选择器",
"version": "0.1.6",
"description": "通过数据驱动的下拉框选择器",
"keywords": [
"uni-ui",
"select",
"uni-data-select",
"下拉框",
"下拉选"
],
"repository": "https://github.com/dcloudio/uni-ui",
"engines": {
"HBuilderX": "^3.1.1"
},
"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-load-more"],
"encrypt": [],
"platforms": {
"cloud": {
"tcb": "y",
"aliyun": "y"
},
"client": {
"App": {
"app-vue": "u",
"app-nvue": "n"
},
"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",
"阿里": "u",
"百度": "u",
"字节跳动": "u",
"QQ": "u",
"京东": "u"
},
"快应用": {
"华为": "u",
"联盟": "u"
},
"Vue": {
"vue2": "y",
"vue3": "y"
}
}
}
}
}

View File

@ -0,0 +1,8 @@
## DataSelect 下拉框选择器
> **组件名uni-data-select**
> 代码块: `uDataSelect`
当选项过多时,使用下拉菜单展示并选择内容
### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-data-select)
#### 如使用过程中有任何问题或者您对uni-ui有一些好的建议欢迎加入 uni-ui 交流群871950839

View File

@ -0,0 +1,25 @@
## 0.2.02021-07-13
- 组件兼容 vue3如何创建vue3项目详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834)
## 0.1.12021-07-02
- 修复 sourceType 缺少默认值导致 ios 无法选择文件
## 0.1.02021-06-30
- 优化 解耦与uniCloud的强绑定关系 如不绑定服务空间默认autoUpload为false且不可更改
## 0.0.112021-06-30
- 修复 由 0.0.10 版本引发的 returnType 属性失效的问题
## 0.0.102021-06-29
- 优化 文件上传后进度条消失时机
## 0.0.92021-06-29
- 修复 在uni-forms 中,删除文件 获取的值不对的Bug
## 0.0.82021-06-15
- 修复 删除文件时无法触发 v-model 的Bug
## 0.0.72021-05-12
- 新增 组件示例地址
## 0.0.62021-04-09
- 修复 选择的文件非 file-extname 字段指定的扩展名报错的Bug
## 0.0.52021-04-09
- 优化 更新组件示例
## 0.0.42021-04-09
- 优化 file-extname 字段支持字符串写法,多个扩展名需要用逗号分隔
## 0.0.32021-02-05
- 调整为uni_modules目录规范
- 修复 微信小程序不指定 fileExtname 属性选择失败的Bug

View File

@ -0,0 +1,142 @@
'use strict';
// Object.defineProperty(exports, '__esModule', { value: true });
const ERR_MSG_OK = 'chooseAndUploadFile:ok';
const ERR_MSG_FAIL = 'chooseAndUploadFile:fail';
function chooseImage(opts) {
const { count, sizeType, sourceType = ['album', 'camera'], extension } = opts
return new Promise((resolve, reject) => {
uni.chooseImage({
count,
sizeType,
sourceType,
extension,
success(res) {
resolve(normalizeChooseAndUploadFileRes(res, 'image'));
},
fail(res) {
reject({
errMsg: res.errMsg.replace('chooseImage:fail', ERR_MSG_FAIL),
});
},
});
});
}
function chooseVideo(opts) {
const { camera, compressed, maxDuration, sourceType = ['album', 'camera'], extension } = opts;
return new Promise((resolve, reject) => {
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),
});
},
});
});
}
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('.'));
});
// wx.chooseMessageFile
if (!res.tempFilePaths) {
res.tempFilePaths = res.tempFiles.map((file) => file.path);
}
return res;
}
function uploadCloudFiles(res, max = 5, onUploadProgress) {}
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
// return uploadCloudFiles(res, 5, onUploadProgress);
})
}
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};

View File

@ -0,0 +1,706 @@
<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="is-add">
<view class="icon-add"></view>
<view class="icon-add rotate"></view>
</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} from './choose-and-upload-file.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
},
props: {
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'
},
// inputUrl: {
// type: Boolean,
// default: false
// },
// 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'
}
},
watch: {
value: {
handler(newVal) {
let newFils = []
let newData = [].concat(newVal || [])
newData.forEach(v => {
const files = this.files.find(i => i.url === v.url)
const reg = /cloud:\/\/([\w.]+\/?)\S*/
if (!v.path) {
v.path = v.url
}
if (reg.test(v.url)) {
this.getTempFileURL(v, v.url)
}
newFils.push(files ? files : v)
})
let data = null
if (this.returnType === 'object') {
data = this.backObject(newFils)[0]
} else {
data = this.backObject(newFils)
}
this.formItem && this.formItem.setValue(data)
this.files = newFils
},
immediate: true
}
},
data() {
return {
files: [],
}
},
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
},
extname(){
if (!Array.isArray(this.fileExtname)) {
let extname = this.fileExtname.replace(/(\[|\])/g,'')
return extname.split(',')
} else {
return this.fileExtname
}
return []
}
},
created() {
// TODO
if(!(uniCloud.config && uniCloud.config.provider)){
this.noSpace = true
uniCloud.chooseAndUploadFile = chooseAndUploadFile
}
this.tempData = {}
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: {
/**
* 获取父元素实例
*/
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;
},
/**
* 继续上传
*/
upload() {
// TODO
// if (this.$uploadFiles) {
// this.$uploadFiles()
// } else {
// uni.showToast({
// title: '',
// icon: 'none'
// })
// }
let files = []
this.files.forEach((v, index) => {
if (v.status === 'ready' || v.status === 'error') {
files.push(Object.assign({}, v))
}
})
this.uploadFiles(files)
},
/**
* 选择文件
*/
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
}
// uni.showActionSheet({
// itemList: [' url ', ''],
// success: (res) => {
// if (res.tapIndex === 1) {
// this.chooseFiles()
// }
// },
// fail: function(res) {}
// });
this.chooseFiles()
},
/**
* 选择文件并上传
*/
chooseFiles() {
uniCloud
.chooseAndUploadFile({
type: this.fileMediatype,
compressed: false,
// TODO video
extension: this.extname.length > 0 ? this.extname : undefined,
count: this.limitLength - this.files.length, //9
onChooseFile: async res => {
if ((Number(this.limitLength) === 1 && this.disablePreview && !this.disabled) || this.returnType === 'object') {
this.files = []
}
let filePaths = []
let files = []
if (this.extname && this.extname.length > 0) {
res.tempFiles.forEach(v => {
let fileFullName = this.getFileExt(v.name)
const extname = fileFullName.ext.toLowerCase()
if (this.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
})
}
} else {
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 this.getFileData(files[i], this.fileMediatype)
filedata.file = files[i]
filedata.progress = 0
filedata.status = 'ready'
this.files.push(filedata)
currentData.push(filedata)
}
this.$emit('select', {
tempFiles: currentData,
tempFilePaths: filePaths
})
res.tempFiles = files
//
if (!this.autoUpload || this.noSpace) {
res.tempFiles = []
// TODO
// return new Promise((resolve) => {
// this.$uploadFiles = () => {
// // this._is_uploading = true
// resolve(res)
// }
// })
}
},
onUploadProgress: progressEvent => {
this.setProgress(progressEvent, progressEvent.index)
}
})
.then(result => {
this.setSuccessAndError(result.tempFiles)
})
.catch(err => {
console.log('选择失败', err)
})
},
/**
* 批传
* @param {Object} e
*/
uploadFiles(files) {
files = [].concat(files)
this.uploadCloudFiles(files, 5, res => {
this.setProgress(res, res.index, true)
})
.then(result => {
this.setSuccessAndError(result)
})
.catch(err => {
console.log('err', err)
})
},
/**
* 成功或失败
*/
async setSuccessAndError(res, fn) {
let successData = []
let errorData = []
let tempFilePath = []
let errorTempFilePath = []
for (let i = 0; i < res.length; i++) {
// const index = item.index
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].url = item.url
this.files[index].status = 'success'
this.files[index].progress += 1
successData.push(this.files[index])
tempFilePath.push(this.files[index].url)
}
}
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', {
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)
}
},
/**
* 获取图片信息
* @param {Object} filepath
*/
getFileInfo(filepath) {
return new Promise((resolve, reject) => {
uni.getImageInfo({
src: filepath,
success(res) {
resolve(res)
},
fail(err) {
reject(err)
}
})
})
},
/**
* 获取封装数据
*/
async getFileData(files, type = 'image') {
//
let fileFullName = this.getFileExt(files.name)
const extname = fileFullName.ext.toLowerCase()
let filedata = {
name: files.name,
uuid: files.uuid,
extname: extname || '',
cloudPath: files.cloudPath,
file:files.file,
fileType: files.fileType,
url: files.path || files.path,
size: files.size, //
image: {},
path: files.path,
video: {}
}
if (type === 'image') {
const imageinfo = await this.getFileInfo(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
},
/**
* 批量上传
*/
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()
}
})
}
})
},
setEmit() {
let data = []
if (this.returnType === 'object') {
data = this.backObject(this.files)[0]
} else {
data = this.backObject(this.files)
}
this.$emit('input', data)
},
backObject(files) {
let newFilesData = JSON.parse(JSON.stringify(files))
newFilesData.map(v => {
delete v.path
delete v.uuid
delete v.video
delete v.progress
delete v.errMsg
delete v.status
delete v.cloudPath
return v
})
return newFilesData
},
async getTempFileURL(file, fileList) {
fileList = {
fileList: [].concat(fileList)
}
const urls = await uniCloud.getTempFileURL(fileList)
file.path = urls.fileList[0].tempFileURL || ''
const index = this.files.findIndex(v => v.path === file.path)
if (index !== -1) {
this.$set(this.files, index, file)
}
}
}
}
</script>
<style>
.uni-file-picker {
/* #ifndef APP-NVUE */
box-sizing: border-box;
overflow: hidden;
/* #endif */
}
.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;
}
.is-add {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
align-items: center;
justify-content: center;
}
.icon-add {
width: 50px;
height: 5px;
background-color: #f1f1f1;
border-radius: 2px;
}
.rotate {
position: absolute;
transform: rotate(90deg);
}
</style>

View File

@ -0,0 +1,324 @@
<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",
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>

View File

@ -0,0 +1,289 @@
<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.path" 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 && !readonly" class="file-picker__box" :style="boxStyle">
<view class="file-picker__box-content is-add" :style="borderStyle" @click="choose">
<slot>
<view class="icon-add"></view>
<view class="icon-add rotate"></view>
</slot>
</view>
</view>
</view>
</template>
<script>
export default {
name: "uploadImage",
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 = {}
if (typeof border === 'boolean') {
obj.border = border ? '1px #eee solid' : 'none'
} else {
let width = (border && border.width) || 1
width = this.value2px(width)
let radius = (border && border.radius) || 5
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() {
this.$emit("choose")
},
delFile(index) {
this.$emit('delFile', index)
},
prviewImage(img, index) {
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.path)
})
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: 8px;
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;
}
.icon-add {
width: 50px;
height: 5px;
background-color: #f1f1f1;
border-radius: 2px;
}
.rotate {
position: absolute;
transform: rotate(90deg);
}
.icon-del-box {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
align-items: center;
justify-content: center;
position: absolute;
top: 5px;
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: 2px;
background-color: #fff;
border-radius: 2px;
}
</style>

View File

@ -0,0 +1,82 @@
{
"id": "uni-file-picker",
"displayName": "uni-file-picker 文件选择上传",
"version": "0.2.0",
"description": "文件选择上传组件,可以选择图片、视频等任意文件并上传到当前绑定的服务空间",
"keywords": [
"uni-ui",
"uniui",
"图片上传",
"文件上传"
],
"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": [],
"encrypt": [],
"platforms": {
"cloud": {
"tcb": "y",
"aliyun": "y"
},
"client": {
"App": {
"app-vue": "y",
"app-nvue": "n"
},
"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"
}
}
}
}
}

View File

@ -0,0 +1,301 @@
## FilePicker 文件选择上传
> **组件名uni-file-picker**
> 代码块: `uFilePicker`
文件选择上传组件,可以选择图片、视频等任意文件并上传到当前绑定的服务空间
> **注意事项**
> 为了避免错误使用,给大家带来不好的开发体验,请在使用组件前仔细阅读下面的注意事项,可以帮你避免一些错误。
> - 组件需要依赖 `sass` 插件 ,请自行手动安装
> - 如不绑定服务空间,`autoUpload`默认为`false`且不可更改
> - 选择文件目前只支持 `H5``微信小程序平台` ,且 `微信小程序平台` 使用 `wx.chooseMessageFile()`
> - 如使用过程中有任何问题或者您对uni-ui有一些好的建议欢迎加入 uni-ui 交流群871950839
## API
### FilePicker Props
| 属性名 | 类型 | 默认值 | 可选值 | 说明 |
| :-: | :-: | :-: | :-: | :-: |
| v-model/value | Array\Object | - | - | 组件数据,通常用来回显 ,类型由`return-type`属性决定 **格式见下文** |
| disabled | Boolean | false | - | 组件禁用 |
| readonly | Boolean | false | - | 组件只读,不可选择,不显示进度,不显示删除按钮 |
| return-type | String | array | array/object | 限制 `value` 格式,当为 `object` 时 ,组件只能单选,且会覆盖 |
| disable-preview| Boolean | false | - | 禁用图片预览,仅 `mode:grid`生效 |
| del-icon | Boolean | true | - | 是否显示删除按钮 |
| auto-upload | Boolean | true | - | 是否自动上传,值为`true`则只触发@select,可自行上传|
| limit | Number\String | 9 | - | 最大选择个数 h5 会自动忽略多选的部分 |
| title | String | - | - | 组件标题,右侧显示上传计数 |
| mode | String | list | list/grid | 选择文件后的文件列表样式 |
| file-mediatype| String | image | image/video/all | 选择文件类型,all 只支持 H5 和微信小程序平台 |
| file-extname | Array\String | - | - | 选择文件后缀,字符串的情况下需要用逗号分隔(推荐使用字符串),根据 `file-mediatype` 属性而不同|
| list-styles | Object | - | - | `mode:list` 时的样式 |
| image-styles | Object | - | - | `mode:grid` 时的样式 |
### value 格式
三个属性必填,否则影响组件显示
```json
[
{
"name":"file.txt",
"extname":"txt",
"url":"https://xxxx",
// ...
}
]
```
### list-styles 格式
```json
{
"borderStyle":{
"color":"#eee", // 边框颜色
"width":"1px", // 边框宽度
"style":"solid", // 边框样式
"radius":"5px" // 边框圆角,不支持百分比
},
"border":false, // 是否显示边框
"dividline":true // 是否显示分隔线
}
```
### image-styles 格式
```json
{
"height": 60, // 边框高度
"width": 60, // 边框宽度
"border":{ // 如果为 Boolean 值,可以控制边框显示与否
"color":"#eee", // 边框颜色
"width":"1px", // 边框宽度
"style":"solid", // 边框样式
"radius":"50%" // 边框圆角,支持百分比
}
}
```
### FilePicker Events
|事件称名 |说明 | 返回值 |
|:-: |:-: | :-: |
|@select | 选择文件后触发 | 见下文|
|@progress|文件上传时触发 | 见下文|
|@success |上传成功触发 | 见下文|
|@fail |上传失败触发 | 见下文|
|@delete |文件从列表移除时触发| 见下文|
#### Callback Params
```json
{
"progress" : Number, // 上传进度 ,仅 @progress 事件包含此字段
"index" : Number, // 上传文件索引 ,仅 @progress 事件包含此字段
"tempFile" : file, // 当前文件对象 ,包含文件流,文件大小,文件名称等,仅 @progress 事件包含此字段
"tempFiles" : files, // 文件列表,包含文件流,文件大小,文件名称等
"tempFilePaths" : filePaths, // 文件地址列表,@sucess 事件为上传后的线上文件地址
}
```
### FilePicker Methods
通过 `$ref` 调用
| 方法称名 | 说明 | 参数 |
| :-: | :-: | :-: |
| upload | 手动上传 ,如`autoUpload`为`false` ,必须调用此方法| - |
### FilePicker Slots
插槽可定义上传按钮显示样式
| 插槽名 | 说明 |
| :-: | :-: |
| default |默认插槽|
## 组件用法
### 基础用法
```html
<uni-file-picker
v-model="imageValue"
fileMediatype="image"
mode="grid"
@select="select"
@progress="progress"
@success="success"
@fail="fail"
/>
```
```javascript
export default {
data() {
return {
imageValue:[]
}
},
methods:{
// 获取上传状态
select(e){
console.log('选择文件:',e)
}
// 获取上传进度
progress(e){
console.log('上传进度:',e)
},
// 上传成功
success(e){
console.log('上传成功')
},
// 上传失败
fail(e){
console.log('上传失败:',e)
}
}
}
```
### 选择指定后缀图片,且限制选择个数
配置 `file-mediatype` 属性为 `image`,限定只选择图片
配置 `file-extname` 属性为 `'png,jpg'`,限定只选择 `png`和`jpg`后缀的图片
配置 `limit` 属性为 1 ,则最多选择一张图片
配置 `mode` 属性为 `grid` ,可以使用九宫格样式选择图片
```html
<uni-file-picker
v-model="imageValue"
file-mediatype="image"
mode="grid"
file-extname="png,jpg"
:limit="1"
@progress="progress"
@success="success"
@fail="fail"
@select="select"
/>
```
### 手动上传
配置 `auto-upload` 属性为 `false` ,可以停止自动上传,通过`ref`调用`upload`方法自行选择上传时机
```html
<view>
<uni-file-picker ref="files" :auto-upload="false"/>
<button @click="upload">上传文件</button>
</view>
```
```javascript
export default {
data() {},
methods:{
upload(){
this.$refs.files.upload()
}
}
}
```
### 单选图片且点击再次选择
配置 `disable-preview` 属性为 `true`,禁用点击预览图片功能
配置 `del-icon` 属性为 `false`,隐藏删除按钮
配置 `return-type` 属性为 `object`,设置 `value` 类型 ,如需绑定 `array`类型 ,则设置`limit:1`,可达到一样的效果
```html
<uni-file-picker
disable-preview
:del-icon="false"
return-type="object"
>选择头像</uni-file-picker>
```
### 自定义样式
配置 `image-styles` 属性,可以自定义`mode:image`时的回显样式
配置 `list-styles` 属性,可以自定义`mode:video|| mode:all`时的回显样式
```html
<view>
<uni-file-picker fileMediatype="image" :image-styles="imageStyles"/>
<uni-file-picker fileMediatype="all" :list-styles="listStyles"/>
</view>
```
```javascript
export default {
data() {
imageStyles:{
width:64,
height:64,
border:{
color:"#ff5a5f",
width:2,
style:'dashed',
radius:'2px'
}
},
listStyles:{
// 是否显示边框
border: true,
// 是否显示分隔线
dividline: true,
// 线条样式
borderStyle: {
width:1,
color:'blue',
radius:2
}
}
}
}
```
### 使用插槽
使用默认插槽可以自定义选择文件按钮样式
```html
<uni-file-picker
v-model="value" file-mediatype="all">
<button>选择文件</button>
</uni-file-picker>
```
## 组件示例
点击查看:[https://hellouniapp.dcloud.net.cn/pages/extUI/file-picker/file-picker](https://hellouniapp.dcloud.net.cn/pages/extUI/file-picker/file-picker)

View File

@ -1,3 +1,21 @@
## 1.3.52022-01-24
- 优化 size 属性可以传入不带单位的字符串数值
## 1.3.42022-01-24
- 优化 size 支持其他单位
## 1.3.32022-01-17
- 修复 nvue 有些图标不显示的bug兼容老版本图标
## 1.3.22021-12-01
- 优化 示例可复制图标名称
## 1.3.12021-11-23
- 优化 兼容旧组件 type 值
## 1.3.02021-11-19
- 新增 更多图标
- 优化 自定义图标使用方式
- 优化 组件UI并提供设计资源详见:[https://uniapp.dcloud.io/component/uniui/resource](https://uniapp.dcloud.io/component/uniui/resource)
- 文档迁移,详见:[https://uniapp.dcloud.io/component/uniui/uni-icons](https://uniapp.dcloud.io/component/uniui/uni-icons)
## 1.1.72021-11-08
## 1.2.02021-07-30
- 组件兼容 vue3如何创建vue3项目详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834)
## 1.1.52021-05-12
- 新增 组件示例地址
## 1.1.42021-02-05

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,663 @@
.uniui-color:before {
content: "\e6cf";
}
.uniui-wallet:before {
content: "\e6b1";
}
.uniui-settings-filled:before {
content: "\e6ce";
}
.uniui-auth-filled:before {
content: "\e6cc";
}
.uniui-shop-filled:before {
content: "\e6cd";
}
.uniui-staff-filled:before {
content: "\e6cb";
}
.uniui-vip-filled:before {
content: "\e6c6";
}
.uniui-plus-filled:before {
content: "\e6c7";
}
.uniui-folder-add-filled:before {
content: "\e6c8";
}
.uniui-color-filled:before {
content: "\e6c9";
}
.uniui-tune-filled:before {
content: "\e6ca";
}
.uniui-calendar-filled:before {
content: "\e6c0";
}
.uniui-notification-filled:before {
content: "\e6c1";
}
.uniui-wallet-filled:before {
content: "\e6c2";
}
.uniui-medal-filled:before {
content: "\e6c3";
}
.uniui-gift-filled:before {
content: "\e6c4";
}
.uniui-fire-filled:before {
content: "\e6c5";
}
.uniui-refreshempty:before {
content: "\e6bf";
}
.uniui-location-filled:before {
content: "\e6af";
}
.uniui-person-filled:before {
content: "\e69d";
}
.uniui-personadd-filled:before {
content: "\e698";
}
.uniui-back:before {
content: "\e6b9";
}
.uniui-forward:before {
content: "\e6ba";
}
.uniui-arrow-right:before {
content: "\e6bb";
}
.uniui-arrowthinright:before {
content: "\e6bb";
}
.uniui-arrow-left:before {
content: "\e6bc";
}
.uniui-arrowthinleft:before {
content: "\e6bc";
}
.uniui-arrow-up:before {
content: "\e6bd";
}
.uniui-arrowthinup:before {
content: "\e6bd";
}
.uniui-arrow-down:before {
content: "\e6be";
}
.uniui-arrowthindown:before {
content: "\e6be";
}
.uniui-bottom:before {
content: "\e6b8";
}
.uniui-arrowdown:before {
content: "\e6b8";
}
.uniui-right:before {
content: "\e6b5";
}
.uniui-arrowright:before {
content: "\e6b5";
}
.uniui-top:before {
content: "\e6b6";
}
.uniui-arrowup:before {
content: "\e6b6";
}
.uniui-left:before {
content: "\e6b7";
}
.uniui-arrowleft:before {
content: "\e6b7";
}
.uniui-eye:before {
content: "\e651";
}
.uniui-eye-filled:before {
content: "\e66a";
}
.uniui-eye-slash:before {
content: "\e6b3";
}
.uniui-eye-slash-filled:before {
content: "\e6b4";
}
.uniui-info-filled:before {
content: "\e649";
}
.uniui-reload:before {
content: "\e6b2";
}
.uniui-micoff-filled:before {
content: "\e6b0";
}
.uniui-map-pin-ellipse:before {
content: "\e6ac";
}
.uniui-map-pin:before {
content: "\e6ad";
}
.uniui-location:before {
content: "\e6ae";
}
.uniui-starhalf:before {
content: "\e683";
}
.uniui-star:before {
content: "\e688";
}
.uniui-star-filled:before {
content: "\e68f";
}
.uniui-calendar:before {
content: "\e6a0";
}
.uniui-fire:before {
content: "\e6a1";
}
.uniui-medal:before {
content: "\e6a2";
}
.uniui-font:before {
content: "\e6a3";
}
.uniui-gift:before {
content: "\e6a4";
}
.uniui-link:before {
content: "\e6a5";
}
.uniui-notification:before {
content: "\e6a6";
}
.uniui-staff:before {
content: "\e6a7";
}
.uniui-vip:before {
content: "\e6a8";
}
.uniui-folder-add:before {
content: "\e6a9";
}
.uniui-tune:before {
content: "\e6aa";
}
.uniui-auth:before {
content: "\e6ab";
}
.uniui-person:before {
content: "\e699";
}
.uniui-email-filled:before {
content: "\e69a";
}
.uniui-phone-filled:before {
content: "\e69b";
}
.uniui-phone:before {
content: "\e69c";
}
.uniui-email:before {
content: "\e69e";
}
.uniui-personadd:before {
content: "\e69f";
}
.uniui-chatboxes-filled:before {
content: "\e692";
}
.uniui-contact:before {
content: "\e693";
}
.uniui-chatbubble-filled:before {
content: "\e694";
}
.uniui-contact-filled:before {
content: "\e695";
}
.uniui-chatboxes:before {
content: "\e696";
}
.uniui-chatbubble:before {
content: "\e697";
}
.uniui-upload-filled:before {
content: "\e68e";
}
.uniui-upload:before {
content: "\e690";
}
.uniui-weixin:before {
content: "\e691";
}
.uniui-compose:before {
content: "\e67f";
}
.uniui-qq:before {
content: "\e680";
}
.uniui-download-filled:before {
content: "\e681";
}
.uniui-pyq:before {
content: "\e682";
}
.uniui-sound:before {
content: "\e684";
}
.uniui-trash-filled:before {
content: "\e685";
}
.uniui-sound-filled:before {
content: "\e686";
}
.uniui-trash:before {
content: "\e687";
}
.uniui-videocam-filled:before {
content: "\e689";
}
.uniui-spinner-cycle:before {
content: "\e68a";
}
.uniui-weibo:before {
content: "\e68b";
}
.uniui-videocam:before {
content: "\e68c";
}
.uniui-download:before {
content: "\e68d";
}
.uniui-help:before {
content: "\e679";
}
.uniui-navigate-filled:before {
content: "\e67a";
}
.uniui-plusempty:before {
content: "\e67b";
}
.uniui-smallcircle:before {
content: "\e67c";
}
.uniui-minus-filled:before {
content: "\e67d";
}
.uniui-micoff:before {
content: "\e67e";
}
.uniui-closeempty:before {
content: "\e66c";
}
.uniui-clear:before {
content: "\e66d";
}
.uniui-navigate:before {
content: "\e66e";
}
.uniui-minus:before {
content: "\e66f";
}
.uniui-image:before {
content: "\e670";
}
.uniui-mic:before {
content: "\e671";
}
.uniui-paperplane:before {
content: "\e672";
}
.uniui-close:before {
content: "\e673";
}
.uniui-help-filled:before {
content: "\e674";
}
.uniui-paperplane-filled:before {
content: "\e675";
}
.uniui-plus:before {
content: "\e676";
}
.uniui-mic-filled:before {
content: "\e677";
}
.uniui-image-filled:before {
content: "\e678";
}
.uniui-locked-filled:before {
content: "\e668";
}
.uniui-info:before {
content: "\e669";
}
.uniui-locked:before {
content: "\e66b";
}
.uniui-camera-filled:before {
content: "\e658";
}
.uniui-chat-filled:before {
content: "\e659";
}
.uniui-camera:before {
content: "\e65a";
}
.uniui-circle:before {
content: "\e65b";
}
.uniui-checkmarkempty:before {
content: "\e65c";
}
.uniui-chat:before {
content: "\e65d";
}
.uniui-circle-filled:before {
content: "\e65e";
}
.uniui-flag:before {
content: "\e65f";
}
.uniui-flag-filled:before {
content: "\e660";
}
.uniui-gear-filled:before {
content: "\e661";
}
.uniui-home:before {
content: "\e662";
}
.uniui-home-filled:before {
content: "\e663";
}
.uniui-gear:before {
content: "\e664";
}
.uniui-smallcircle-filled:before {
content: "\e665";
}
.uniui-map-filled:before {
content: "\e666";
}
.uniui-map:before {
content: "\e667";
}
.uniui-refresh-filled:before {
content: "\e656";
}
.uniui-refresh:before {
content: "\e657";
}
.uniui-cloud-upload:before {
content: "\e645";
}
.uniui-cloud-download-filled:before {
content: "\e646";
}
.uniui-cloud-download:before {
content: "\e647";
}
.uniui-cloud-upload-filled:before {
content: "\e648";
}
.uniui-redo:before {
content: "\e64a";
}
.uniui-images-filled:before {
content: "\e64b";
}
.uniui-undo-filled:before {
content: "\e64c";
}
.uniui-more:before {
content: "\e64d";
}
.uniui-more-filled:before {
content: "\e64e";
}
.uniui-undo:before {
content: "\e64f";
}
.uniui-images:before {
content: "\e650";
}
.uniui-paperclip:before {
content: "\e652";
}
.uniui-settings:before {
content: "\e653";
}
.uniui-search:before {
content: "\e654";
}
.uniui-redo-filled:before {
content: "\e655";
}
.uniui-list:before {
content: "\e644";
}
.uniui-mail-open-filled:before {
content: "\e63a";
}
.uniui-hand-down-filled:before {
content: "\e63c";
}
.uniui-hand-down:before {
content: "\e63d";
}
.uniui-hand-up-filled:before {
content: "\e63e";
}
.uniui-hand-up:before {
content: "\e63f";
}
.uniui-heart-filled:before {
content: "\e641";
}
.uniui-mail-open:before {
content: "\e643";
}
.uniui-heart:before {
content: "\e639";
}
.uniui-loop:before {
content: "\e633";
}
.uniui-pulldown:before {
content: "\e632";
}
.uniui-scan:before {
content: "\e62a";
}
.uniui-bars:before {
content: "\e627";
}
.uniui-cart-filled:before {
content: "\e629";
}
.uniui-checkbox:before {
content: "\e62b";
}
.uniui-checkbox-filled:before {
content: "\e62c";
}
.uniui-shop:before {
content: "\e62f";
}
.uniui-headphones:before {
content: "\e630";
}
.uniui-cart:before {
content: "\e631";
}

View File

@ -1,7 +1,7 @@
{
"id": "uni-icons",
"displayName": "uni-icons 图标",
"version": "1.1.5",
"version": "1.3.5",
"description": "图标组件,用于展示移动端常见的图标,可自定义颜色、大小。",
"keywords": [
"uni-ui",
@ -11,7 +11,7 @@
],
"repository": "https://github.com/dcloudio/uni-ui",
"engines": {
"HBuilderX": ""
"HBuilderX": "^3.2.14"
},
"directories": {
"example": "../../temps/example_temps"
@ -40,7 +40,7 @@
"npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui"
},
"uni_modules": {
"dependencies": [],
"dependencies": ["uni-scss"],
"encrypt": [],
"platforms": {
"cloud": {
@ -75,6 +75,10 @@
"快应用": {
"华为": "u",
"联盟": "u"
},
"Vue": {
"vue2": "y",
"vue3": "y"
}
}
}

View File

@ -1,46 +1,8 @@
## Icons 图标
> **组件名uni-icons**
> 代码块: `uIcons`
用于展示 icons 图标 。
### 安装方式
本组件符合[easycom](https://uniapp.dcloud.io/collocation/pages?id=easycom)规范,`HBuilderX 2.5.5`起,只需将本组件导入项目,在页面`template`中即可直接使用,无需在页面中`import`和注册`components`。
如需通过`npm`方式使用`uni-ui`组件,另见文档:[https://ext.dcloud.net.cn/plugin?id=55](https://ext.dcloud.net.cn/plugin?id=55)
### 基本用法
在 ``template`` 中使用组件
```html
<uni-icons type="contact" size="30"></uni-icons>
```
## API
### Icons Props
|属性名 |类型 |默认值 |说明 |
|:-: |:-: |:-: |:-: |
|size |Number |24 |图标大小 |
|type |String |- |图标图案,参考示例 |
|color |String |- |图标颜色 |
### Icons Events
|事件名 |说明 |返回值|
|:-: |:-: |:-: |
|@click|点击 Icon 触发事件|- |
## 组件示例
点击查看:[https://hellouniapp.dcloud.net.cn/pages/extUI/icons/icons](https://hellouniapp.dcloud.net.cn/pages/extUI/icons/icons)
### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-icons)
#### 如使用过程中有任何问题或者您对uni-ui有一些好的建议欢迎加入 uni-ui 交流群871950839

View File

@ -0,0 +1,19 @@
## 1.3.32022-01-20
- 新增 showText属性 ,是否显示文本
## 1.3.22022-01-19
- 修复 nvue 平台下不显示文本的bug
## 1.3.12022-01-19
- 修复 微信小程序平台样式选择器报警告的问题
## 1.3.02021-11-19
- 优化 组件UI并提供设计资源详见:[https://uniapp.dcloud.io/component/uniui/resource](https://uniapp.dcloud.io/component/uniui/resource)
- 文档迁移,详见:[https://uniapp.dcloud.io/component/uniui/uni-load-more](https://uniapp.dcloud.io/component/uniui/uni-load-more)
## 1.2.12021-08-24
- 新增 支持国际化
## 1.2.02021-07-30
- 组件兼容 vue3如何创建vue3项目详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834)
## 1.1.82021-05-12
- 新增 组件示例地址
## 1.1.72021-03-30
- 修复 uni-load-more 在首页使用时h5 平台报 'uni is not defined' 的 bug
## 1.1.62021-02-05
- 调整为uni_modules目录规范

View File

@ -0,0 +1,5 @@
{
"uni-load-more.contentdown": "Pull up to show more",
"uni-load-more.contentrefresh": "loading...",
"uni-load-more.contentnomore": "No more data"
}

View File

@ -0,0 +1,8 @@
import en from './en.json'
import zhHans from './zh-Hans.json'
import zhHant from './zh-Hant.json'
export default {
en,
'zh-Hans': zhHans,
'zh-Hant': zhHant
}

View File

@ -0,0 +1,5 @@
{
"uni-load-more.contentdown": "上拉显示更多",
"uni-load-more.contentrefresh": "正在加载...",
"uni-load-more.contentnomore": "没有更多数据了"
}

View File

@ -0,0 +1,5 @@
{
"uni-load-more.contentdown": "上拉顯示更多",
"uni-load-more.contentrefresh": "正在加載...",
"uni-load-more.contentnomore": "沒有更多數據了"
}

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,86 @@
{
"id": "uni-load-more",
"displayName": "uni-load-more 加载更多",
"version": "1.3.3",
"description": "LoadMore 组件,常用在列表里面,做滚动加载使用。",
"keywords": [
"uni-ui",
"uniui",
"加载更多",
"load-more"
],
"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-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"
}
}
}
}
}

View File

@ -0,0 +1,14 @@
### LoadMore 加载更多
> **组件名uni-load-more**
> 代码块: `uLoadMore`
用于列表中,做滚动加载使用,展示 loading 的各种状态。
### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-load-more)
#### 如使用过程中有任何问题或者您对uni-ui有一些好的建议欢迎加入 uni-ui 交流群871950839

View File

@ -0,0 +1,37 @@
## 1.3.42022-01-24
- 更新 组件示例
## 1.3.32022-01-24
- 新增 left-width/right-width属性 ,可修改左右两侧的宽度
## 1.3.22022-01-18
- 修复 在vue下标题不垂直居中的bug
## 1.3.12022-01-18
- 修复 height 属性类型错误
## 1.3.02022-01-18
- 新增 height 属性,可修改组件高度
- 新增 dark 属性可可开启暗黑模式
- 优化 标题字数过多显示省略号
- 优化 插槽,插入内容可完全覆盖
## 1.2.12022-01-10
- 修复 color 属性不生效的bug
## 1.2.02021-11-19
- 优化 组件UI并提供设计资源详见:[https://uniapp.dcloud.io/component/uniui/resource](https://uniapp.dcloud.io/component/uniui/resource)
- 文档迁移,详见:[https://uniapp.dcloud.io/component/uniui/uni-nav-bar](https://uniapp.dcloud.io/component/uniui/uni-nav-bar)
## 1.1.02021-07-30
- 组件兼容 vue3如何创建vue3项目详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834)
## 1.0.112021-05-12
- 新增 组件示例地址
## 1.0.102021-04-30
- 修复 在nvue下fixed为true宽度不能撑满的Bug
## 1.0.92021-04-21
- 优化 添加依赖 uni-icons, 导入后自动下载依赖
## 1.0.82021-04-14
- uni-ui 修复 uni-nav-bar 当 fixed 属性为 true 时铺不满屏幕的 bug
## 1.0.72021-02-25
- 修复 easycom 下,找不到 uni-status-bar 的bug
## 1.0.62021-02-05
- 优化 组件引用关系通过uni_modules引用组件
## 1.0.52021-02-05
- 调整为uni_modules目录规范

View File

@ -0,0 +1,363 @@
<template>
<view class="uni-navbar" :class="{'uni-dark':dark}">
<view :class="{ 'uni-navbar--fixed': fixed, 'uni-navbar--shadow': shadow, 'uni-navbar--border': border }"
:style="{ 'background-color': themeBgColor }" class="uni-navbar__content">
<status-bar v-if="statusBar" />
<!-- 2022年2月18日style="position: relative;" -->
<view :style="{ color: themeColor,backgroundColor: themeBgColor ,height:navbarHeight}"
class="uni-navbar__header" style="position: relative;">
<!-- 2022年2月18日整体image绝对定位来显示height为110rpx的背景色 -->
<image v-if="mytopimg" style="position: absolute;width: 100%;height: 100%;left: 0;top: 0;" :src="mytopimg"></image>
<view @tap="onClickLeft" class="uni-navbar__header-btns uni-navbar__header-btns-left"
:style="{width:leftIconWidth}">
<slot name="left">
<view class="uni-navbar__content_view" v-if="leftIcon.length > 0">
<uni-icons :color="themeColor" :type="leftIcon" size="20" />
</view>
<view :class="{ 'uni-navbar-btn-icon-left': !leftIcon.length > 0 }" class="uni-navbar-btn-text"
v-if="leftText.length">
<text :style="{ color: themeColor, fontSize: '38rpx' }" style="font-weight: bold;">{{ leftText }}</text>
</view>
</slot>
</view>
<view class="uni-navbar__header-container " @tap="onClickTitle">
<slot>
<view class="uni-navbar__header-container-inner" v-if="title.length>0">
<text class="uni-nav-bar-text uni-ellipsis-1"
:style="{color: themeColor }">{{ title }}</text>
</view>
</slot>
</view>
<view @click="onClickRight" class="uni-navbar__header-btns uni-navbar__header-btns-right"
:style="{width:rightIconWidth}">
<slot name="right">
<view v-if="rightIcon.length">
<uni-icons :color="themeColor" :type="rightIcon" size="22" />
</view>
<view class="uni-navbar-btn-text" v-if="rightText.length && !rightIcon.length">
<text class="uni-nav-bar-right-text" :style="{ color: themeColor}">{{ rightText }}</text>
</view>
</slot>
</view>
</view>
</view>
<view class="uni-navbar__placeholder" v-if="fixed">
<status-bar v-if="statusBar" />
<view class="uni-navbar__placeholder-view" :style="{ height:navbarHeight}" />
</view>
</view>
</template>
<script>
import statusBar from "./uni-status-bar.vue";
const getVal = (val) => typeof val === 'number' ? val + 'px' : val;
/**
* NavBar 自定义导航栏
* @description 导航栏组件主要用于头部导航
* @tutorial https://ext.dcloud.net.cn/plugin?id=52
* @property {Boolean} dark 开启黑暗模式
* @property {String} title 标题文字
* @property {String} leftText 左侧按钮文本
* @property {String} rightText 右侧按钮文本
* @property {String} leftIcon 左侧按钮图标图标类型参考 [Icon 图标](http://ext.dcloud.net.cn/plugin?id=28) type
* @property {String} rightIcon 右侧按钮图标图标类型参考 [Icon 图标](http://ext.dcloud.net.cn/plugin?id=28) type
* @property {String} color 图标和文字颜色
* @property {String} backgroundColor 导航栏背景颜色
* @property {Boolean} fixed = [true|false] 是否固定顶部
* @property {Boolean} statusBar = [true|false] 是否包含状态栏
* @property {Boolean} shadow = [true|false] 导航栏下是否有阴影
* @event {Function} clickLeft 左侧按钮点击时触发
* @event {Function} clickRight 右侧按钮点击时触发
* @event {Function} clickTitle 中间标题点击时触发
*/
export default {
name: "UniNavBar",
components: {
statusBar
},
emits: ['clickLeft', 'clickRight', 'clickTitle'],
props: {
dark: {
type: Boolean,
default: false
},
title: {
type: String,
default: ""
},
leftText: {
type: String,
default: ""
},
rightText: {
type: String,
default: ""
},
leftIcon: {
type: String,
default: ""
},
rightIcon: {
type: String,
default: ""
},
fixed: {
type: [Boolean, String],
default: false
},
color: {
type: String,
default: ""
},
backgroundColor: {
type: String,
default: ""
},
mytopimg: {
type: String,
default: ""
},
statusBar: {
type: [Boolean, String],
default: false
},
shadow: {
type: [Boolean, String],
default: false
},
border: {
type: [Boolean, String],
default: true
},
height: {
type: [Number, String],
default: 44
},
leftWidth: {
type: [Number, String],
default: 60
},
rightWidth: {
type: [Number, String],
default: 60
},
},
computed: {
themeBgColor() {
if (this.dark) {
//
if (this.backgroundColor) {
return this.backgroundColor
} else {
return this.dark ? '#333' : '#FFF'
}
}
return this.backgroundColor || '#FFF'
},
themeColor() {
if (this.dark) {
//
if (this.color) {
return this.color
} else {
return this.dark ? '#fff' : '#333'
}
}
return this.color || '#333'
},
navbarHeight() {
return getVal(this.height)
},
leftIconWidth() {
return getVal(this.leftWidth)
},
rightIconWidth() {
return getVal(this.rightWidth)
}
},
mounted() {
if (uni.report && this.title !== '') {
uni.report('title', this.title)
}
},
methods: {
onClickLeft() {
this.$emit("clickLeft");
},
onClickRight() {
this.$emit("clickRight");
},
onClickTitle() {
this.$emit("clickTitle");
}
}
};
</script>
<style lang="scss" scoped>
$nav-height: 44px;
.uni-navbar {
// box-sizing: border-box;
}
.uni-nav-bar-text {
/* #ifdef APP-PLUS */
font-size: 34rpx;
/* #endif */
/* #ifndef APP-PLUS */
font-size: 14px;
/* #endif */
}
.uni-nav-bar-right-text {
font-size: 12px;
}
.uni-navbar__content {
position: relative;
// background-color: #fff;
// box-sizing: border-box;
background-color: transparent;
}
.uni-navbar__content_view {
// box-sizing: border-box;
}
.uni-navbar-btn-text {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: column;
justify-content: flex-start;
align-items: center;
/*
line-height: 12px;
*/
}
.uni-navbar__header {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
/*
padding: 0 10px;
*/
padding: 0 18rpx;
flex-direction: row;
height: $nav-height;
font-size: 12px;
/*
background-image: url("@/static/workbench/bgimg.png");
background-position: center top;
background-size: 100%;
*/
}
.uni-navbar__header-btns {
/* #ifndef APP-NVUE */
overflow: hidden;
display: flex;
/* #endif */
flex-wrap: nowrap;
flex-direction: row;
width: 120rpx;
// padding: 0 6px;
justify-content: center;
align-items: center;
/* #ifdef H5 */
cursor: pointer;
/* #endif */
}
.uni-navbar__header-btns-left {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
width: 120rpx;
justify-content: flex-start;
align-items: center;
// 2022218
z-index: 11111;
position: relative;
}
.uni-navbar__header-btns-right {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: row;
// width: 150rpx;
// padding-right: 30rpx;
justify-content: flex-end;
align-items: center;
}
.uni-navbar__header-container {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex: 1;
padding: 0 10px;
overflow: hidden;
}
.uni-navbar__header-container-inner {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex: 1;
flex-direction: row;
align-items: center;
justify-content: center;
font-size: 12px;
overflow: hidden;
// box-sizing: border-box;
}
.uni-navbar__placeholder-view {
height: $nav-height;
}
.uni-navbar--fixed {
position: fixed;
z-index: 998;
/* #ifdef H5 */
left: var(--window-left);
right: var(--window-right);
/* #endif */
/* #ifndef H5 */
left: 0;
right: 0;
/* #endif */
}
.uni-navbar--shadow {
box-shadow: 0 1px 6px #ccc;
}
.uni-navbar--border {
border-bottom-width: 1rpx;
border-bottom-style: solid;
border-bottom-color: #eee;
}
.uni-ellipsis-1 {
overflow: hidden;
/* #ifndef APP-NVUE */
white-space: nowrap;
text-overflow: ellipsis;
/* #endif */
/* #ifdef APP-NVUE */
lines: 1;
text-overflow: ellipsis;
/* #endif */
}
//
.uni-dark {}
</style>

View File

@ -0,0 +1,28 @@
<template>
<view :style="{ height: statusBarHeight }" class="uni-status-bar">
<slot />
</view>
</template>
<script>
export default {
name: 'UniStatusBar',
data() {
return {
statusBarHeight: 20
}
},
mounted() {
this.statusBarHeight = uni.getSystemInfoSync().statusBarHeight + 'px'
}
}
</script>
<style lang="scss" >
.uni-status-bar {
// width: 750rpx;
height: 20px;
background-color: #fff;
// height: var(--status-bar-height);
}
</style>

View File

@ -0,0 +1,89 @@
{
"id": "uni-nav-bar",
"displayName": "uni-nav-bar 自定义导航栏",
"version": "1.3.4",
"description": "自定义导航栏组件,主要用于头部导航。",
"keywords": [
"uni-ui",
"导航",
"导航栏",
"自定义导航栏"
],
"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-scss",
"uni-icons"
],
"encrypt": [],
"platforms": {
"cloud": {
"tcb": "y",
"aliyun": "y"
},
"client": {
"App": {
"app-vue": "y",
"app-nvue": "y"
},
"H5-mobile": {
"Safari": "y",
"Android Browser": "y",
"微信浏览器(Android)": "y",
"QQ浏览器(Android)": "y"
},
"H5-pc": {
"Chrome": "y",
"IE": "y",
"Edge": "y",
"Firefox": "y",
"Safari": "y"
},
"小程序": {
"微信": "y",
"阿里": "y",
"百度": "y",
"字节跳动": "y",
"QQ": "y"
},
"快应用": {
"华为": "u",
"联盟": "u"
},
"Vue": {
"vue2": "y",
"vue3": "y"
}
}
}
}
}

View File

@ -0,0 +1,15 @@
## NavBar 导航栏
> **组件名uni-nav-bar**
> 代码块: `uNavBar`
导航栏组件,主要用于头部导航。
### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-nav-bar)
#### 如使用过程中有任何问题或者您对uni-ui有一些好的建议欢迎加入 uni-ui 交流群871950839

View File

@ -0,0 +1,8 @@
## 1.0.32022-01-21
- 优化 组件示例
## 1.0.22021-11-22
- 修复 / 符号在 vue 不同版本兼容问题引起的报错问题
## 1.0.12021-11-22
- 修复 vue3中scss语法兼容问题
## 1.0.02021-11-18
- init

View File

@ -0,0 +1 @@
@import './styles/index.scss';

View File

@ -0,0 +1,82 @@
{
"id": "uni-scss",
"displayName": "uni-scss 辅助样式",
"version": "1.0.3",
"description": "uni-sass是uni-ui提供的一套全局样式 通过一些简单的类名和sass变量实现简单的页面布局操作比如颜色、边距、圆角等。",
"keywords": [
"uni-scss",
"uni-ui",
"辅助样式"
],
"repository": "https://github.com/dcloudio/uni-ui",
"engines": {
"HBuilderX": "^3.1.0"
},
"dcloudext": {
"category": [
"JS SDK",
"通用 SDK"
],
"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": [],
"encrypt": [],
"platforms": {
"cloud": {
"tcb": "y",
"aliyun": "y"
},
"client": {
"App": {
"app-vue": "y",
"app-nvue": "u"
},
"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"
},
"快应用": {
"华为": "n",
"联盟": "n"
},
"Vue": {
"vue2": "y",
"vue3": "y"
}
}
}
}
}

View File

@ -0,0 +1,4 @@
`uni-sass``uni-ui`提供的一套全局样式 ,通过一些简单的类名和`sass`变量,实现简单的页面布局操作,比如颜色、边距、圆角等。
### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-sass)
#### 如使用过程中有任何问题或者您对uni-ui有一些好的建议欢迎加入 uni-ui 交流群871950839

View File

@ -0,0 +1,7 @@
@import './setting/_variables.scss';
@import './setting/_border.scss';
@import './setting/_color.scss';
@import './setting/_space.scss';
@import './setting/_radius.scss';
@import './setting/_text.scss';
@import './setting/_styles.scss';

Some files were not shown because too many files have changed in this diff Show More