f0ab4214 by 杨炀

no message

1 parent 4c57b42c
Showing 65 changed files with 808 additions and 2869 deletions
......@@ -493,6 +493,36 @@ function getMergePaymentInfo(mergeId) {
}
})
}
// 一键下发
function submitCert(data) {
return request({
url: `/exam/payment/submitCerts/nesting`,
method: 'put',
params: data
})
}
function getCertsLList(query) {
return request({
url: '/exam/payment/certsList',
method: 'get',
params: query
})
}
function getExamListByPayId(params) {
return request({
url: `/exam/payment/examList/${params.payId}`,
method: 'get',
params: params
})
}
function certStudentList(query) {
return request({
url: '/exam/person/cert/studentList',
method: 'get',
params: query
})
}
export {
getMessage,
......@@ -539,5 +569,7 @@ export {
groupCommitPaymentVoucher,getFeeBillById,
personalCommit,
delPayment,editYear,addPersonPaymentGroup,
commitRenew,getVerityMergeList,doMergeFlows,getMergePaymentInfo
commitRenew,getVerityMergeList,doMergeFlows,getMergePaymentInfo,
submitCert,getCertsLList,getExamListByPayId,
certStudentList
}
\ No newline at end of file
......
......@@ -147,7 +147,16 @@ color: #7D8592;}
font-weight: 500;color: #0A1629;
}
.mt30{margin-top: 30rpx;}
.userlist {
.userlist {
.func{display: flex;justify-content: flex-end;
border-top: 1px dashed #e5e5e5;padding-top: 20rpx;
button{border: 1px solid #AD181F;
border-radius: 30rpx;height: 60rpx;line-height: 60rpx;
font-size: 30rpx;color: #AD181F;background: #fff;
margin: 0 0 0 30rpx;padding: 0 60rpx;
}
text{font-size: 30rpx;padding:30rpx 0 0;}
}
.colorful {
width: 100rpx;
margin-right: 14rpx;
......
<template>
<view class="content">
<swiper class="swiper"
:autoplay="autoplay"
:duration="duration">
<swiper-item>
<view class="swiper-item">
<view class="swiper-item-img"><image src="../../static/guide/title_01.png" mode="aspectFit"></image></view>
<view class="swiper-item-img"><image src="../../static/guide/icon_01.png" mode="aspectFit"></image></view>
</view>
<view class="jump-over" @tap="launchFlag()">{{jumpover}}</view>
</swiper-item>
<swiper-item>
<view class="swiper-item">
<view class="swiper-item-img"><image src="../../static/guide/title_02.png" mode="aspectFit"></image></view>
<view class="swiper-item-img"><image src="../../static/guide/icon_02.png" mode="aspectFit"></image></view>
</view>
<view class="jump-over" @tap="launchFlag()">{{jumpover}}</view>
</swiper-item>
<swiper-item>
<view class="swiper-item">
<view class="swiper-item-img"><image src="../../static/guide/title_03.png" mode="aspectFit"></image></view>
<view class="swiper-item-img"><image src="../../static/guide/icon_03.png" mode="aspectFit"></image></view>
</view>
<view class="jump-over" @tap="launchFlag()">{{jumpover}}</view>
</swiper-item>
<swiper-item>
<view class="swiper-item">
<view class="swiper-item-img"><image src="../../static/guide/title_04.png" mode="aspectFit"></image></view>
<view class="swiper-item-img"><image src="../../static/guide/icon_04.png" mode="aspectFit"></image></view>
</view>
<view class="experience" @tap="launchFlag()">{{experience}}</view>
</swiper-item>
</swiper>
<view class="uniapp-img"><image src="../../static/guide/uniapp4@2x.png" mode="aspectFit"></image></view>
</view>
</template>
<script>
export default {
data() {
return {
background: ['color1', 'color2', 'color3'],
autoplay: false,
duration: 500,
jumpover: '跳过',
experience: '立即体验'
}
},
methods: {
launchFlag: function(){
/**
* 向本地存储中设置launchFlag的值,即启动标识;
*/
uni.setStorage({
key: 'launchFlag',
data: true,
});
uni.switchTab({
url: '/pages/tabBar/component/component'
});
}
}
}
</script>
<style>
page,
.content{
width: 100%;
height: 100%;
background-size: 100% auto ;
padding: 0;
}
.swiper{
width: 100%;
height: 80%;
background: #FFFFFF;
}
.swiper-item {
width: 100%;
height: 100%;
text-align: center;
position: relative;
display: flex;
/* justify-content: center; */
align-items:flex-end;
flex-direction:column-reverse
}
.swiper-item-img{
width: 100%;
height: auto;
margin: 0 auto;
}
.swiper-item-img image{
width: 80%;
}
.uniapp-img{
height: 20%;
background: #FFFFFF;
display: flex;
justify-content: center;
align-items:center;
overflow: hidden;
}
.uniapp-img image{
width: 40%;
}
.jump-over,.experience{
position: absolute;
height: 60upx;
line-height: 60upx;
padding: 0 40upx;
border-radius: 30upx;
font-size: 32upx;
color: #454343;
border: 1px solid #454343;
z-index: 999;
}
.jump-over{
right: 45upx;
top: 125upx;
}
.experience{
right: 50%;
margin-right: -105upx;
bottom: 0;
}
</style>
# 引导页
### 基于uni-app框架的swiper组件打开的时候启动。
> 首次启动展示引导页,之后启动不再展示。那么就意味着,我们需要一个标识来确定,App是否已经启动过。
> 我们可以在本地存储一个key来做为已经启动过App的标识。那么,我们在入口这里,就可以读取这个key,来决定是否展示引导页。
> 因工作繁忙目前该程序金对安卓做了适配,IOS可根据环境自己适配。谢谢
## 目录结构
* /pages/index/index.vue //入口页
### 存储key
* 向本地存储中设置launchFlag的值,即启动标识;
### 获取key
* 向本地存储中设置launchFlag的值,即启动标识;
* 获取本地存储中launchFlag的值
* 若存在,说明不是首次启动,直接进入首页;
* 若不存在,说明是首次启动,进入引导页;
```html
<view class="main">
<code-elf-guide v-if="guidePages"></code-elf-guide>
</view>
```
```javascript
import codeElfGuide from '@/components/code-elf-guide/code-elf-guide.vue'
export default {
components: {
codeElfGuide
},
data() {
return {
guidePages:true
}
},
onLoad(){
this.loadExecution()
},
methods: {
loadExecution: function(){
/**
* 获取本地存储中launchFlag的值
* 若存在,说明不是首次启动,直接进入首页;
* 若不存在,说明是首次启动,进入引导页;
*/
try {
// 获取本地存储中launchFlag标识
const value = uni.getStorageSync('launchFlag');
if (value) {
// launchFlag=true直接跳转到首页
uni.switchTab({
url: '/pages/tabBar/component/component'
});
} else {
// launchFlag!=true显示引导页
this.guidePages = true
}
} catch(e) {
// error
uni.setStorage({
key: 'launchFlag',
data: true,
success: function () {
console.log('error时存储launchFlag');
}
});
this.guidePages = true
}
}
}
}
```
```css
page,.main{
width: 100%;
height: 100%;
}
```
### 首页清除key,进行测试
* 清除本地存储中设置launchFlag的值,即启动标识;
* 两秒后重启APP,进行测试
```javascript
uni.showModal({
title: '清除launchFlag值',
content: '确定要清除launchFlag值,进行重启测试?',
success: function (res) {
if (res.confirm) {
console.log('用户点击确定');
// 清除缓存
uni.clearStorage();
uni.showToast({
icon: 'none',
duration:3000,
title: '清除成功2秒后重启'
});
// 两秒后重启
setTimeout(function() {
uni.hideToast();
plus.runtime.restart();
}, 2000);
} else if (res.cancel) {
console.log('用户点击取消');
}
}
});
```
\ No newline at end of file
# 日历组件 lx-calendar可选择周与月支持左右滑动切换
```
<template>
<view class="content">
<lxCalendar @change="change"></lxCalendar>
</view>
</template>
<script>
import lxCalendar from '../../components/lx-calendar/lx-calendar.vue'
export default {
components:{
lxCalendar,
},
data() {
return {
title: 'Hello'
}
},
onLoad() {
},
methods: {
change(e){
console.log(e);
}
}
}
</script>
```
事件 | 说明
---|---
change | 日期改变时执行
参数 | 类型 | 说明
---|---|---
value | 字符串 | 选中的日期
dot_lists | 数组 | 显示点的日期
<template>
<view class="date">
<view class="head" hidden>
<view class="icon" @click="switch_month_week('prev',true)"><text class="iconfont icon-fanhui" /></view>
<view class="title">{{nowYear+'年'+nowMonth+'月'}}</view>
<view class="icon" @click="switch_month_week('next',true)"><text class="iconfont next icon-fanhui" /></view>
</view>
<view class="date_dl">
<view class="dd" v-for="(item,index) in week" :key="index">{{item}}</view>
</view>
<view class="bigMonthInBottom">{{nowMonth+'月'}}</view>
<swiper :style="{height:(retract ? 2 * 60 : (week_list.length + 1) * 60 ) + 'rpx'}" :current="current" circular
@change="change_date">
<swiper-item>
<view class="date_dl" v-show="!retract || index == to_prev_week_index"
v-for="(item,index) in week_list_prev_co" :key="index">
<view class="dd" @click="item_click(vo,index,key)" v-for="(vo,key) in item" :key="key">
<view class="num"
:class="[vo.today ? 'today' : '',vo.cantOrder?'cantOrder':'',vo.type == 'month' ? 'month' : (retract ? '' : 'disabled')]">
{{vo.day}}
</view>
<view v-show="vo.dot && (vo.type == 'month' || retract)" class="dot"></view>
</view>
</view>
<view @click="open" class="retract icon"><text class="iconfont next icon-fanhui"
:class="[retract ? '' : 'retract_icon']" /></view>
</swiper-item>
<swiper-item>
<view class="date_dl" v-show="!retract || index == to_week_index" v-for="(item,index) in week_list"
:key="index">
<view class="dd" @click="item_click(vo,index,key)" v-for="(vo,key) in item" :key="key">
<view class="num"
:class="[vo.today ? 'today' : '',vo.cantOrder?'cantOrder':'',vo.type == 'month' ? 'month' : (retract ? '' : 'disabled')]">
{{vo.day}}
</view>
<view v-show="vo.dot && (vo.type == 'month' || retract)" class="dot"></view>
</view>
</view>
<view @click="open" class="retract icon"><text class="iconfont next icon-fanhui"
:class="[retract ? '' : 'retract_icon']" /></view>
</swiper-item>
<swiper-item>
<view class="date_dl" v-show="!retract || index == to_next_week_index"
v-for="(item,index) in week_list_next_co" :key="index">
<view class="dd" @click="item_click(vo,index,key)" v-for="(vo,key) in item" :key="key">
<view class="num"
:class="[vo.today ? 'today' : '',vo.cantOrder?'cantOrder':'',vo.type == 'month' ? 'month' : (retract ? '' : 'disabled')]">
{{vo.day}}
</view>
<view v-show="vo.dot && (vo.type == 'month' || retract)" class="dot"></view>
</view>
</view>
<view @click="open" class="retract icon"><text class="iconfont next icon-fanhui"
:class="[retract ? '' : 'retract_icon']" /></view>
</swiper-item>
</swiper>
</view>
</template>
<script>
import dayjs from 'dayjs';
export default {
props: {
value: {
type: [String, Number],
default: ''
},
dot_lists: {
type: Array,
default: () => {
return [];
}
},
startTime: {
type: Number,
default: 0
},
endTime: {
type: Number,
default: 0
}
},
data() {
return {
debug: false,
week: ['日', '一', '二', '三', '四', '五', '六'],
week_list: [],
week_list_prev: [],
week_list_prev_week: [],
week_list_next: [],
week_list_next_week: [],
now_date: '',
start_date: '',
end_date: '',
prev_date: '',
next_date: '',
nowYear: '',
nowMonth: '',
nowDay: '',
retract: true,
to_week_index: 0,
to_prev_week_index: 0,
to_next_week_index: 0,
nowTime: 0,
dot_list: [],
current: 1,
date: '',
cantOrder: false
}
},
watch: {
value(value) {
this.get_date(this.date_parse(value));
},
dot_lists: {
immediate: true,
handler(value) {
this.dot_list = value;
this.set_doc_lists_update()
}
},
endTime:{
handler(value) {
this.doc_list_update()
}
}
},
computed: {
week_list_prev_co() {
return this.retract ? this.week_list_prev_week : this.week_list_prev
},
week_list_next_co() {
return this.retract ? this.week_list_next_week : this.week_list_next
}
},
created() {
this.init();
},
mounted() {
// this.doc_list_update();
},
methods: {
change() {
let value = {
fulldate: this.date.replace(/-(\d)(?!\d)/g, '-0$1')
};
this.$emit('change', value)
},
init() {
if (this.value) {
this.get_date(this.date_parse(this.value));
} else {
this.get_date();
}
this.update_month();
},
open() {
this.retract = !this.retract;
this.get_date(this.nowTime);
this.set_to_day('week_list_prev')
this.set_to_day('week_list_next')
this.change_week();
if (this.retract) {
this.update_swiper_item('week')
} else {
this.update_swiper_item('month')
}
this.set_doc_lists_update();
},
change_week() {
if (this.to_week_index < this.week_list.length - 1) {
this.to_next_week_index = this.to_week_index + 1;
this.week_list_next_week = this.week_list;
} else {
this.to_next_week_index = 0;
this.week_list_next_week = this.week_list_next;
}
if (this.to_week_index == 0) {
this.update_month();
// if(){
let next_day = this.week_list_prev[this.week_list_prev.length - 1][6].day;
// }
this.to_prev_week_index = this.week_list_prev.length - 1 - Math.ceil(next_day / 7);
this.week_list_prev_week = JSON.parse(JSON.stringify(this.week_list_prev));
} else {
this.to_prev_week_index = this.to_week_index - 1;
this.week_list_prev_week = this.week_list;
}
// if(this.current == 1){
// }
// let to_week_index = this.to_week_index;
// if(this.current == 2){
// this.to_next_week_index = this.to_week_index;
// this.to_week_index = this.to_week_index - 1;
// this.to_prev_week_index = this.to_next_week_index + 1;
// }else if(this.current == 0){
// this.to_next_week_index = this.to_week_index;
// this.to_week_index = this.to_week_index - 1;
// this.to_prev_week_index = this.to_next_week_index + 1;
// }
},
change_date_week(type) {
let week_list = this.week_list;
let to_week_index = this.to_week_index;
if (type == 'prev') {
this.to_week_index = this.to_prev_week_index;
this.to_prev_week_index = this.to_next_week_index
this.to_next_week_index = to_week_index;
this.week_list = this.week_list_prev_week
this.week_list_prev_week = this.week_list_next_week;
this.week_list_next_week = week_list;
} else if (type == 'next') {
this.to_week_index = this.to_next_week_index;
this.to_next_week_index = this.to_prev_week_index
this.to_prev_week_index = to_week_index;
this.week_list = this.week_list_next_week
this.week_list_next_week = this.week_list_prev_week;
this.week_list_prev_week = week_list;
}
this.set_to_day_all();
},
change_date_month(type) {
let week_list = this.week_list;
if (type == 'prev') {
this.week_list = this.week_list_prev
this.week_list_prev = this.week_list_next;
this.week_list_next = week_list;
} else if (type == 'next') {
this.week_list = this.week_list_next
this.week_list_next = this.week_list_prev;
this.week_list_prev = week_list;
}
},
change_date(e) {
if (this.current == e.detail.current) {
this.change()
return
}
let primary_current = this.current
let current = e.detail.current;
this.current = current;
if (primary_current - current == -1 || primary_current - current == 2) {
if (this.retract) {
this.switch_month_week('next')
this.change_week()
if (primary_current - current == -1 && current != 1) {
this.change_date_week('prev')
} else if (primary_current - current == 2) {
this.change_date_week('next')
}
} else {
this.get_date(this.get_month('next'));
this.update_month();
if (primary_current - current == -1 && current != 1) {
this.change_date_month('prev')
} else if (primary_current - current == 2) {
this.change_date_month('next')
}
}
} else {
if (this.retract) {
this.switch_month_week('prev')
this.change_week()
if (primary_current - current == 1 && current != 1) {
this.change_date_week('next')
} else if (primary_current - current == -2) {
this.change_date_week('prev')
}
} else {
this.get_date(this.get_month('prev'));
this.update_month();
if (primary_current - current == 1 && current != 1) {
this.change_date_month('next')
} else if (primary_current - current == -2) {
this.change_date_month('prev')
}
}
}
this.set_to_day_all();
this.set_doc_lists_update();
this.change()
},
update_month() {
this.get_date(this.get_month('prev'), 'prev');
this.get_date(this.get_month('next'), 'next');
},
set_doc_lists_update() {
this.doc_list_update('week_list');
this.doc_list_update('week_list_prev');
this.doc_list_update('week_list_next');
this.doc_list_update('week_list_prev_week')
this.doc_list_update('week_list_next_week')
},
doc_list_update(week_list = 'week_list') {
let list = [],
dayTime;
this[week_list].map((item, index) => {
list.push(item.map((vo, key) => {
if (this.dot_list.indexOf(vo.date) > -1 || this.dot_list.indexOf(vo.date
.replace(/-(\d)(?!\d)/g, '-0$1')) > -1) {
vo.dot = true;
} else {
vo.dot = false;
}
dayTime = dayjs(vo.date).valueOf()
if (dayTime < this.startTime || (this.endTime != 0 && dayTime >= this
.endTime)) {
vo.cantOrder = true
} else {
vo.cantOrder = false
}
return {
...vo
}
}))
})
this[week_list] = list;
},
set_to_day(type) {
let list = [];
this[type].map((item, index) => {
list.push(item.map((vo, key) => {
if (vo.date == `${this.date}`) {
vo.today = true;
} else {
vo.today = false;
}
return {
...vo
};
}))
})
this[type] = list;
},
item_click(item, item_index = -1) {
if (item.date == this.date) {
return
}
// if(item.cantOrder){
// // 不能预订的
// return
// }
if (!this.retract && item.type !== 'month') {
return false;
}
this.date = item.date;;
if (item.type == 'month') {
this.nowDay = item.day;
if (item_index >= 0) this.to_week_index = item_index;
} else if (this.retract) {
this.nowDay = item.day;
}
let now_arr = item.date.split('-')
this.nowYear = now_arr[0];
this.nowMonth = now_arr[1];
this.nowDay = now_arr[2];
this.set_to_day_all(item_index);
this.nowTime = this.date_parse(`${item.date}`);
this.change()
this.set_doc_lists_update();
},
set_to_day_all(item_index) {
this.set_to_day('week_list')
this.set_to_day('week_list_prev')
this.set_to_day('week_list_next')
this.set_to_day('week_list_prev_week')
this.set_to_day('week_list_next_week')
},
get_month(type) {
let nowMonth = this.nowMonth;
let nowYear = this.nowYear;
let nowDay = this.nowDay;
if (type == 'prev') {
if (nowMonth == 1) {
nowMonth = 12;
nowYear = nowYear - 1;
} else {
nowMonth--;
}
} else if (type == 'next') {
if (nowMonth == 12) {
nowMonth = 1;
nowYear = nowYear + 1;
} else {
nowMonth++;
}
}
let days = this.get_month_days(nowMonth, nowYear);
if (nowDay > days) {
nowDay = days;
}
return this.date_parse(`${nowYear}-${nowMonth}-${nowDay}`);
},
date_parse(str) {
return Date.parse(str.replace(/-(\d)(?!\d)/g, '-0$1'));
},
switch_month_week(type = 'next', update_week = false) {
if (this.retract) {
if (type == 'prev') {
this.get_date(this.nowTime - 86400 * 7 * 1000);
} else if (type == 'next') {
this.get_date(this.nowTime + 86401 * 7 * 1000);
}
if (update_week) {
this.update_swiper_item('week');
this.set_doc_lists_update();
}
} else {
this.get_date(this.get_month(type))
this.update_swiper_item('month');
}
this.set_doc_lists_update();
this.set_to_day_all();
if (update_week) {
this.change()
}
},
update_swiper_item(type = 'month') {
if (type == 'month') {
if (this.current == 0) {
this.change_date_month('next')
} else if (this.current == 2) {
this.change_date_month('prev')
}
} else if (type == 'week') {
if (this.current == 0) {
this.change_date_week('next')
} else if (this.current == 2) {
this.change_date_week('prev')
}
}
},
next() {
this.get_date(this.next_date)
},
get_date(value = '', type = 'same') {
let date = new Date();
if (value) {
date = new Date(value);
}
let nowMonth = date.getMonth() + 1,
nowYear = date.getFullYear(),
nowDay = date.getDate(),
nowTime = date.getTime(),
nowWeek = date.getDay();
let days = this.get_month_days(nowMonth, nowYear);
let start_date = new Date(nowYear, nowMonth - 1, 1);
let end_date = new Date(nowYear, nowMonth - 1, days);
let prev_date = new Date(start_date.getTime() - 1);
let prev_date_days = prev_date.getDate();
let next_date = new Date(end_date.getTime() + 86401 * 1000);
let next_date_days = next_date.getDate();
let start_week = start_date.getDay();
let date_arrs = [];
let week_list = [];
let count_days = 35;
for (let i = prev_date_days - start_week + 1; i <= prev_date_days; i++) {
date_arrs.push({
day: i,
type: 'prev',
date: `${prev_date.getFullYear()}-${prev_date.getMonth()+1}-${i}`
})
}
for (let i = 1; i <= days; i++) {
date_arrs.push({
day: i,
type: 'month',
today: i == nowDay ? true : false,
date: `${nowYear}-${nowMonth}-${i}`
})
if (i == nowDay && type == 'same') {
this.date = `${nowYear}-${nowMonth}-${i}`;
}
}
if (this.debug) console.log(value, date, this.date,
`${next_date.getFullYear()}-${next_date.getMonth()+1}-${next_date.getDate()}`)
let date_arrs_length = date_arrs.length;
// if(date_arrs_length > 35){
count_days = 42;
// }
for (let i = 1; i <= count_days - date_arrs_length; i++) {
date_arrs.push({
day: i,
type: 'next',
date: `${next_date.getFullYear()}-${next_date.getMonth()+1}-${i}`
})
}
for (let i = 0; i < date_arrs.length / 7; i++) {
let arr = [];
for (let j = 0; j < 7; j++) {
if (date_arrs[i * 7 + j].today) {
if (type == 'same') {
this.to_week_index = i
}
}
arr.push(date_arrs[i * 7 + j]);
}
week_list.push(arr);
}
if (type == 'same') {
this.week_list = week_list;
this.nowYear = nowYear;
this.nowMonth = nowMonth;
this.nowDay = nowDay;
this.nowTime = nowTime;
this.start_date = start_date;
this.end_date = end_date;
this.prev_date = prev_date;
this.next_date = next_date;
} else if (type == 'prev') {
this.week_list_prev = week_list;
} else if (type == 'next') {
this.week_list_next = week_list;
}
},
get_month_days(nowMonth, nowYear) {
let month_arr = [1, 3, 5, 7, 8, 10, 12];
let days = 0;
if (nowMonth == 2) {
if (nowYear % 4 == 0) {
days = 29;
} else {
days = 28;
}
} else if (month_arr.indexOf(nowMonth) >= 0) {
days = 31;
} else {
days = 30;
}
return days;
}
}
}
</script>
<style lang="less">
@import (less) '../../static/lx-calendar/fonts/iconfont.css';
@color: #1EC886;
@color_disabled: #f1f1f1;
@color_cantOrder: #999;
@color_standard: #333;
@color_border: #f5f5f5;
.date {
position: relative;
overflow: hidden;
border-radius: 20rpx 20rpx 0px 0px;
width: 750rpx;
background: #F7F8FA;
}
.head {
display: flex;
align-items: center;
height: 100rpx;
justify-content: center;
border-bottom: 1rpx solid @color_border;
color: @color_standard;
.title {
width: 200rpx;
font-size: 30rpx;
text-align: center;
}
.icon {
display: block;
.next {
transform: rotate(180deg);
display: block;
}
}
}
.retract {
display: flex;
justify-content: center;
align-items: center;
height: 80rpx;
;
.iconfont {
transform: rotate(270deg);
&.retract_icon {
transform: rotate(90deg);
}
}
}
.date_dl {
display: flex;
width: 100%;
.dd {
flex: 1;
text-align: center;
height: 60rpx;
font-size: 24rpx;
color: #666666;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
position: relative;
.num {
font-size: 28rpx;
width: 60rpx;
height: 60rpx;
border-radius: 50%;
line-height: 60rpx;
&.month {
color: @color_standard;
}
&.cantOrder {
color: @color_cantOrder;
}
&.today {
background: @color;
color: #fff;
}
&.disabled {
color: @color_disabled;
}
}
.dot {
width: 8rpx;
height: 8rpx;
border-radius: 50%;
background: @color;
position: absolute;
bottom: 0;
left: 50%;
transform: translateX(-50%);
}
}
}
.bigMonthInBottom {
font-size: 160rpx;
color: #c7e0de;
position: absolute;
left: 0;
right: 0;
text-align: center;
top: 140rpx;
}
</style>
# slider-range
uni-app 滑块区间选择组件
可根据具体需求,修改、自定义其他内容。
## 属性说明
|属性名|类型|默认值|说明|
| -- | -- | --|--|
| value | Array<Number, Number> | [0,100] |滑块已选中区间的值|
| min | Number| 0 | 滑块区间最小值 |
| max | Number | 100 | 滑块区间最大值 |
| step | Number | 1 | 拖动时的步长 |
| disabled | Boolean | false | 是否为禁用状态 |
| height | Number | 50 | 滑块容器高度 |
| barHeight | Number | 5 | 滑块进度条高度 |
| backgroundColor | String | #e9e9e9| 滑块进度条背景色|
| activeColor | String | #1aad19 | 已选中区间进度条颜色|
| blockSize | Number | 20 | 滑块大小 |
| blockColor | String | #fff | 滑块颜色 |
| decorationVisible | Boolean | false | 是否显示滑块内装饰元素|
| tipVisible | Boolean | true | 是否显示滑块值提示文本 |
| fomat| Function | | 滑块值提示文本格式化函数,**注意**:小程序中此属性必传,否则会报错,如果无需格式化,可以简单返回原始值: `format(val) { return val }`;H5中可以不传。|
## 使用示例
```html
<slider-range
:value="rangeValue"
:min="rangeMin"
:max="rangMax"
:step="5"
:bar-height="3"
:block-size="26"
background-color="#EEEEF6"
active-color="#FF6B00"
:format="format"
:decorationVisible="true"
@change="handleRangeChange"
></slider-range>
```
```javascript
import SliderRange from '../components/slider-range/index.vue'
export default {
components: {
SliderRange
},
data() {
return {
rangeMin: 5,
rangMax: 200,
rangeValue: [10, 50]
}
},
methods: {
format(val) {
return val + '%'
},
handleRangeChange(e) {
this.rangeValue = e
}
}
}
```
效果图
![](http://images.alisali.cn/img_20190715175325.png)
<template>
<view
class="slider-range"
:class="{ disabled: disabled }"
:style="{ paddingLeft: blockSize / 2 + 'px', paddingRight: blockSize / 2 + 'px' }"
>
<view class="slider-range-inner" :style="{ height: height + 'px' }">
<view
class="slider-bar"
:style="{
height: barHeight + 'px',
}"
>
<!-- 背景条 -->
<view
class="slider-bar-bg"
:style="{
backgroundColor: backgroundColor,
}"
></view>
<!-- 滑块实际区间 -->
<view
class="slider-bar-inner"
:style="{
width: ((values[1] - values[0]) / (max - min)) * 100 + '%',
left: lowerHandlePosition + '%',
backgroundColor: activeColor,
}"
></view>
</view>
<!-- 滑动块-左 -->
<view
class="slider-handle-block"
:class="{ decoration: decorationVisible }"
:style="{
backgroundColor: blockColor,
width: blockSize + 'px',
height: blockSize + 'px',
left: lowerHandlePosition + '%',
}"
@touchstart="_onTouchStart"
@touchmove="_onBlockTouchMove"
@touchend="_onBlockTouchEnd"
data-tag="lowerBlock"
></view>
<!-- 滑动块-右 -->
<view
class="slider-handle-block"
:class="{ decoration: decorationVisible }"
:style="{
backgroundColor: blockColor,
width: blockSize + 'px',
height: blockSize + 'px',
left: higherHandlePosition + '%',
}"
@touchstart="_onTouchStart"
@touchmove="_onBlockTouchMove"
@touchend="_onBlockTouchEnd"
data-tag="higherBlock"
></view>
<!-- 滑块值提示 -->
<view v-if="tipVisible" class="range-tip" :style="lowerTipStyle">{{ format(values[0]) }}</view>
<view v-if="tipVisible" class="range-tip" :style="higherTipStyle">{{ format(values[1]) }}</view>
</view>
</view>
</template>
<script>
export default {
components: {},
props: {
//滑块区间当前取值
value: {
type: Array,
default: function() {
return [0, 100]
},
},
//最小值
min: {
type: Number,
default: 0,
},
//最大值
max: {
type: Number,
default: 100,
},
step: {
type: Number,
default: 1,
},
format: {
type: Function,
default: function(val) {
return val
},
},
disabled: {
type: Boolean,
default: false,
},
//滑块容器高度
height: {
height: Number,
default: 50,
},
//区间进度条高度
barHeight: {
type: Number,
default: 5,
},
//背景条颜色
backgroundColor: {
type: String,
default: '#e9e9e9',
},
//已选择的颜色
activeColor: {
type: String,
default: '#1aad19',
},
//滑块大小
blockSize: {
type: Number,
default: 20,
},
blockColor: {
type: String,
default: '#fff',
},
tipVisible: {
type: Boolean,
default: true,
},
decorationVisible: {
type: Boolean,
default: false,
},
},
data() {
return {
values: [this.min, this.max],
startDragPos: 0, // 开始拖动时的坐标位置
startVal: 0, //开始拖动时较小点的值
}
},
computed: {
// 较小点滑块的坐标
lowerHandlePosition() {
return ((this.values[0] - this.min) / (this.max - this.min)) * 100
},
// 较大点滑块的坐标
higherHandlePosition() {
return ((this.values[1] - this.min) / (this.max - this.min)) * 100
},
lowerTipStyle() {
if (this.lowerHandlePosition < 90) {
return `left: ${this.lowerHandlePosition}%;`
}
return `right: ${100 - this.lowerHandlePosition}%;transform: translate(50%, -100%);`
},
higherTipStyle() {
if (this.higherHandlePosition < 90) {
return `left: ${this.higherHandlePosition}%;`
}
return `right: ${100 - this.higherHandlePosition}%;transform: translate(50%, -100%);`
},
},
created: function() {},
onLoad: function(option) {},
watch: {
//滑块当前值
value: {
immediate: true,
handler(newVal, oldVal) {
if (this._isValuesValid(newVal) && (newVal[0] !== this.values[0] || newVal[1] !== this.values[1])) {
this._updateValue(newVal)
}
},
},
},
methods: {
_updateValue(newVal) {
// 步长大于区间差,或者区间最大值和最小值相等情况
if (this.step >= this.max - this.min) {
throw new RangeError('Invalid slider step or slider range')
}
let newValues = []
if (Array.isArray(newVal)) {
newValues = [newVal[0], newVal[1]]
}
if (typeof newValues[0] !== 'number') {
newValues[0] = this.values[0]
} else {
newValues[0] = Math.round((newValues[0] - this.min) / this.step) * this.step + this.min
}
if (typeof newValues[1] !== 'number') {
newValues[1] = this.values[1]
} else {
newValues[1] = Math.round((newValues[1] - this.min) / this.step) * this.step + this.min
}
// 新值与原值相等,不做处理
if (this.values[0] === newValues[0] && this.values[1] === newValues[1]) {
return
}
// 左侧滑块值小于最小值时,设置为最小值
if (newValues[0] < this.min) {
newValues[0] = this.min
}
// 右侧滑块值大于最大值时,设置为最大值
if (newValues[1] > this.max) {
newValues[1] = this.max
}
// 两个滑块重叠或左右交错,使两个滑块保持最小步长的间距
if (newValues[0] >= newValues[1]) {
// 左侧未动,右侧滑块滑到左侧滑块之左
if (newValues[0] === this.values[0]) {
newValues[1] = newValues[0] + this.step
} else {
// 右侧未动, 左侧滑块滑到右侧之右
newValues[0] = newValues[1] - this.step
}
}
this.values = newValues
this.$emit('change', this.values)
},
_onTouchStart: function(event) {
if (this.disabled) {
return
}
this.isDragging = true
let tag = event.target.dataset.tag
//兼容h5平台及某版本微信
let e = event.changedTouches ? event.changedTouches[0] : event
this.startDragPos = e.pageX
this.startVal = tag === 'lowerBlock' ? this.values[0] : this.values[1]
},
_onBlockTouchMove: function(e) {
if (this.disabled) {
return
}
this._onDrag(e)
},
_onBlockTouchEnd: function(e) {
if (this.disabled) {
return
}
this.isDragging = false
this._onDrag(e)
},
_onDrag(event) {
if (!this.isDragging) {
return
}
let view = uni
.createSelectorQuery()
.in(this)
.select('.slider-range-inner')
view
.boundingClientRect(data => {
let sliderWidth = data.width
const tag = event.target.dataset.tag
let e = event.changedTouches ? event.changedTouches[0] : event
let diff = ((e.pageX - this.startDragPos) / sliderWidth) * (this.max - this.min)
let nextVal = this.startVal + diff
if (tag === 'lowerBlock') {
this._updateValue([nextVal, null])
} else {
this._updateValue([null, nextVal])
}
})
.exec()
},
_isValuesValid: function(values) {
return Array.isArray(values) && values.length == 2
},
},
}
</script>
<style scoped>
.slider-range {
position: relative;
padding-top: 40rpx;
}
.slider-range-inner {
position: relative;
width: 100%;
}
.slider-range.disabled .slider-bar-inner {
opacity: 0.35;
}
.slider-range.disabled .slider-handle-block {
cursor: not-allowed;
}
.slider-bar {
position: absolute;
top: 50%;
left: 0;
right: 0;
transform: translateY(-50%);
}
.slider-bar-bg {
position: absolute;
width: 100%;
height: 100%;
border-radius: 10000px;
z-index: 10;
}
.slider-bar-inner {
position: absolute;
width: 100%;
height: 100%;
border-radius: 10000px;
z-index: 11;
}
.slider-handle-block {
position: absolute;
top: 50%;
transform: translate(-50%, -50%);
border-radius: 50%;
box-shadow: 0 0 3px 2px rgba(227, 229, 241, 0.5);
z-index: 12;
}
.slider-handle-block.decoration::before {
position: absolute;
content: '';
width: 6upx;
height: 24upx;
top: 50%;
left: 29%;
transform: translateY(-50%);
background: #eeedf2;
border-radius: 3upx;
z-index: 13;
}
.slider-handle-block.decoration::after {
position: absolute;
content: '';
width: 6upx;
height: 24upx;
top: 50%;
right: 29%;
transform: translateY(-50%);
background: #eeedf2;
border-radius: 3upx;
z-index: 13;
}
.range-tip {
position: absolute;
top: 0;
font-size: 24upx;
color: #666;
transform: translate(-50%, -100%);
}
</style>
<template>
<view class="demo-slider-range">
<view class="section-title">普通用法</view>
<view class="slider-item">
<slider-range
:value="slider1.rangeValue"
:min="slider1.min"
:max="slider1.max"
:step="slider1.step"
:bar-height="barHeight"
:block-size="blockSize"
:background-color="backgroundColor"
:format="format1"
@change="handleRangeChange"
></slider-range>
</view>
<view class="section-title">自定义</view>
<view class="slider-item">
<slider-range
:value="slider2.rangeValue"
:min="slider2.min"
:max="slider2.max"
:step="slider2.step"
:bar-height="barHeight"
:block-size="blockSize"
:background-color="backgroundColor"
:active-color="slider2.activeColor"
:format="format2"
:decorationVisible="slider2.decorationVisible"
@change="handleRangeChange"
></slider-range>
</view>
</view>
</template>
<script>
import SliderRange from '../../components/slider-range/index.vue'
export default {
components: {
SliderRange,
},
data() {
return {
barHeight: 3,
blockSize: 26,
backgroundColor: '#EEEEF6',
slider1: {
min: 50,
max: 200,
step: 10,
rangeValue: [50, 150],
},
slider2: {
rangeMin: 0,
rangMax: 100,
rangeValue: [8, 80],
step: 1,
activeColor: '#FF6B00',
decorationVisible: true,
},
}
},
methods: {
format1(val) {
return val
},
format2(val) {
return `${val}%`
},
handleRangeChange(e) {
this.rangeValue = e
},
},
}
</script>
<style>
.demo-slider-range {
background-color: #fff;
padding: 100rpx 40rpx 0;
}
.section-title {
padding: 0 0 20rpx;
color: #666;
}
.slider-item:not(:last-child) {
margin-bottom: 100rpx;
}
</style>
<template>
<view class="box">
<view class="box1">
<view class="title">
<view class="title-left">{{ porps.title }}</view>
<view class="title-icon" @click="changFN">
<uni-icons type="top" color="#95a1a6" v-if="show"></uni-icons>
<uni-icons type="bottom" color="#95a1a6" v-else></uni-icons>
</view>
</view>
<view class="conter-liner-cost">
<view class="liner-left">{{ porps.text }}&nbsp;&nbsp; 合计:</view>
<view class="liner-right">{{ porps.cost }}</view>
</view>
</view>
<view class="box2" v-show="show"><slot></slot></view>
</view>
</template>
<script setup>
import { ref } from 'vue';
const porps = defineProps({
title: String,
text: String,
cost: String
});
const show = ref(false);
function changFN() {
show.value = !show.value;
}
</script>
<style lang="scss" scoped>
.box {
margin: 0;
padding: 0 25rpx;
.box1 {
margin-bottom: 23rpx;
margin-top: 35rpx;
.title {
display: flex;
justify-content: space-between;
margin-bottom: 10rpx;
.title-left {
font-size: 30rpx;
font-family: PingFang SC;
font-weight: 500;
color: #2b3133;
}
}
.conter-liner-cost {
display: flex;
.liner-left {
font-size: 28rpx;
font-family: PingFang SC;
font-weight: 400;
color: #7b7f83;
}
.liner-right {
font-size: 28rpx;
font-family: PingFang SC;
font-weight: 400;
color: #ff8124;
}
}
}
.box2 {
border-top: 1rpx solid #e6e6e6;
}
}
</style>
<template>
<view class="box">
<view class="box-title">
<view class="title-left">是否住宿</view>
<view class="title-right ">
<radio-group name="radio" @change="radio">
<label>
<radio value="1" :checked="flag" />
<text></text>
</label>
<label>
<radio value="0" :checked="!flag" />
<text></text>
</label>
</radio-group>
</view>
</view>
<!-- 酒店信息 -->
<view class="box-conter" v-if="flag">
<checkbox-group @change="change">
<view class="conter-conter" v-for="item in range" :key="item.id">
<view class="bgcColor">
<view class="conter-top">
<view class="text">{{ item.name }}</view>
<checkbox :value="item.hotelFlag" @click="checkedFN(item)" :disabled="disabled" />
</view>
<view class="box-dress">
<uni-icons custom-prefix="iconfont" type="icon-31dingwei" color="#95A1A6"></uni-icons>
{{ item.address }}
</view>
<view class="conter-text">
<view class="conter-liner">
<view class="liner-left">房型:</view>
<view class="liner-right">{{ item.houseType }}</view>
</view>
<view class="conter-liner">
<view class="liner-left">价格:</view>
<view class="liner-right">{{ item.spend }}</view>
</view>
<view class="conter-liner">
<view class="liner-left">餐食:</view>
<view class="liner-right">{{ item.haveDinner == 1 ? '含早' : '不含早参' }}</view>
</view>
<view class="conter-liner">
<view class="liner-left">入住时间:</view>
<view class="liner-right liner-move">
<view class="liner-right-hotl" v-for="val in item.move" :key="val.id">
<uni-datetime-picker
:start="val.moveIntoTime"
:end="val.leaveTime"
type="daterange"
v-model="val.move"
return-type="yyyy/MM/dd"
@change="maskClick(val)"
/>
<uni-icons
class="liner-del"
@click="delHot(item, val)"
v-if="item.move.length > 1"
custom-prefix="custom-icon"
type="trash"
size="20"
/>
</view>
<uni-icons
@click="addHot(item)"
custom-prefix="custom-icon"
type="plusempty"
size="20"
/>
</view>
</view>
</view>
</view>
</view>
</checkbox-group>
<view class="remark" v-if="hotelList">
<view class="liner-left">备注:</view>
<input class="uni-input" v-model="remark" placeholder="请输入你的内容" />
</view>
</view>
<view class="foot ">
<view class="button1" @click="upFN">上一步</view>
<view class="button" @click="nextFN">下一步</view>
</view>
</view>
</template>
<script setup>
import * as train from '@/common/train.js';
import {
onLoad,
onReady,
onShareAppMessage,
onShareTimeline,
onPullDownRefresh,
onReachBottom,
onShow
} from '@dcloudio/uni-app';
import { ref, getCurrentInstance, reactive, watch, toRefs } from 'vue';
const emit = defineEmits(['nextFN']);
const props = defineProps({
projectIdsArray: {},
id: {},
signId: {},
examIdsArry: {}
});
const moveList = ref([
{
id: 1,
move: null
}
]);
const hotShow = ref(true);
const popup = ref();
const hotlList = ref();
const omve = ref();
const arr = ref([]);
const range = ref();
const id = ref(props.id);
const hotelIdsArray = ref();
const state = ref(); //是否住宿
const remark = ref();
const flag = ref(true);
const disabled = ref(false);
const costID = ref();
const code = ref();
const status = ref();
const signId = ref();
const data = reactive({
addForm: {}
});
const { addForm } = toRefs(data);
onShow(() => {
status.value = 3;
});
getList();
async function getList() {
addForm.value.id = id.value;
let res = await train.trainParticulars(addForm.value);
status.value = res.data.signStatus;
range.value = res.data.hotelList;
range.value.forEach(item => {
let tId = uuid();
item.move = [
{
moveIntoTime: item.moveIntoTime.replace(/-/g, '/'),
leaveTime: item.leaveTime.replace(/-/g, '/'),
id: tId,
hotlId: item.id,
move: [item.moveIntoTime.replace(/-/g, '/'), item.leaveTime.replace(/-/g, '/')]
}
];
});
// 数据加工
if (res.data.signId) signId.value = res.data.signId;
console.log(range.value);
}
function uuid() {
var s = [];
var hexDigits = '0123456789abcdef';
for (var i = 0; i < 36; i++) {
s[i] = hexDigits.substr(Math.floor(Math.random() * 0x10), 1);
}
s[14] = '4'; // bits 12-15 of the time_hi_and_version field to 0010
s[19] = hexDigits.substr((s[19] & 0x3) | 0x8, 1); // bits 6-7 of the clock_seq_hi_and_reserved to 01
s[8] = s[13] = s[18] = s[23] = '-';
var uuid = s.join('');
return uuid;
}
// 是否住宿
function changeRadio(e) {
console.log(e);
if (e.target.value == 0) {
hotShow.value = false;
} else {
hotShow.value = true;
}
}
// 获取用酒店信息
function change(e) {
hotelIdsArray.value = e.target;
}
// 封装数据处理
function changeKey(arr) {
let newArr = [];
arr.forEach(item => {
newArr.push({
text: item.moveIntoTimeStr,
value: item.id
});
});
return newArr;
}
// 下一步
async function nextFN() {
await initData();
}
// 上一步
function upFN() {
console.log(111);
emit('nextFN', 1);
}
// 是否住宿
function radio(e) {
console.log(e);
e.target.value == 1 ? (flag.value = true) : (flag.value = false);
console.log(flag.value);
}
// 页面跳转
async function goRenew() {
let path = `/pages/train/costBreakdown/costBreakdown?id=` + id.value;
await wx.navigateTo({
url: path
});
}
function checkedFN(item) {
item.hotelFlag = !item.hotelFlag;
}
// 日期确定时处发
// function maskClick(item) {
// item.move.forEach(val => {
// val = val.replace(/-/g, '/');
// });
// console.log(item.move);
// console.log(item);
// }
// 添加住宿
function addHot(item) {
let tId = uuid;
item.move.push({
moveIntoTime: item.moveIntoTime.replace(/-/g, '/'),
leaveTime: item.leaveTime.replace(/-/g, '/'),
id: tId,
move: [item.moveIntoTime.replace(/-/g, '/'), item.leaveTime.replace(/-/g, '/')],
hotlId: item.id
});
}
function delHot(item, val) {
item.move = item.move.filter(obj => {
return obj.id != val.id;
});
}
// 提交
async function initData() {
let list = null;
list = JSON.parse(JSON.stringify(range.value));
// 1.过滤没有选中的酒店
list = list.filter(item => {
return item.hotelFlag == true;
});
// 2.过滤没有选择日期的
let arr = [];
list.forEach((item, index) => {
arr[index] = item;
arr[index].move = item.move.filter(val => {
return val.move.length != 0;
});
});
// 3.过滤酒店日期相同
let arr1 = [];
arr.forEach((item, index) => {
item.move.forEach(val => {
arr1.push(val);
});
});
let arr2 = [];
arr1.forEach(item => {
item.move = item.move.join();
arr2.push({
hotlId: item.hotlId,
move: item.move
});
});
// // 去重
// for (var i = 0; i < arr2.length - 1; i++) {
// for (var j = i + 1; j < arr2.length; j++) {
// if (arr2[i].move == arr2[j].move) {
// arr2.splice(j, 1);
// j--;
// }
// }
// }
if (flag.value) {
if (arr2.length == 0) {
uni.showToast({
title: '请选择入住酒店!',
duration: 2000,
icon: 'error'
});
return false;
}
addForm.value.hotelIdsArray = arr2;
} else {
addForm.value.hotelIdsArray = [];
}
addForm.value.projectIdsArray = props.projectIdsArray;
addForm.value.examIdsArray = props.examIdsArry;
addForm.value.trainId = id.value;
addForm.value.remark = remark.value;
let res = null;
// if (status.value == null || status.value == 4) {
// 添加
// addForm.value.id = null
addForm.value.id = signId.value;
res = await train.trainNext(addForm.value);
signId.value = res.data;
// } else {
// // 修改
// addForm.value.id = signId.value
// res = await train.trainUpdata(addForm.value);
// }
costID.value = res.data;
// 报名成功才跳转
if (res.code == 200) {
// 酒店是否已住满
goRenew();
}
}
</script>
<style scoped lang="scss">
.box {
margin-top: 5rpx;
padding: 25rpx;
.bgcColor {
background-color: #fff;
border-radius: 15rpx;
padding: 25rpx;
}
.box-title {
padding: 25rpx;
display: flex;
justify-content: space-between;
margin-bottom: 30rpx;
background-color: #fff;
border-radius: 15rpx;
}
.title-left {
text {
font-size: 30rpx;
font-family: PingFang SC;
font-weight: 400;
color: #000000;
}
}
.box-conter {
padding: 25rpx 0;
display: block;
.conter-conter {
margin-bottom: 20rpx;
.conter-top {
display: flex;
justify-content: space-between;
margin-bottom: 10rpx;
.text {
font-size: 33rpx;
font-family: PingFang SC;
font-weight: 500;
color: #2b3133;
}
.checkbox {
}
}
.box-dress {
font-family: PingFang SC;
font-weight: 400;
color: #2b3133;
font-size: 24rpx;
border-bottom: 1px solid #e6e6e6;
padding-bottom: 32rpx;
}
.conter-text {
.conter-liner {
display: flex;
justify-content: space-between;
margin-top: 20rpx;
padding: 0 10rpx;
.liner-left {
font-size: 28rpx;
font-family: PingFang SC;
font-weight: 400;
color: #7b7f83;
padding-top: 10rpx;
}
.liner-right {
font-size: 28rpx;
font-family: PingFang SC;
font-weight: 400;
color: #2b3133;
width: 80%;
text-align: right;
}
}
}
}
}
.remark {
margin-top: 35rpx;
display: flex;
justify-content: space-between;
margin-bottom: 120rpx;
background-color: #fff;
border-radius: 15rpx;
padding: 10rpx 25rpx;
.liner-left {
font-size: 28rpx;
font-family: PingFang SC;
font-weight: 400;
color: #7b7f83;
padding-top: 18rpx;
}
}
.foot {
background-color: #ffffff;
padding: 20rpx 0;
position: absolute;
left: 0;
bottom: 0;
width: 100%;
display: flex;
.button {
margin: 0 auto;
height: 80rpx;
width: 300rpx;
text-align: center;
font-size: 32rpx;
font-family: PingFang SC;
font-weight: 500;
color: #ffffff;
line-height: 80rpx;
background: linear-gradient(270deg, #54e1b9, #00caa6);
border-radius: 40rpx;
}
.button1 {
margin: 0 auto;
height: 80rpx;
width: 300rpx;
text-align: center;
font-size: 32rpx;
font-family: PingFang SC;
font-weight: 500;
line-height: 80rpx;
background: #fff;
border-radius: 40rpx;
border: 1px solid #2ed981;
color: #2ed981;
}
}
.select {
width: 300rpx;
}
}
.uni-date {
flex: 0;
width: 65%;
}
.popup-center {
display: flex;
justify-content: space-between;
}
.popup-title {
display: flex;
justify-content: space-between;
border-bottom: 1px solid #e6e6e6;
padding: 30rpx 50rpx;
}
.popup-title-left {
font-size: 30rpx;
font-weight: 400;
color: 000;
font-family: PingFangSC-Medium;
}
.popup-body {
border-bottom: 1px solid #e6e6e6;
padding: 15rpx 50rpx;
color: #4c5359;
font-size: 30rpx;
}
.popup-box {
height: 500rpx;
overflow-y: scroll;
}
.liner-right-hotl {
display: flex;
}
.liner-del {
margin-top: 19rpx;
}
</style>
<template>
<view class=" conter-box">
<view class="box" v-if="props.trainProjectsList.length != 0">
<view class="text">培训科目</view>
<view class="box2">
<checkbox-group>
<view class="box-check" v-for="item in props.trainProjectsList" :key="item.id">
<view class="">
<view class="title">{{ item.projectName }}</view>
<view class="content">
{{ item.isNecessary == 1 ? '必选' : '非必选' }}&nbsp;&nbsp;合计:
<view class="span">{{ item.cost }}</view>
</view>
</view>
<view class="checkbox">
<checkbox
:disabled="item.isNecessary == 1"
:value="item.id"
@click="checkTrain(item)"
:checked="item.check"
/>
</view>
</view>
</checkbox-group>
</view>
</view>
<view class="box" v-if="props.examProjectsList.length != 0">
<view class="text">考试科目</view>
<view class="box2">
<checkbox-group>
<view class="box-check" v-for="item in props.examProjectsList" :key="item.id">
<view class="">
<view class="title">{{ item.projectName }}</view>
<view class="content">
{{ item.isNecessary == 1 ? '必选' : '非必选' }}&nbsp;&nbsp;合计:
<view class="span">{{ item.cost }}</view>
</view>
</view>
<view class="checkbox">
<checkbox
:disabled="item.isNecessary == 1"
:value="item.id"
@click="checkTrain(item)"
:checked="item.check"
/>
</view>
</view>
</checkbox-group>
</view>
</view>
</view>
<view class="foot">
<view class="button1" @click="upFN">上一步</view>
<view class="button" @click="nextFN">下一步</view>
</view>
<view class="nodata " v-if="props.examProjectsList.length == 0 && props.trainProjectsList.length == 0">
没有培训科目
</view>
</template>
<script setup>
import { forEach } from 'lodash';
import { ref, getCurrentInstance, reactive, toRefs } from 'vue';
const props = defineProps({
trainProjectsList: {},
examProjectsList: {},
hotelList: {},
id: {}
});
const data = reactive({
projectIdsArray: []
});
const examIdsArry = ref([]);
const { projectIdsArray } = toRefs(data);
const emit = defineEmits(['nextFN']);
const checkbox1 = ref([0]);
function checkTrain(item) {
if (item.isNecessary == 1) {
item.check = true;
} else {
item.check = !item.check;
}
}
// 上一步
function upFN() {
emit('nextFN', 0);
}
// 下一步
function nextFN() {
let falg = true;
let arr1 = [];
let arr2 = [];
props.examProjectsList.forEach(item => {
if (item.check) {
arr1.push(item.id);
}
});
props.trainProjectsList.forEach(item => {
if (item.check) {
arr2.push(item.id);
}
});
let examList = JSON.parse(JSON.stringify(props.examProjectsList));
let trainList = JSON.parse(JSON.stringify(props.trainProjectsList));
examList.concat(trainList).forEach(item => {
if (item.isNecessary == 1 && item.check == false) {
falg = false;
}
});
if (falg) {
examIdsArry.value = arr1;
projectIdsArray.value = arr2;
if (props.hotelList.length == 0) {
// 没有酒店直接报名
// 页面跳转
let path = `/pages/train/costBreakdown/costBreakdown?id=` + props.id;
wx.navigateTo({
url: path
});
} else {
emit('nextFN', 2, projectIdsArray.value, examIdsArry.value);
}
} else {
uni.showToast({
title: '请选择必选科目!',
duration: 2000,
icon: 'error'
});
return false;
}
}
</script>
<style scoped lang="scss">
.nodata {
background: url(/static/nodata.png) no-repeat;
background-size: 100%;
width: 100%;
height: 835rpx;
color: #aaa59f;
font-size: 50rpx;
}
.conter-box {
padding-bottom: 100rpx;
}
.box {
padding: 34rpx 25rpx;
background-color: #f4f6fa;
padding-bottom: 0;
.box2 {
background-color: #fff;
border-radius: 15rpx;
margin-top: 20rpx;
}
.text {
height: 29px;
font-size: 30rpx;
font-family: PingFang SC;
font-weight: 500;
color: #000000;
line-height: 62rpx;
}
.box-check {
padding: 40rpx;
display: flex;
justify-content: space-between;
border-bottom: 1rpx solid #e6e6e6;
padding-bottom: 20rpx;
:deep(.checkbox__inner) {
background-color: #d9d9d9 !important;
border-color: #d9d9d9 !important;
border-radius: 50% !important;
width: 45rpx !important;
height: 45rpx !important;
line-height: 40rpx;
}
.text {
font-size: 12px;
color: #666;
margin-top: 5px;
}
.title {
font-size: 30rpx;
font-family: PingFang SC;
font-weight: 400;
color: #2b3133;
margin-bottom: 10rpx;
}
.content {
display: flex;
font-size: 30rpx;
font-family: PingFang SC;
font-weight: 400;
color: #2b3133;
.span {
color: #ff8124;
font-size: 28rpx;
font-family: PingFang SC;
font-weight: 400;
}
}
}
:deep(.checkbox__inner-icon) {
position: absolute !important;
top: 4px !important;
left: 7px !important;
color: #000 !important;
}
:deep(.uni-data-checklist .checklist-group .checklist-box) {
margin-right: 0;
}
}
.conter-button {
position: absolute;
left: 0;
bottom: 10rpx;
width: 100%;
display: flex;
justify-content: center;
.button {
height: 80rpx;
width: 500rpx;
text-align: center;
font-size: 32rpx;
font-family: PingFang SC;
font-weight: 500;
color: #ffffff;
line-height: 80rpx;
background: linear-gradient(270deg, #54e1b9, #00caa6);
border-radius: 40rpx;
}
}
.foot {
display: flex;
background-color: #ffffff;
padding: 20rpx 0;
position: absolute;
left: 0;
bottom: 0;
width: 100%;
.button {
margin: 0 auto;
height: 80rpx;
width: 300rpx;
text-align: center;
font-size: 32rpx;
font-family: PingFang SC;
font-weight: 500;
color: #ffffff;
line-height: 80rpx;
background: linear-gradient(270deg, #54e1b9, #00caa6);
border-radius: 40rpx;
}
.button1 {
margin: 0 auto;
height: 80rpx;
width: 300rpx;
text-align: center;
font-size: 32rpx;
font-family: PingFang SC;
font-weight: 500;
line-height: 80rpx;
background: #fff;
border-radius: 40rpx;
border: 1px solid #2ed981;
color: #2ed981;
}
}
</style>
<template>
<view class="box">
<view class="liner" v-for="item in props.scheduleList" :key="item.id">
<view class="timer">
<uni-icons custom-prefix="iconfont" type="icon-ai253" color="#1ec886" size="20"></uni-icons>
&nbsp; {{ item.dayStr }} 10:00-12:00
</view>
<view class="conetr">{{ item.event }}</view>
<view class="data">
<uni-icons custom-prefix="iconfont" type="icon-loufangfangzi"></uni-icons>
{{ item.place }}
</view>
</view>
<view class="nodata" v-if="props?.scheduleList?.length == 0">你还没有日程安排</view>
</view>
</template>
<script setup>
import { ref, getCurrentInstance, reactive, toRefs } from 'vue';
const props = defineProps({
scheduleList: {}
});
</script>
<style scoped lang="scss">
.nodata {
background: url(/static/nodata.png) no-repeat;
background-size: 100%;
width: 100%;
height: 835rpx;
color: #aaa59f;
font-size: 50rpx;
}
.box {
padding-top: 25rpx;
.liner {
margin-bottom: 20rpx;
background-color: #fff;
border-radius: 15rpx;
padding: 20rpx;
}
.timer {
display: flex;
font-size: 28rpx;
font-family: PingFang SC;
font-weight: 400;
color: #1ec886;
}
.conetr {
font-size: 30rpx;
font-family: PingFang SC;
font-weight: 400;
color: #2b3133;
margin: 25rpx 0;
}
.data {
font-size: 28rpx;
font-family: PingFang SC;
font-weight: 400;
color: #7b7f83;
}
}
</style>
<template>
<view class="big-box">
<view class="list-box">
<view class="image">
<image class="img" referrer="no-referrer|origin|unsafe-url" :src="porps.pic" mode="aspectFill"></image>
</view>
<view class="text">
<view class="text-title">{{ porps.title }}</view>
<view class="text-card color" v-if="porps.card == '报名中'">{{ porps.card }}</view>
<view class="text-card color1" v-if="porps.card == '进行中'">{{ porps.card }}</view>
<view class="text-card color2" v-if="porps.card == '即将开始'">{{ porps.card }}</view>
<view class="text-card color3" v-if="porps.card == '已结束'">{{ porps.card }}</view>
<view class="text-card color4" v-if="porps.card == '培训未开始'">{{ porps.card }}</view>
<view class="text-card color4" v-if="porps.card == '报名未开始'">{{ porps.card }}</view>
<view class="text-timer ">报名截止:{{ porps.timer }}</view>
</view>
</view>
<view class="hr"></view>
</view>
</template>
<script setup>
const porps = defineProps({
pic: {
type: String
},
title: {
type: String
},
card: {
type: String
},
timer: {
type: String
}
});
</script>
<style lang="scss">
.big-box {
width: 100%;
padding: 25rpx 0;
.hr {
width: 100%;
border-bottom: 1rpx solid #e5e5e5;
padding-top: 25rpx;
}
.list-box {
width: 100%;
height: 180rpx;
display: flex;
.image {
width: 270rpx;
height: 180rpx;
padding-right: 25rpx;
.img {
width: 270rpx;
height: 180rpx;
border-radius: 15rpx;
}
}
.text {
margin-left: 20rpx;
.text-title {
text-align: left;
font-size: 30rpx;
font-family: PingFang SC;
font-weight: 400;
color: #000000;
}
.text-card {
font-size: 20rpx;
width: 110rpx;
height: 32rpx;
margin-top: 57rpx;
text-align: center;
font-family: PingFang SC;
font-weight: 400;
color: #ffffff;
border-radius: 16px 16px 16px 0px;
}
.color {
background: linear-gradient(270deg, #54e1b9, #00caa6);
}
.color1 {
background: linear-gradient(270deg, #be8efb, #a76df4);
}
.color2 {
background: linear-gradient(270deg, #fea449, #ffb95f);
}
.color3 {
background: linear-gradient(270deg, #d9d9d9, #bcbcbc);
}
.color4 {
background: linear-gradient(270deg, #40d8ee, #53a7f6);
}
.text-timer {
margin-top: 20rpx;
height: 23rpx;
font-size: 24rpx;
font-family: PingFang SC;
font-weight: 400;
color: #7b7f83;
}
}
}
}
</style>
\ No newline at end of file
<template>
<view class="big-box">
<view class="list-box">
<view class="image">
<image
class="img"
referrer="no-referrer|origin|unsafe-url"
:src="porps.item.cover"
mode="aspectFill"
></image>
</view>
<view class="text">
<view class="text-title">{{ porps.item.trainName }}</view>
<view class="text-card color1" v-if="porps.item.statusStr == '审核通过'">
{{ porps.item.statusStr }}
</view>
<view class="text-card color2" v-if="porps.item.statusStr == '待审核'">
{{
porps.item.status == '0' && porps.item.payStatus == '0'
? porps.item.payStatusStr
: porps.item.statusStr
}}
</view>
<view class="text-card color3" v-if="porps.item.statusStr == '报名失败'">
{{ porps.item.statusStr }}
</view>
<view class="text-card color3" v-if="porps.item.statusStr == '审核拒绝'">
{{ porps.item.statusStr }}
</view>
<view class="text-card color4" v-if="porps.item.statusStr == '待支付'">{{ porps.item.statusStr }}</view>
<view class="text-card color4" v-if="porps.item.statusStr == '待提交'">{{ porps.item.statusStr }}</view>
<view class="text-card color5" v-if="porps.item.statusStr == '已取消'">{{ porps.item.statusStr }}</view>
</view>
</view>
<view class="hr"></view>
</view>
</template>
<script setup>
const porps = defineProps({
pic: {
type: String
},
title: {
type: String
},
card: {
type: String
},
timer: {
type: String
},
item: {}
});
</script>
<style lang="scss">
.big-box {
width: 100%;
padding: 25rpx 0;
.hr {
width: 100%;
border-bottom: 1rpx solid #e5e5e5;
padding-top: 25rpx;
}
.list-box {
width: 100%;
height: 180rpx;
display: flex;
.image {
width: 270rpx;
height: 180rpx;
padding-right: 25rpx;
.img {
width: 270rpx;
height: 180rpx;
border-radius: 15rpx;
}
}
.text {
margin-left: 20rpx;
.text-title {
text-align: left;
font-size: 30rpx;
font-family: PingFang SC;
font-weight: 400;
color: #000000;
}
.text-card {
font-size: 20rpx;
width: 94rpx;
height: 32rpx;
margin-top: 57rpx;
text-align: center;
font-family: PingFang SC;
font-weight: 400;
color: #ffffff;
border-radius: 16px 16px 16px 0px;
}
.color1 {
background: linear-gradient(270deg, #54e1b9, #00caa6);
}
.color2 {
background: linear-gradient(270deg, #be8efb, #a76df4);
}
.color3 {
background: linear-gradient(90deg, #f83841, #f76d74);
}
.color4 {
background: linear-gradient(90deg, #fea449, #ffb95f);
}
.color5 {
background: linear-gradient(270deg, #d9d9d9, #bcbcbc);
}
}
}
}
</style>
......@@ -181,6 +181,20 @@
}
}, {
"path": "pages/level/ztx/approval",
"style": {
"navigationBarTitleText": "级位考试审批",
"enablePullDownRefresh": false
}
}, {
"path": "pages/level/ztx/cert",
"style": {
"navigationBarTitleText": "级位证书发布",
"enablePullDownRefresh": false
}
}, {
"path": "pages/rank/approval",
"style": {
"navigationBarTitleText": "段位考试审批",
......@@ -422,7 +436,25 @@
"enablePullDownRefresh": false
}
}
],
,{
"path" : "pages/level/ztx/examList",
"style" :
{
"navigationBarTitleText": "级位考试详情",
"enablePullDownRefresh": false
}
}
,{
"path" : "pages/level/ztx/studentList",
"style" :
{
"navigationBarTitleText": "考生列表",
"enablePullDownRefresh": false
}
}
],
"globalStyle": {
"navigationStyle": "custom",
"navigationBarTextStyle": "white",
......
......@@ -3,7 +3,13 @@
<!-- 团队会员审核 -->
<uni-segmented-control class="whitebg" :current="current" :values="navs" @clickItem="onClickItem"
styleType="text" activeColor="#AD181F"></uni-segmented-control>
<view class="appList">
<view class="appList">
<view class="vipData" v-if="userType == '1'" v-show="totalCost>0">
<view>费用合计:
<text>¥{{ totalCost.toFixed(2) }}</text>
</view>
</view>
<view class="appItem" v-for="item in list">
<view class="status" @click="goDetail(item)">
<text v-if="item.auditStatus == 0" class="text-primary">审核中</text>
......@@ -36,24 +42,21 @@
<view>{{item.content.renewYear}}</view>
</view>
<view v-if="deptType == 1">
团体会员/新会员
<view>{{item.content.allCount}}/{{item.content.newCount}}</view>
会员合计/新会员
<view>{{item.content.allCount}}/<text class="text-danger">{{item.content.newCount}}</text></view>
</view>
<view v-if="deptType == 1">
费用合计
<view> {{ (item?.content?.allFee*1).toFixed(2) }}</view>
<view> ¥{{ (item?.content?.allFee*1).toFixed(2) }}</view>
</view>
</view>
<view class="func" v-if="(userType == '3'||userType == '2') && item.auditStatus == 0">
<button @click="audit(item.recordId,'0')">拒绝</button>
<button @click="audit(item.recordId,'1')">同意</button>
</view>
<view class="func" v-if="(deptType == 1&&item.ztxRes == 0)||((deptType == 2 || deptType == 3)&&item.shenRes == 0)">
<view class="func" v-if="(userType == '1'&&item.auditStatus == 0)">
<button @click="audit(item.recordId,'0')">拒绝</button>
<button @click="audit(item.recordId,'1')">同意</button>
</view>
<view class="func" v-if="(deptType == 6&&(item.status == 0 || item.status == 2))">
<button>提交审核</button>
</view>
</view>
</view>
......@@ -89,7 +92,8 @@
const list = ref([])
const total = ref(0)
const deptType = ref('')
const userType = ref('')
const userType = ref('')
const totalCost = ref(0)
onLoad(() => {
if (app.globalData.isLogin) {
init()
......@@ -125,13 +129,15 @@
queryParams.value.noEmpty = 1
}else if( deptType.value==4||deptType.value==5){
queryParams.value.noEmpty=1
}
}
totalCost.value = 0
api.getGroupList(queryParams.value).then(res => {
uni.hideLoading()
list.value = res.rows
list.value.forEach(item => {
item.content = JSON.parse(item.content)
// item.doc = JSON.parse(item.doc)
// item.doc = JSON.parse(item.doc)
totalCost.value = totalCost.value + (item.content.allFee * 1)
})
total.value = res.total
})
......@@ -194,7 +200,7 @@
if(userType.value=='1'){
// 查看
let path = `/pages/group/apply/applyDetail?rangeId=${item.id}&auditLog=${auditLog}&form=${form}`
let path = `/pages/group/apply/mergeUpDetail?form=${form}`
uni.navigateTo({
url: path
});
......
......@@ -40,16 +40,30 @@
</view>
<view class="flexbox">
<view>
单价
<text>¥{{n.unitPrice}}</text>
<view>
原有效期
<text>{{n.validityTime?.slice(0,10)}}</text>
</view>
<view>
提交日期
<text>{{n.commitTime?.slice(0,10)}}</text>
</view>
</view>
<view>
年限
<text>{{n.renewYear}}</text>
<view v-if="deptType==1">
会员证
<text v-if="form.content.sendJiaoFeiFlag==1" class="text-success">已下发</text>
<text v-else class="text-warning">未下发</text>
</view>
</view>
<view>
总价
<text>¥{{n.allFee}}</text>
单价
<text>¥{{n.unitPrice}}</text>
<view>总价
<text>¥{{n.allFee}}</text>
</view>
</view>
</view>
</view>
......@@ -80,15 +94,15 @@
</view>
</view>
<view class="fixedBottom" v-if="(deptType == 1)&&form.ztxRes == 0">
<!-- <view class="fixedBottom" v-if="(deptType == 1)&&form.auditStatus == 0">
<button class="btn-red-kx" @click="audit(form.id,'2')">拒绝</button>
<button class="btn-red" @click="audit(form.id,'1')">同意</button>
</view>
<view class="fixedBottom" v-if="(deptType == 2 || deptType == 3)&&form.shenRes == 0">
<view class="fixedBottom" v-if="(deptType == 2 || deptType == 3)&&form.auditStatus == 0">
<button class="btn-red-kx" @click="audit(form.id,'2')">拒绝</button>
<button class="btn-red" @click="audit(form.id,'1')">同意</button>
</view>
</view> -->
</view>
</template>
......
......@@ -15,7 +15,7 @@
<view class="item" v-for="n in list">
<view class="w100">
<view class="name">{{n.certName}}</view>
<view class="date" v-if="n.validityTime">{{n.validityTime?.silce(0,10)}}</view>
<view class="date" v-if="n.validityTime">{{n.validityTime?.slice(0,10)}}</view>
<view class="flexbox">
<view>单价
<text>¥{{ (n.unitPrice*1).toFixed(2) }}</text>
......
<template>
<view class="page">
<view class="bgbg">
<view class="bgbg">
<view class="loginOutIcon" @click="loginOut">
<image src="@/static/switch.png"></image>
</view>
<view class="welcome">您好!
{{memberInfo.name}}
<br />欢迎使用中跆协会员管理系统
......@@ -42,7 +45,7 @@
<view v-if="userType=='4'" @click="goPath('/pages/level/apply')">
<image />级位考试申请
</view>
<view v-if="userType!='4'" @click="goPath('/pages/level/approval')">
<view v-if="userType!='4'&&userType!='1'" @click="goPath('/pages/level/approval')">
<image />级位考试审核
</view>
<view v-if="userType=='2'" @click="goPath('/pages/level/apply')">
......@@ -51,7 +54,13 @@
</view>
<view v-if="userType=='1'" class="girdBox">
<view v-if="userType=='1'" class="girdBox">
<view @click="goPath('/pages/level/ztx/approval')">
<image />级位考试审核
</view>
<view @click="goPath('/pages/level/ztx/cert')">
<image />级位证书发布
</view>
<view @click="goPath('/pages/rank/approval')">
<image />段位考试审核
</view>
......@@ -132,7 +141,9 @@
proId = option.proId;
}
});
function loginOut(){
}
function goPath(path) {
uni.navigateTo({
url: path
......@@ -281,7 +292,10 @@
}
</script>
<style scope lang="scss">
<style scope lang="scss">
.loginOutIcon{
image{}
}
.welcome {
padding: 55rpx;
line-height: 55rpx;
......
......@@ -11,7 +11,7 @@
'text-success':item.auditStatus=='1',
'text-danger':item.auditStatus=='2',
'text-warning':item.auditStatus=='3'
}">{{ item.statusStr }}</text>
}">{{ item.statusStr }}</text>
</view>
<view class="date" v-if="item.status!='0'&&item.submitTime">提交时间:{{item.submitTime}}</view>
......@@ -42,6 +42,9 @@
<image mode="aspectFit" src="/static/nodata.png"></image>
<text>暂无数据</text>
</view>
<view v-if="userType=='2'" class="block-btn-box">
<button @click="goMerge" class="btn-red-kx">前往合并 > </button>
</view>
</view>
</template>
......
......@@ -39,8 +39,8 @@
</view>
<view class="nodata" v-if="infoList.length==0">
<image mode="aspectFit" src="/static/nodata.png"></image>
<text>暂无数据</text>
<image mode="aspectFit" src="/static/nodata.png"></image>
<button class="btn-red" @click="gohome">回到首页</button>
</view>
</view>
</template>
......@@ -160,6 +160,12 @@
url: path
});
}
function gohome(){
let path = `/pages/index/index`
uni.reLaunch({
url: path
});
}
</script>
......
<template>
<view>
<uni-segmented-control class="whitebg" :current="current" :values="navs" @clickItem="onClickItem"
styleType="text" activeColor="#AD181F"></uni-segmented-control>
<view v-show="totalCost>0" class="vipData">
<view>费用合计:
<text>{{ totalCost.toFixed(2) }}</text>
</view>
</view>
<view class="appList">
<view class="appItem" v-for="item in infoList">
<view class="status" :class="{
'text-primary':item.status=='0',
'text-success':item.status=='1',
'text-danger':item.status=='2',
'text-warning':item.status=='3'
}" @click="goDetail(item)">
{{ item.statusStr }}
</view>
<view class="date" v-if="item.status!='0'&&item.submitTime">提交时间:{{item.submitTime}}</view>
<view class="name mt0" @click="goDetail(item)">{{item.mergeName}}</view>
<view class="pp esp">上报单位:{{item.memName}}</view>
<view class="flexbox" @click="goDetail(item)">
<view>
考试人数
<view>{{item.totalNum}}</view>
</view>
<view>
缴费状态
<view>
<text :class="{
'text-success':item.examPayStatusStr=='已上传凭证',
'text-danger':item.examPayStatusStr=='未上传凭证',
'text-warning':item.examPayStatusStr=='已结算'
}">{{ item.examPayStatusStr||'--' }}</text>
</view>
</view>
<view>
总金额
<view>¥{{item.totalAmount}}</view>
</view>
</view>
<view class="func" v-if="item.status=='0'">
<button @click="audit(item,'2')">拒绝</button>
<button @click="audit(item,'1')">同意</button>
</view>
</view>
</view>
<view class="nodata" v-if="infoList.length==0">
<image mode="aspectFit" src="/static/nodata.png"></image>
<text>暂无数据</text>
</view>
</view>
</template>
<script setup>
import * as api from '@/common/api.js'
import config from '@/config.js'
import _ from 'lodash'
import {
onMounted,
ref
} from 'vue'
import {
onLoad,
onShow
} from '@dcloudio/uni-app'
const app = getApp();
const queryParams = ref({
// pageNum: 1,
// pageSize: 10
status: '0',
type: '1'
})
const navs = ref(['审核中', '审核通过', '审核拒绝', '审批撤回'])
const statusArr = ['审批中', '审批通过', '审批拒绝', '审批撤回']
const current = ref()
const infoList = ref([])
const total = ref(0)
const totalCost = ref(0)
const deptType = ref('')
const userType = ref('')
onLoad(() => {
})
onShow(() => {
if (app.globalData.isLogin) {
init()
} else {
app.firstLoadCallback = () => {
init()
};
}
})
function init() {
deptType.value = app.globalData.deptType
userType.value = app.globalData.userType
getList()
}
function getList() {
uni.showLoading({
title: '加载中'
})
totalCost.value = 0
api.getVerityMergeList(queryParams.value).then(response => {
uni.hideLoading()
const list = []
_.each(response.rows, r => {
const item = JSON.parse(r.remark)
item.recordId = r.recordId
item.status = r.auditStatus
item.statusStr = statusArr[r.auditStatus]
item.isView = r.isView
item.payStatus = r.payStatus
item.examPayStatusStr = r.examPayStatusStr
item.sourceData = r
item.auditProcess = r.auditProcess
list.push(item)
totalCost.value += (item.totalAmount * 1)
})
infoList.value = list
total.value = response.total
})
}
function onClickItem(e) {
console.log(e)
uni.showLoading({
title: '加载中'
})
queryParams.value.status = e.currentIndex
getList()
}
function goDetail(item) {
const form = encodeURIComponent(JSON.stringify(item))
// 查看
let path = `/pages/level/mergeUpDetail?form=${form}&type=1`
uni.navigateTo({
url: path
});
}
function audit(item, flag) {
var obj = {
flag: flag,
reason: null,
id: item.recordId
}
if (flag == '2') {
// 拒绝
// 弹出框填写理由
uni.showModal({
title: '请输入拒绝理由',
editable: true,
success: function(res) {
if (res.confirm) {
if (!res.content) {
uni.showToast({
title: '请输入拒绝理由',
icon: 'none'
})
} else {
obj.reason = res.content
doApproval(obj)
}
}
}
})
} else if (flag == '1') {
// 二次确认
uni.showModal({
title: '提示',
content: `确定审批通过吗`,
success: function(res) {
if (res.confirm) {
doApproval(obj)
}
}
})
}
}
function doApproval(obj) {
console.log(obj)
api.doMergeFlows(obj).then((res) => {
uni.showToast({
title: '操作成功',
icon: 'none'
})
getList()
})
}
</script>
<style scoped lang="scss">
.mt0 {
margin-top: 0 !important;
}
.appList .appItem .name {
width: 80%;
word-break: break-all;
}
</style>
\ No newline at end of file
<template>
<view>
<!-- 级位证书发布 -->
<view class="appList">
<view class="appItem" v-for="item in infoList">
<view class="status" @click="goDetail(item)">
<text :class="{
'text-warning':item.certStatus=='0',
'text-success':item.certStatus=='1'
}">{{ item.certStatusStr }}</text>
</view>
<view class="date">提交日期:{{item.submitTimeStr}}</view>
<view class="name mt0" @click="goDetail(item)">{{item.name}}</view>
<view class="pp esp" v-if="item.certTime">证书发送时间:{{item.certTimeStr}}</view>
<view class="flexbox" @click="goDetail(item)">
<view>
申请单位
<view>{{item.memberName}}</view>
</view>
<view>
已发证书
<view>{{item.hasCerts}}</view>
</view>
<view>
待发证书
<view>{{item.noCerts}}</view>
</view>
</view>
<view class="func" v-if="item.certStatus != '2'">
<button @click="send(item)">一键生成</button>
</view>
</view>
</view>
<view class="nodata" v-if="infoList.length==0">
<image mode="aspectFit" src="/static/nodata.png"></image>
<text>暂无数据</text>
</view>
</view>
</template>
<script setup>
import * as api from '@/common/api.js'
import config from '@/config.js'
import _ from 'lodash'
import {
onMounted,
ref
} from 'vue'
import {
onLoad,
onShow
} from '@dcloudio/uni-app'
const app = getApp();
const queryParams = ref({
// pageNum: 1,
// pageSize: 10
status: '0',
type: '1'
})
const statusArr = ['审批中', '审批通过', '审批拒绝', '审批撤回']
const current = ref()
const infoList = ref([])
const total = ref(0)
const deptType = ref('')
const userType = ref('')
onLoad((option) => {
})
onShow(() => {
if (app.globalData.isLogin) {
init()
} else {
app.firstLoadCallback = () => {
init()
};
}
})
function init() {
deptType.value = app.globalData.deptType
userType.value = app.globalData.userType
getList()
}
function getList() {
uni.showLoading({
title: '加载中'
})
api.getCertsLList(queryParams.value).then(res => {
infoList.value = res.rows
uni.hideLoading()
})
}
function goDetail(item) {
// const form = encodeURIComponent(JSON.stringify(item))
let path = `/pages/level/ztx/examList?type=1&payId=${item.payId}`
uni.navigateTo({
url: path
});
}
function send(row) {
uni.showModal({
title: '提示',
content: `确定生成 ${row.name} 的证书吗`,
success: function(res) {
if (res.confirm) {
api.submitCert([{
id: row.payId
}]).then(res => {
uni.showToast({
title: `下发成功`
})
getList()
})
}
}
})
}
</script>
<style scoped lang="scss">
.mt0 {
margin-top: 0 !important;
}
.appList .appItem .name {
width: 80%;
word-break: break-all;
}
</style>
\ No newline at end of file
<template>
<view>
<!-- 级位证书发布 -->
<view class="appList">
<view class="appItem" v-for="item in infoList">
<view class="status" @click="goDetail(item)">
<text :class="{
'text-warning':item.isCert=='0',
'text-primary':item.isCert=='1',
'text-success':item.isCert=='2'
}">{{ statusArr[item.isCert]}}</text>
</view>
<view class="date">申请日期: {{item.applyTime?.slice(0,10)}}</view>
<view class="name mt0" @click="goDetail(item)">{{item.name}}</view>
<view class="pp esp">考级考官:{{item.examinerNames}}</view>
<view class="flexbox" @click="goDetail(item)">
<view>
申请单位
<view>{{item.memberName}}</view>
</view>
<view>
已发/待发证书
<view>{{item.hasCerts}}/<text class="text-danger">{{item.noCerts}}</text></view>
</view>
<view>
考生数/通过数
<view>{{item.totalNum}}/<text class="text-danger">{{item.pass}}</text></view>
</view>
</view>
<view class="func" v-if="item.certStatus != '2'">
<button @click="send(item)">一键生成</button>
</view>
</view>
</view>
<view class="nodata" v-if="infoList.length==0">
<image mode="aspectFit" src="/static/nodata.png"></image>
<text>暂无数据</text>
</view>
</view>
</template>
<script setup>
import * as api from '@/common/api.js'
import config from '@/config.js'
import _ from 'lodash'
import {
onMounted,
ref
} from 'vue'
import {
onLoad,
onShow
} from '@dcloudio/uni-app'
const app = getApp();
const queryParams = ref({
// pageNum: 1,
// pageSize: 10
})
const statusArr = ['未发放', '部分发放', '已发放']
const current = ref()
const infoList = ref([])
const total = ref(0)
const deptType = ref('')
const userType = ref('')
onLoad((option) => {
queryParams.value.payId = option.payId
queryParams.value.type = option.type
})
onShow(() => {
if (app.globalData.isLogin) {
init()
} else {
app.firstLoadCallback = () => {
init()
};
}
})
function init() {
deptType.value = app.globalData.deptType
userType.value = app.globalData.userType
getList()
}
function getList() {
uni.showLoading({
title: '加载中'
})
api.getExamListByPayId(queryParams.value).then(res => {
infoList.value = res.rows
uni.hideLoading()
})
}
function goDetail(item) {
// const form = encodeURIComponent(JSON.stringify(item))
let path = `/pages/level/ztx/studentList?type=${queryParams.value.type}&examId=${item.examId}&payId=${queryParams.value.payId}`
uni.navigateTo({
url: path
});
}
function send(row) {
uni.showModal({
title: '提示',
content: `确定生成 ${row.name} 的证书吗`,
success: function(res) {
if (res.confirm) {
api.submitCert([{
id: row.payId
}]).then(res => {
uni.showToast({
title: `下发成功`
})
getList()
})
}
}
})
}
</script>
<style scoped lang="scss">
.mt0 {
margin-top: 0 !important;
}
.appList .appItem .name {
width: 80%;
word-break: break-all;
}
</style>
\ No newline at end of file
<template>
<view class="hasfixedbottom">
<view class="searchbar">
<uni-easyinput placeholderStyle="font-size:30rpx" :input-border="false" prefixIcon="search"
v-model="queryParams.name" placeholder="搜索姓名" @blur="getList()" @clear="getList()">
</uni-easyinput>
</view>
<view class="indexboxre">
<view class="userlist">
<view class="item" v-for="n in list">
<view class="w100">
<view class="status">
<text class="text-success" v-if="n.isCert == '1' ">已发送</text>
<text class="text-warning" v-else>未发送</text>
</view>
<view class="name">{{n.realName}}</view>
<view class="flexbox mtb30">
<view>所属团体
<text>{{n.memName}}</text>
</view>
<view>会员有效期
<text>{{n.vaildityDate?.slice(0,10)}}</text>
</view>
<view>级位
<text>
{{ szToHz(n.levelNew) }}
</text>
</view>
</view>
<div class="func">
<button @click="sendCert(n)">{{ ['发送证书','更新证书'][n.isCert] }}</button>
</div>
</view>
</view>
</view>
</view>
</view>
</template>
<script setup>
import * as api from '@/common/api.js'
import config from '@/config.js'
import {
ref,
getCurrentInstance
} from 'vue'
import {
onLoad
} from '@dcloudio/uni-app'
const {
proxy
} = getCurrentInstance()
const app = getApp();
const queryParams = ref({})
const list = ref([])
const total = ref(0)
const userType = ref('')
onLoad((option) => {
queryParams.value.examId = option.examId
queryParams.value.payId = option.payId
queryParams.value.type = option.type
getList()
})
function getList() {
uni.showLoading({
title: '加载中'
})
api.certStudentList(queryParams.value).then(res => {
list.value = res.rows
uni.hideLoading()
})
}
function szToHz(num) {
const hzArr = ['〇', '一', '二', '三', '四', '五', '六', '七', '八', '九', '十']
return hzArr[parseInt(num)]
}
function sendCert(row) {
uni.showModal({
title: '提示',
content: `确定下发 ${row.realName} 的证书吗`,
success: function(res) {
if (res.confirm) {
const params = [{
id: queryParams.value.payId,
children: [{
id: queryParams.value.examId,
children: [row.id]
}]
}]
api.submitCert(params).then(res => {
uni.showToast({
title: `下发成功`
})
getList()
})
}
}
})
}
function handleImport() {
var arr = []
for (var n of list.value) {
if (n.checked) {
arr.push(n.perId)
}
}
if (arr.length == 0) {
uni.showToast({
title: "请选择会员",
icon: "none"
})
return
}
api.addPersonPaymentGroup({
rangeId: queryParams.value.paymentRangeId,
personIdArray: arr.join(',')
}).then(res => {
let path = `/pages/personalVip/renew?rangeId=${res.data.rangeId}`
uni.redirectTo({
url: path
});
})
}
</script>
<style scoped lang="scss">
.indexboxre {
padding: 0 30rpx;
.tt {
font-size: 30rpx;
margin: 0 0 30rpx;
color: #4C5359;
}
position: relative;
height: calc(100vh - 280rpx);
overflow: auto;
}
.searchbar {
display: flex;
align-items: center;
padding: 25rpx;
box-sizing: border-box;
:deep(.uni-easyinput .uni-easyinput__content) {
border-radius: 35rpx;
border: none;
height: 70rpx;
}
:deep(.uni-easyinput__content-input) {
font-size: 26rpx;
}
}
</style>
\ No newline at end of file
......@@ -2,7 +2,7 @@
<view class="hasfixedbottom">
<view class="searchbar">
<uni-easyinput placeholderStyle="font-size:30rpx" :input-border="false" prefixIcon="search"
v-model="queryParams.name" placeholder="搜索姓名或证件号码" @blur="getList()" @clear="getList()">
v-model="queryParams.name" placeholder="搜索姓名" @blur="getList()" @clear="getList()">
</uni-easyinput>
</view>
<view class="indexboxre">
......
@font-face {font-family: "iconfont";
src: url('iconfont.eot?t=1587304858380'); /* IE9 */
src: url('iconfont.eot?t=1587304858380#iefix') format('embedded-opentype'), /* IE6-IE8 */
url('data:application/x-font-woff2;charset=utf-8;base64,d09GMgABAAAAAAKYAAsAAAAABkQAAAJOAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHEIGVgCCcApQZAE2AiQDCAsGAAQgBYRtBzAbigXIrrApw69IkQJyuEPQxl76g4HoIYL6/dje+w8TiUTRZBoiHqpVEmRaIRRCYrpn8t//uczdiITNQB7LUyNSaIv5v7/lNAN0rMlIMv6eHwo3dzBnwGQPk3M8ZxtLDRi4CKu4hFtT9xqbz3M5vQl0IPMDneNqDtrDFk3qBXQvDqQA98IosjJJvGHsApfwmECtQTWVzdXtPRiWWasCcWu0A8O5tCyzWrVQWXMwixcVqtNTegeew+/Hn04Mk1QUrJaD8xUf5j/ZxeKxhE/IENDxChSYBzJxUlve0ycY16e23G8U7Ksx+FSWfkjs1S/YX2fV14N+qN6T5uq3WktwWxN1AL2jriQ6LvSLqs8PXI9IP2WWb82rj+Ho6f7KTwh8/vG/+MEqQLlFX3EFFQR3W5dz1tTif3VdBh/nNUyWm/WLguq9RIK/ofUcyLphBVNWtVpz0nGWtlq1KAnHW/2N9XSc2hyqR0SrDKQoVBsnMzuPCnUWUKnaCmrNWTtepw3rE7kGs64BQrNXJI3eUGjWIzP7iwqd/lGpOfpQ6yzaLqwzGWZ0g8kR8tE9ReNlqXLCMho17pA+jB3OGiF/QFyaHLYbrWJtjVLiObaUR7ojolBxluAqeI7iOMOcs5A8aQQiebfZVHVvanhZAqM2MOIQxIdcp5DhyaSUP1qMlj6/g2iHYg5u6aspDxBWMtOjtoZWD3LNkfbqu5dXSke0DiEUpLBMAq2CeSQWy6C8fl6IeERDMKKY62raw1RfR2N9V/J1x6CW5U1hzypUnjtpcGgAAA==') format('woff2'),
url('iconfont.woff?t=1587304858380') format('woff'),
url('iconfont.ttf?t=1587304858380') format('truetype'), /* chrome, firefox, opera, Safari, Android, iOS 4.2+ */
url('iconfont.svg?t=1587304858380#iconfont') format('svg'); /* iOS 4.1- */
}
.iconfont {
font-family: "iconfont" !important;
font-size: 16px;
font-style: normal;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.icon-fanhui:before {
content: "\e65c";
}
No preview for this file type
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" >
<!--
2013-9-30: Created.
-->
<svg>
<metadata>
Created by iconfont
</metadata>
<defs>
<font id="iconfont" horiz-adv-x="1024" >
<font-face
font-family="iconfont"
font-weight="500"
font-stretch="normal"
units-per-em="1024"
ascent="896"
descent="-128"
/>
<missing-glyph />
<glyph glyph-name="fanhui" unicode="&#58972;" d="M349.184 382.976l435.2 432.64c13.824 13.824 13.824 39.424 0 53.76l-13.824 13.824c-13.824 13.824-39.424 13.824-53.76 0L239.616 410.624c-13.824-13.824-13.824-39.424 0-53.76l474.624-472.576c13.824-13.824 39.424-13.824 53.76 0l13.824 13.824c13.824 13.824 13.824 39.424 0 53.76l-432.64 431.104z" horiz-adv-x="1024" />
</font>
</defs></svg>
No preview for this file type
No preview for this file type
Styling with Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!