Merge branch 'master' of https://e.coding.net/ctcdevteam/examtest
This commit is contained in:
commit
398fa371ed
|
|
@ -31,7 +31,11 @@
|
||||||
"pages/qtest/form",
|
"pages/qtest/form",
|
||||||
"pages/main/start",
|
"pages/main/start",
|
||||||
"pages/exam/index",
|
"pages/exam/index",
|
||||||
"pages/exam/note"
|
"pages/exam/note",
|
||||||
|
"pages/admin/index",
|
||||||
|
"pages/admin/login",
|
||||||
|
"pages/admin/exam/add",
|
||||||
|
"pages/admin/exam/add2"
|
||||||
],
|
],
|
||||||
"window": {
|
"window": {
|
||||||
"backgroundTextStyle": "light",
|
"backgroundTextStyle": "light",
|
||||||
|
|
@ -88,7 +92,7 @@
|
||||||
},
|
},
|
||||||
"plugins": {
|
"plugins": {
|
||||||
"tencentvideo": {
|
"tencentvideo": {
|
||||||
"version": "1.3.15",
|
"version": "1.3.31",
|
||||||
"provider": "wxa75efa648b60994b"
|
"provider": "wxa75efa648b60994b"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,566 @@
|
||||||
|
|
||||||
|
Component({
|
||||||
|
/**
|
||||||
|
* 组件的属性列表
|
||||||
|
*/
|
||||||
|
properties: {
|
||||||
|
pickerShow: {
|
||||||
|
type: Boolean,
|
||||||
|
observer:function(val){ //弹出动画
|
||||||
|
// console.log(this.data);
|
||||||
|
if(val){
|
||||||
|
let animation = wx.createAnimation({
|
||||||
|
duration: 500,
|
||||||
|
timingFunction: "ease"
|
||||||
|
});
|
||||||
|
let animationOpacity = wx.createAnimation({
|
||||||
|
duration: 500,
|
||||||
|
timingFunction: "ease"
|
||||||
|
});
|
||||||
|
setTimeout(() => {
|
||||||
|
animation.bottom(0).step();
|
||||||
|
animationOpacity.opacity(0.7).step();
|
||||||
|
this.setData({
|
||||||
|
animationOpacity: animationOpacity.export(),
|
||||||
|
animationData: animation.export()
|
||||||
|
})
|
||||||
|
}, 0);
|
||||||
|
}else{
|
||||||
|
let animation = wx.createAnimation({
|
||||||
|
duration: 100,
|
||||||
|
timingFunction: "ease"
|
||||||
|
});
|
||||||
|
let animationOpacity = wx.createAnimation({
|
||||||
|
duration: 500,
|
||||||
|
timingFunction: "ease"
|
||||||
|
});
|
||||||
|
animation.bottom(-320).step();
|
||||||
|
animationOpacity.opacity(0).step();
|
||||||
|
this.setData({
|
||||||
|
animationOpacity: animationOpacity.export(),
|
||||||
|
animationData: animation.export()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 在picker滚动未停止前点确定,会使startValue数组各项归零,发生错误,这里判断并重新初始化
|
||||||
|
// 微信新增了picker滚动的回调函数,已进行兼容
|
||||||
|
if(this.data.startValue&&this.data.endValue){
|
||||||
|
let s = 0, e = 0;
|
||||||
|
let conf = this.data.config;
|
||||||
|
|
||||||
|
this.data.startValue.map(val => {
|
||||||
|
if (val == 0) {
|
||||||
|
s++
|
||||||
|
}
|
||||||
|
})
|
||||||
|
this.data.endValue.map(val => {
|
||||||
|
if (val == 0) {
|
||||||
|
e++;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
let tmp={
|
||||||
|
hour:4,
|
||||||
|
minute:5,
|
||||||
|
second:6
|
||||||
|
}
|
||||||
|
let n = tmp[conf.column];
|
||||||
|
if (s>=n || e>=n) {
|
||||||
|
this.initPick(this.data.config);
|
||||||
|
this.setData({
|
||||||
|
startValue: this.data.startValue,
|
||||||
|
endValue: this.data.endValue,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
},
|
||||||
|
config: Object
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 组件的初始数据
|
||||||
|
*/
|
||||||
|
data: {
|
||||||
|
// pickerShow:true
|
||||||
|
// limitStartTime: new Date().getTime()-1000*60*60*24*30,
|
||||||
|
// limitEndTime: new Date().getTime(),
|
||||||
|
// yearStart:2000,
|
||||||
|
// yearEnd:2100
|
||||||
|
},
|
||||||
|
detached: function() {
|
||||||
|
console.log("dele");
|
||||||
|
},
|
||||||
|
attached: function() {},
|
||||||
|
ready: function() {
|
||||||
|
this.readConfig();
|
||||||
|
this.initPick(this.data.config || null);
|
||||||
|
this.setData({
|
||||||
|
startValue: this.data.startValue,
|
||||||
|
endValue: this.data.endValue,
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* 组件的方法列表
|
||||||
|
*/
|
||||||
|
methods: {
|
||||||
|
//阻止滑动事件
|
||||||
|
onCatchTouchMove(e) {
|
||||||
|
|
||||||
|
},
|
||||||
|
//读取配置项
|
||||||
|
readConfig() {
|
||||||
|
let limitEndTime = new Date().getTime();
|
||||||
|
let limitStartTime = new Date().getTime() - 1000 * 60 * 60 * 24 * 30;
|
||||||
|
if (this.data.config) {
|
||||||
|
let conf = this.data.config;
|
||||||
|
|
||||||
|
if (typeof conf.dateLimit == "number") {
|
||||||
|
limitStartTime =
|
||||||
|
new Date().getTime() - 1000 * 60 * 60 * 24 * conf.dateLimit;
|
||||||
|
}
|
||||||
|
if(conf.limitStartTime){
|
||||||
|
|
||||||
|
limitStartTime = new Date(conf.limitStartTime.replace(/-/g,'/')).getTime();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (conf.limitEndTime) {
|
||||||
|
limitEndTime = new Date(conf.limitEndTime.replace(/-/g, '/')).getTime();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.setData({
|
||||||
|
yearStart: conf.yearStart || 2000,
|
||||||
|
yearEnd: conf.yearEnd || 2100,
|
||||||
|
endDate: conf.endDate || false,
|
||||||
|
dateLimit: conf.dateLimit || false,
|
||||||
|
hourColumn:
|
||||||
|
conf.column == "hour" ||
|
||||||
|
conf.column == "minute" ||
|
||||||
|
conf.column == "second",
|
||||||
|
minColumn: conf.column == "minute" || conf.column == "second",
|
||||||
|
secColumn: conf.column == "second"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
let limitStartTimeArr = formatTime(limitStartTime);
|
||||||
|
let limitEndTimeArr = formatTime(limitEndTime);
|
||||||
|
|
||||||
|
this.setData({
|
||||||
|
limitStartTime,
|
||||||
|
limitStartTimeArr,
|
||||||
|
limitEndTime,
|
||||||
|
limitEndTimeArr
|
||||||
|
});
|
||||||
|
},
|
||||||
|
//滚动开始
|
||||||
|
handlePickStart:function(e){
|
||||||
|
this.setData({
|
||||||
|
isPicking:true
|
||||||
|
})
|
||||||
|
},
|
||||||
|
//滚动结束
|
||||||
|
handlePickEnd:function(e){
|
||||||
|
this.setData({
|
||||||
|
isPicking:false
|
||||||
|
})
|
||||||
|
},
|
||||||
|
onConfirm: function() {
|
||||||
|
//滚动未结束时不能确认
|
||||||
|
if(this.data.isPicking){return}
|
||||||
|
let startTime = new Date(this.data.startPickTime.replace(/-/g, "/"));
|
||||||
|
let endTime = new Date(this.data.endPickTime.replace(/-/g, "/"));
|
||||||
|
if (startTime <= endTime || !this.data.endDate) {
|
||||||
|
this.setData({
|
||||||
|
startTime,
|
||||||
|
endTime
|
||||||
|
});
|
||||||
|
let startArr = formatTime(startTime).arr;
|
||||||
|
let endArr = formatTime(endTime).arr;
|
||||||
|
let format0 = function(num){
|
||||||
|
return num<10?'0'+num:num
|
||||||
|
}
|
||||||
|
|
||||||
|
let startTimeBack =
|
||||||
|
startArr[0] +
|
||||||
|
"-" +
|
||||||
|
format0(startArr[1]) +
|
||||||
|
"-" +
|
||||||
|
format0(startArr[2]) +
|
||||||
|
" " +
|
||||||
|
(this.data.hourColumn ? format0(startArr[3]) : "00") +
|
||||||
|
":" +
|
||||||
|
(this.data.minColumn ? format0(startArr[4]) : "00") +
|
||||||
|
":" +
|
||||||
|
(this.data.secColumn ? format0(startArr[5]) : "00");
|
||||||
|
|
||||||
|
let endTimeBack =
|
||||||
|
endArr[0] +
|
||||||
|
"-" +
|
||||||
|
format0(endArr[1]) +
|
||||||
|
"-" +
|
||||||
|
format0(endArr[2]) +
|
||||||
|
" " +
|
||||||
|
(this.data.hourColumn ? format0(endArr[3]) : "00") +
|
||||||
|
":" +
|
||||||
|
(this.data.minColumn ? format0(endArr[4]) : "00") +
|
||||||
|
":" +
|
||||||
|
(this.data.secColumn ? format0(endArr[5]) : "00");
|
||||||
|
|
||||||
|
let time = {
|
||||||
|
startTime: startTimeBack,
|
||||||
|
endTime: endTimeBack
|
||||||
|
};
|
||||||
|
|
||||||
|
//触发自定义事件
|
||||||
|
this.triggerEvent("setPickerTime", time);
|
||||||
|
this.triggerEvent("hidePicker", {});
|
||||||
|
} else {
|
||||||
|
wx.showToast({
|
||||||
|
icon: "none",
|
||||||
|
title: "时间不合理"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
hideModal: function() {
|
||||||
|
|
||||||
|
this.triggerEvent("hidePicker", {});
|
||||||
|
},
|
||||||
|
changeStartDateTime: function(e) {
|
||||||
|
let val = e.detail.value;
|
||||||
|
|
||||||
|
this.compareTime(val, "start");
|
||||||
|
},
|
||||||
|
|
||||||
|
changeEndDateTime: function(e) {
|
||||||
|
let val = e.detail.value;
|
||||||
|
this.compareTime(val, "end");
|
||||||
|
},
|
||||||
|
//比较时间是否在范围内
|
||||||
|
compareTime(val, type) {
|
||||||
|
let h = val[3] ? this.data.HourList[val[3]] : "00";
|
||||||
|
let m = val[4] ? this.data.MinuteList[val[4]] : "00";
|
||||||
|
let s = val[5] ? this.data.SecondList[val[5]] : "00";
|
||||||
|
let time =
|
||||||
|
this.data.YearList[val[0]] +
|
||||||
|
"-" +
|
||||||
|
this.data.MonthList[val[1]] +
|
||||||
|
"-" +
|
||||||
|
this.data.DayList[val[2]] +
|
||||||
|
" " +
|
||||||
|
h +
|
||||||
|
":" +
|
||||||
|
m +
|
||||||
|
":" +
|
||||||
|
s;
|
||||||
|
|
||||||
|
let start = this.data.limitStartTime;
|
||||||
|
let end = this.data.limitEndTime;
|
||||||
|
let timeNum = new Date(time.replace(/-/g, '/')).getTime();
|
||||||
|
let year, month, day, hour, min, sec, limitDate;
|
||||||
|
let tempArr = []
|
||||||
|
|
||||||
|
if (!this.data.dateLimit){
|
||||||
|
limitDate = [
|
||||||
|
this.data.YearList[val[0]],
|
||||||
|
this.data.MonthList[val[1]],
|
||||||
|
this.data.DayList[val[2]],
|
||||||
|
this.data.HourList[val[3]],
|
||||||
|
this.data.MinuteList[val[4]],
|
||||||
|
this.data.SecondList[val[5]]]
|
||||||
|
} else if (type == "start" && timeNum > new Date(this.data.endPickTime.replace(/-/g, '/')) && this.data.config.endDate) {
|
||||||
|
limitDate = formatTime(this.data.endPickTime).arr;
|
||||||
|
|
||||||
|
} else if (type == "end" && timeNum < new Date(this.data.startPickTime.replace(/-/g, '/'))) {
|
||||||
|
limitDate = formatTime(this.data.startPickTime).arr;
|
||||||
|
|
||||||
|
} else if (timeNum < start) {
|
||||||
|
limitDate = this.data.limitStartTimeArr.arr;
|
||||||
|
|
||||||
|
} else if (timeNum > end) {
|
||||||
|
limitDate = this.data.limitEndTimeArr.arr;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
limitDate = [
|
||||||
|
this.data.YearList[val[0]],
|
||||||
|
this.data.MonthList[val[1]],
|
||||||
|
this.data.DayList[val[2]],
|
||||||
|
this.data.HourList[val[3]],
|
||||||
|
this.data.MinuteList[val[4]],
|
||||||
|
this.data.SecondList[val[5]]
|
||||||
|
]
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
year = limitDate[0];
|
||||||
|
month = limitDate[1];
|
||||||
|
day = limitDate[2];
|
||||||
|
hour = limitDate[3];
|
||||||
|
min = limitDate[4];
|
||||||
|
sec = limitDate[5];
|
||||||
|
|
||||||
|
if (type == "start") {
|
||||||
|
this.setStartDate(year, month, day, hour, min, sec);
|
||||||
|
} else if (type == "end") {
|
||||||
|
this.setEndDate(year, month, day, hour, min, sec);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
getDays: function(year, month) {
|
||||||
|
let daysInMonth = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
|
||||||
|
if (month === 2) {
|
||||||
|
return (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0
|
||||||
|
? 29
|
||||||
|
: 28;
|
||||||
|
} else {
|
||||||
|
return daysInMonth[month - 1];
|
||||||
|
}
|
||||||
|
},
|
||||||
|
initPick: function(initData) {
|
||||||
|
const date = initData.initStartTime ? new Date(initData.initStartTime.replace(/-/g, '/')): new Date();
|
||||||
|
const endDate = initData.initEndTime ? new Date(initData.initEndTime.replace(/-/g, '/')) : new Date();
|
||||||
|
// const startDate = new Date(date.getTime() - 1000 * 60 * 60 * 24);
|
||||||
|
const startDate = date;
|
||||||
|
const startYear = date.getFullYear();
|
||||||
|
const startMonth = date.getMonth() + 1;
|
||||||
|
const startDay = date.getDate();
|
||||||
|
const startHour = date.getHours();
|
||||||
|
const startMinute = date.getMinutes();
|
||||||
|
const startSecond = date.getSeconds();
|
||||||
|
|
||||||
|
const endYear = endDate.getFullYear();
|
||||||
|
const endMonth = endDate.getMonth() + 1;
|
||||||
|
const endDay = endDate.getDate();
|
||||||
|
const endHour = endDate.getHours();
|
||||||
|
const endMinute = endDate.getMinutes();
|
||||||
|
const endSecond = endDate.getSeconds();
|
||||||
|
|
||||||
|
let YearList = [];
|
||||||
|
let MonthList = [];
|
||||||
|
let DayList = [];
|
||||||
|
let HourList = [];
|
||||||
|
let MinuteList = [];
|
||||||
|
let SecondList = [];
|
||||||
|
|
||||||
|
//设置年份列表
|
||||||
|
for (let i = this.data.yearStart; i <= this.data.yearEnd; i++) {
|
||||||
|
YearList.push(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置月份列表
|
||||||
|
for (let i = 1; i <= 12; i++) {
|
||||||
|
MonthList.push(i);
|
||||||
|
}
|
||||||
|
// 设置日期列表
|
||||||
|
for (let i = 1; i <= 31; i++) {
|
||||||
|
DayList.push(i);
|
||||||
|
}
|
||||||
|
// 设置时列表
|
||||||
|
for (let i = 0; i <= 23; i++) {
|
||||||
|
if (0 <= i && i < 10) {
|
||||||
|
i = "0" + i;
|
||||||
|
}
|
||||||
|
HourList.push(i);
|
||||||
|
}
|
||||||
|
// 分|秒
|
||||||
|
for (let i = 0; i <= 59; i++) {
|
||||||
|
if (0 <= i && i < 10) {
|
||||||
|
i = "0" + i;
|
||||||
|
}
|
||||||
|
MinuteList.push(i);
|
||||||
|
SecondList.push(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.setData({
|
||||||
|
YearList,
|
||||||
|
MonthList,
|
||||||
|
DayList,
|
||||||
|
HourList,
|
||||||
|
MinuteList,
|
||||||
|
SecondList
|
||||||
|
});
|
||||||
|
|
||||||
|
this.setStartDate(startYear, startMonth, startDay, startHour, startMinute, startSecond);
|
||||||
|
this.setEndDate(endYear, endMonth, endDay, endHour, endMinute, endSecond);
|
||||||
|
|
||||||
|
//!!!
|
||||||
|
// setTimeout(() => {
|
||||||
|
// this.setStartDate(nowYear, nowMonth, nowDay, nowHour, nowMinute)
|
||||||
|
// this.setEndDate(nowYear, nowMonth, nowDay, nowHour, nowMinute)
|
||||||
|
// }, 0);
|
||||||
|
},
|
||||||
|
setPickerDateArr(type, year, month, day, hour, minute, second) {
|
||||||
|
let yearIdx = 0;
|
||||||
|
let monthIdx = 0;
|
||||||
|
let dayIdx = 0;
|
||||||
|
let hourIdx = 0;
|
||||||
|
let minuteIdx = 0;
|
||||||
|
let secondIdx = 0;
|
||||||
|
|
||||||
|
this.data.YearList.map((v, idx) => {
|
||||||
|
if (parseInt(v) === year) {
|
||||||
|
yearIdx = idx;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
this.data.MonthList.map((v, idx) => {
|
||||||
|
if (parseInt(v) === month) {
|
||||||
|
monthIdx = idx;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 重新设置日期列表
|
||||||
|
let DayList = [];
|
||||||
|
for (let i = 1; i <= this.getDays(year, month); i++) {
|
||||||
|
DayList.push(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
DayList.map((v, idx) => {
|
||||||
|
if (parseInt(v) === day) {
|
||||||
|
dayIdx = idx;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (type == "start") {
|
||||||
|
this.setData({ startDayList: DayList });
|
||||||
|
} else if (type == "end") {
|
||||||
|
this.setData({ endDayList: DayList });
|
||||||
|
}
|
||||||
|
|
||||||
|
this.data.HourList.map((v, idx) => {
|
||||||
|
if (parseInt(v) === parseInt(hour)) {
|
||||||
|
hourIdx = idx;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
this.data.MinuteList.map((v, idx) => {
|
||||||
|
if (parseInt(v) === parseInt(minute)) {
|
||||||
|
minuteIdx = idx;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this.data.SecondList.map((v, idx) => {
|
||||||
|
if (parseInt(v) === parseInt(second)) {
|
||||||
|
secondIdx = idx;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
yearIdx,
|
||||||
|
monthIdx,
|
||||||
|
dayIdx,
|
||||||
|
hourIdx,
|
||||||
|
minuteIdx,
|
||||||
|
secondIdx
|
||||||
|
};
|
||||||
|
},
|
||||||
|
setStartDate: function(year, month, day, hour, minute, second) {
|
||||||
|
let pickerDateArr = this.setPickerDateArr(
|
||||||
|
"start",
|
||||||
|
year,
|
||||||
|
month,
|
||||||
|
day,
|
||||||
|
hour,
|
||||||
|
minute,
|
||||||
|
second
|
||||||
|
);
|
||||||
|
this.setData({
|
||||||
|
startYearList: this.data.YearList,
|
||||||
|
startMonthList: this.data.MonthList,
|
||||||
|
// startDayList: this.data.DayList,
|
||||||
|
startHourList: this.data.HourList,
|
||||||
|
startMinuteList: this.data.MinuteList,
|
||||||
|
startSecondList: this.data.SecondList,
|
||||||
|
startValue: [
|
||||||
|
pickerDateArr.yearIdx,
|
||||||
|
pickerDateArr.monthIdx,
|
||||||
|
pickerDateArr.dayIdx,
|
||||||
|
pickerDateArr.hourIdx,
|
||||||
|
pickerDateArr.minuteIdx,
|
||||||
|
pickerDateArr.secondIdx
|
||||||
|
],
|
||||||
|
startPickTime:
|
||||||
|
this.data.YearList[pickerDateArr.yearIdx] +
|
||||||
|
"-" +
|
||||||
|
this.data.MonthList[pickerDateArr.monthIdx] +
|
||||||
|
"-" +
|
||||||
|
this.data.DayList[pickerDateArr.dayIdx] +
|
||||||
|
" " +
|
||||||
|
this.data.HourList[pickerDateArr.hourIdx] +
|
||||||
|
":" +
|
||||||
|
this.data.MinuteList[pickerDateArr.minuteIdx] +
|
||||||
|
":" +
|
||||||
|
this.data.SecondList[pickerDateArr.secondIdx]
|
||||||
|
});
|
||||||
|
},
|
||||||
|
setEndDate: function(year, month, day, hour, minute, second) {
|
||||||
|
let pickerDateArr = this.setPickerDateArr(
|
||||||
|
"end",
|
||||||
|
year,
|
||||||
|
month,
|
||||||
|
day,
|
||||||
|
hour,
|
||||||
|
minute,
|
||||||
|
second
|
||||||
|
);
|
||||||
|
|
||||||
|
this.setData({
|
||||||
|
endYearList: this.data.YearList,
|
||||||
|
endMonthList: this.data.MonthList,
|
||||||
|
// endDayList: this.data.DayList,
|
||||||
|
endHourList: this.data.HourList,
|
||||||
|
endMinuteList: this.data.MinuteList,
|
||||||
|
endSecondList: this.data.SecondList,
|
||||||
|
endValue: [
|
||||||
|
pickerDateArr.yearIdx,
|
||||||
|
pickerDateArr.monthIdx,
|
||||||
|
pickerDateArr.dayIdx,
|
||||||
|
pickerDateArr.hourIdx,
|
||||||
|
pickerDateArr.minuteIdx,
|
||||||
|
pickerDateArr.secondIdx
|
||||||
|
],
|
||||||
|
endPickTime:
|
||||||
|
this.data.YearList[pickerDateArr.yearIdx] +
|
||||||
|
"-" +
|
||||||
|
this.data.MonthList[pickerDateArr.monthIdx] +
|
||||||
|
"-" +
|
||||||
|
this.data.DayList[pickerDateArr.dayIdx] +
|
||||||
|
" " +
|
||||||
|
this.data.HourList[pickerDateArr.hourIdx] +
|
||||||
|
":" +
|
||||||
|
this.data.MinuteList[pickerDateArr.minuteIdx] +
|
||||||
|
":" +
|
||||||
|
this.data.SecondList[pickerDateArr.secondIdx]
|
||||||
|
});
|
||||||
|
},
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
function formatTime(date) {
|
||||||
|
|
||||||
|
if (typeof date == 'string' || 'number') {
|
||||||
|
try {
|
||||||
|
date = date.replace(/-/g, '/')//兼容ios
|
||||||
|
} catch (error) {
|
||||||
|
}
|
||||||
|
date = new Date(date)
|
||||||
|
}
|
||||||
|
|
||||||
|
const year = date.getFullYear()
|
||||||
|
const month = date.getMonth() + 1
|
||||||
|
const day = date.getDate()
|
||||||
|
const hour = date.getHours()
|
||||||
|
const minute = date.getMinutes()
|
||||||
|
const second = date.getSeconds()
|
||||||
|
|
||||||
|
return {
|
||||||
|
str: [year, month, day].map(formatNumber).join('-') + ' ' + [hour, minute, second].map(formatNumber).join(':'),
|
||||||
|
arr: [year, month, day, hour, minute, second]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function formatNumber(n) {
|
||||||
|
n = n.toString()
|
||||||
|
return n[1] ? n : '0' + n
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,4 @@
|
||||||
|
{
|
||||||
|
"component": true,
|
||||||
|
"usingComponents": {}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,68 @@
|
||||||
|
<!--components/timePicker/timePicker.wxml-->
|
||||||
|
<!-- 自定义时间筛选器 -->
|
||||||
|
<view hidden="{{!pickerShow}}">
|
||||||
|
<view class="picker-container {{pickerShow?'show_picker':'hide_picker'}}" animation="{{animationData}}">
|
||||||
|
|
||||||
|
<view class="btn-box" catchtouchmove="onCatchTouchMove">
|
||||||
|
<view class="pick_btn" bindtap="hideModal">取消</view>
|
||||||
|
<view class='pick_btn' style="color: #19f" bindtap="onConfirm">确定</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view>
|
||||||
|
<picker-view class='sensorTypePicker' indicator-style='height: 35px;' bindchange="changeStartDateTime"
|
||||||
|
value="{{startValue}}" style="height: {{endDate?'120px':'250px'}};" bindpickstart="handlePickStart" bindpickend="handlePickEnd">
|
||||||
|
<picker-view-column style="min-width: 70px;flex-shrink: 0">
|
||||||
|
<view class='picker-item' wx:for="{{startYearList}}" wx:key='*this'>{{item}}年</view>
|
||||||
|
</picker-view-column>
|
||||||
|
<picker-view-column>
|
||||||
|
<view class='picker-item' wx:for="{{startMonthList}}" wx:key='*this'>{{item}}月</view>
|
||||||
|
</picker-view-column>
|
||||||
|
<picker-view-column>
|
||||||
|
<view class='picker-item' wx:for="{{startDayList}}" wx:key='*this'>{{item}}日</view>
|
||||||
|
</picker-view-column>
|
||||||
|
<picker-view-column hidden="{{!hourColumn}}">
|
||||||
|
<view class='picker-item' wx:for="{{startHourList}}" wx:key='*this'>{{item}}时</view>
|
||||||
|
</picker-view-column>
|
||||||
|
<picker-view-column hidden="{{!minColumn}}">
|
||||||
|
<view class='picker-item' wx:for="{{startMinuteList}}" wx:key='*this'>{{item}}分</view>
|
||||||
|
</picker-view-column>
|
||||||
|
<picker-view-column hidden="{{!secColumn}}">
|
||||||
|
<view class='picker-item' wx:for="{{startSecondList}}" wx:key='*this'>{{item}}秒</view>
|
||||||
|
</picker-view-column>
|
||||||
|
</picker-view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view wx:if="{{endDate}}">
|
||||||
|
<view class='to' style='margin-top: 4px;margin-bottom: 4px;'>至</view>
|
||||||
|
<picker-view class='sensorTypePicker' indicator-style='height: 35px;' bindchange="changeEndDateTime" bindpickstart="handlePickStart" bindpickend="handlePickEnd"
|
||||||
|
value="{{endValue}}">
|
||||||
|
<picker-view-column style="min-width: 70px;flex-shrink: 0">
|
||||||
|
<view class='picker-item' wx:for="{{endYearList}}" wx:key='*this' style="min-width: 70px;">{{item}}年</view>
|
||||||
|
</picker-view-column>
|
||||||
|
<picker-view-column>
|
||||||
|
<view class='picker-item' wx:for="{{endMonthList}}" wx:key='*this'>{{item}}月</view>
|
||||||
|
</picker-view-column>
|
||||||
|
<picker-view-column>
|
||||||
|
<view class='picker-item' wx:for="{{endDayList}}" wx:key='*this'>{{item}}日</view>
|
||||||
|
</picker-view-column>
|
||||||
|
<picker-view-column hidden="{{!hourColumn}}" >
|
||||||
|
<view class='picker-item' wx:for="{{endHourList}}" wx:key='*this'>{{item}}时</view>
|
||||||
|
</picker-view-column>
|
||||||
|
<picker-view-column hidden="{{!minColumn}}">
|
||||||
|
<view class='picker-item' wx:for="{{endMinuteList}}" wx:key='*this'>{{item}}分</view>
|
||||||
|
</picker-view-column>
|
||||||
|
<picker-view-column hidden="{{!secColumn}}">
|
||||||
|
<view class='picker-item' wx:for="{{startSecondList}}" wx:key='*this'>{{item}}秒</view>
|
||||||
|
</picker-view-column>
|
||||||
|
|
||||||
|
|
||||||
|
</picker-view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
|
||||||
|
<!-- <view class='sure' bindtap="onConfirm">确定</view> -->
|
||||||
|
|
||||||
|
</view>
|
||||||
|
<!-- 遮罩 -->
|
||||||
|
<view class="sensorType-screen" bindtap="hideModal" catchtouchmove="onCatchTouchMove" animation="{{animationOpacity}}"/>
|
||||||
|
</view>
|
||||||
|
|
@ -0,0 +1,96 @@
|
||||||
|
/* components/timePicker/timePicker.wxss */
|
||||||
|
|
||||||
|
.picker-item{
|
||||||
|
line-height: 100rpx;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 自定义时间 */
|
||||||
|
.picker-container {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
/* justify-content: center; */
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
width: 100%;
|
||||||
|
overflow: hidden;
|
||||||
|
position: fixed;
|
||||||
|
bottom: -640rpx;
|
||||||
|
left: 0;
|
||||||
|
/* height: 0; */
|
||||||
|
transition: height 0.5s;
|
||||||
|
z-index: 2000;
|
||||||
|
background: white;
|
||||||
|
border-top: 1px solid #EFEFF4;
|
||||||
|
}
|
||||||
|
.sensorType-screen{
|
||||||
|
width: 100vw;
|
||||||
|
/* height:400rpx; */
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
background: #000;
|
||||||
|
opacity: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
z-index: 1999;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
.sensorTypePicker{
|
||||||
|
width: 690rpx;
|
||||||
|
height: 240rpx;
|
||||||
|
/* padding: 45px 0; */
|
||||||
|
}
|
||||||
|
.picker-item{
|
||||||
|
line-height: 100rpx;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
font-size: 32rpx;
|
||||||
|
/* overflow: hidden; */
|
||||||
|
}
|
||||||
|
.box{
|
||||||
|
padding: 0 20rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 至 */
|
||||||
|
.to{
|
||||||
|
width:100%;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;align-items: center;
|
||||||
|
color:rgb(138,138,138);
|
||||||
|
/* font-size:30rpx; */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 确定 */
|
||||||
|
.sure{
|
||||||
|
width:100%;
|
||||||
|
height:90rpx;
|
||||||
|
border-top: 2rpx solid #EFEFF4;
|
||||||
|
display: flex;justify-content: center;align-items: center;
|
||||||
|
color: rgb(36,123,255);
|
||||||
|
font-size:16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-box{
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
border-bottom: 2rpx solid #eee;
|
||||||
|
}
|
||||||
|
.pick_btn{
|
||||||
|
padding: 14rpx 30rpx;
|
||||||
|
color: #ccc;
|
||||||
|
/* background-color: #159; */
|
||||||
|
}
|
||||||
|
|
||||||
|
.show_picker{
|
||||||
|
/* height: 320px; */
|
||||||
|
}
|
||||||
|
.hide_picker{
|
||||||
|
/* height: 0; */
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,291 @@
|
||||||
|
// components/dynamicForm/index.js
|
||||||
|
import formatTime from './utils/formatTime';
|
||||||
|
|
||||||
|
Component({
|
||||||
|
/**
|
||||||
|
* 组件的属性列表
|
||||||
|
*/
|
||||||
|
properties: {
|
||||||
|
formData: Array,
|
||||||
|
showSubmitBtn: {
|
||||||
|
type: Boolean,
|
||||||
|
value: true
|
||||||
|
},
|
||||||
|
toSubmit: Number
|
||||||
|
},
|
||||||
|
//监听数据变化, 当toSubmit 值变化时, 代表父组件点击提交案例事件
|
||||||
|
observers: {
|
||||||
|
'toSubmit': function (e) {
|
||||||
|
if (e) {
|
||||||
|
this.formSubmit();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'formData': function () {
|
||||||
|
this.formInit();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* 组件的初始数据
|
||||||
|
*/
|
||||||
|
data: {
|
||||||
|
pickerMap: {},
|
||||||
|
fileMap: {},
|
||||||
|
inputMap: {}
|
||||||
|
},
|
||||||
|
lifetimes: {
|
||||||
|
attached: function () {
|
||||||
|
this.formInit();
|
||||||
|
},
|
||||||
|
moved: function () { },
|
||||||
|
detached: function () { },
|
||||||
|
},
|
||||||
|
pageLifetimes: {
|
||||||
|
// 组件所在页面的生命周期函数
|
||||||
|
show: function () { },
|
||||||
|
hide: function () { },
|
||||||
|
resize: function () { },
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* 组件的方法列表
|
||||||
|
*/
|
||||||
|
methods: {
|
||||||
|
//表单初始化
|
||||||
|
formInit() {
|
||||||
|
|
||||||
|
const pickerMap = {}, fileMap = {}, inputMap = {}, dateMap = {};//存储各表单变化后的值,表单id为索引
|
||||||
|
const pickers = [], files = [], inputs = [], datePickers = [];
|
||||||
|
this.data.formData.forEach(val => {
|
||||||
|
switch (val.type) {
|
||||||
|
case 'picker':
|
||||||
|
pickers.push(val);
|
||||||
|
break;
|
||||||
|
case 'file':
|
||||||
|
files.push(val);
|
||||||
|
break;
|
||||||
|
case 'input':
|
||||||
|
case 'textarea':
|
||||||
|
inputs.push(val);
|
||||||
|
break;
|
||||||
|
case 'date':
|
||||||
|
datePickers.push(val);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
pickers.forEach(val => {
|
||||||
|
pickerMap[val.id] = {
|
||||||
|
original: val,
|
||||||
|
hasChoose: val.defaultIdx != 'undefined',
|
||||||
|
error:null,
|
||||||
|
idx: val.defaultIdx || 0
|
||||||
|
};
|
||||||
|
});
|
||||||
|
files.forEach(val => {
|
||||||
|
fileMap[val.id] = {
|
||||||
|
original: val,
|
||||||
|
error: null,
|
||||||
|
list: val.fileList
|
||||||
|
};
|
||||||
|
});
|
||||||
|
inputs.forEach(val => {
|
||||||
|
inputMap[val.id] = {
|
||||||
|
original: val,
|
||||||
|
value: val.defaultValue || '',
|
||||||
|
placeholder: val.placeholder,
|
||||||
|
error: null,
|
||||||
|
rules: val.rules ? val.rules.map(val => {
|
||||||
|
val.regular = new RegExp(val.regular);
|
||||||
|
return val;
|
||||||
|
}) : []
|
||||||
|
};
|
||||||
|
});
|
||||||
|
datePickers.forEach(val => {
|
||||||
|
dateMap[val.id] = {
|
||||||
|
original: val,
|
||||||
|
config: val.config,
|
||||||
|
completeTime: val.completeTime,
|
||||||
|
show: false,
|
||||||
|
hasChoose: !!val.config.initStartTime,
|
||||||
|
error: null,
|
||||||
|
startDate: val.config.initStartTime || formatTime(),
|
||||||
|
endDate: val.config.initEndTime || formatTime()
|
||||||
|
};
|
||||||
|
if (!val.completeTime){
|
||||||
|
dateMap[val.id].startDate = dateMap[val.id].startDate.split(' ')[0];
|
||||||
|
dateMap[val.id].endDate = dateMap[val.id].endDate.split(' ')[0];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this.setData({
|
||||||
|
pickers,
|
||||||
|
inputs,
|
||||||
|
datePickers,
|
||||||
|
files,
|
||||||
|
pickerMap,
|
||||||
|
inputMap,
|
||||||
|
fileMap,
|
||||||
|
dateMap
|
||||||
|
});
|
||||||
|
},
|
||||||
|
//提交表单
|
||||||
|
formSubmit() {
|
||||||
|
let formData = {};
|
||||||
|
const { pickerMap, inputMap, dateMap, fileMap } = this.data;
|
||||||
|
for (let i in this.data) { //获取表单数据后缀为Map
|
||||||
|
if (i.match(/Map$/)) {
|
||||||
|
formData = Object.assign({}, formData, this.data[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let hasError = false;
|
||||||
|
for (let i in formData) {//循环验证所有表单数据规则
|
||||||
|
let info = formData[i];
|
||||||
|
if (info.original.type === 'input' || info.original.type === 'textarea') {
|
||||||
|
if (!info.value){
|
||||||
|
if (info.original.isRequired){
|
||||||
|
info.error = info.original.lable + '不可为空';
|
||||||
|
hasError = true;
|
||||||
|
}
|
||||||
|
} else if (info.rules){
|
||||||
|
for (let val of info.rules) {
|
||||||
|
if (!info.value.match(val.regular)) {
|
||||||
|
info.error = val.tips || '格式有误';
|
||||||
|
hasError = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.setData({
|
||||||
|
[`inputMap.${i}`]: info
|
||||||
|
});
|
||||||
|
} else if (info.original.type === 'file') {
|
||||||
|
if (info.list.length === 0 && info.original.isRequired) {
|
||||||
|
let error = '请选择文件';
|
||||||
|
if (info.original.accept === 'video') {
|
||||||
|
error = '请选择视频';
|
||||||
|
} else if (info.original.accept === 'image') {
|
||||||
|
error = '请选择图片';
|
||||||
|
}
|
||||||
|
info.error = error;
|
||||||
|
hasError = true;
|
||||||
|
this.setData({
|
||||||
|
[`fileMap.${i}`]: info
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else if (info.original.type === 'picker' || info.original.type === 'date'){
|
||||||
|
if (!info.hasChoose && info.original.isRequired){
|
||||||
|
info.error = '请选择' + info.original.lable;
|
||||||
|
hasError = true;
|
||||||
|
this.setData({
|
||||||
|
[`${info.original.type}Map.${i}`]: info
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (hasError) {
|
||||||
|
wx.showToast({
|
||||||
|
title: '表单填写有误',
|
||||||
|
icon: 'none'
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.triggerEvent('dynamicFormSubmit', formData);
|
||||||
|
console.log(formData);
|
||||||
|
|
||||||
|
},
|
||||||
|
//更新数据劫持
|
||||||
|
updateData(key,val){
|
||||||
|
this.setData({
|
||||||
|
[key]: val
|
||||||
|
});
|
||||||
|
this.triggerEvent('dynamicFormChange', { key, val});
|
||||||
|
},
|
||||||
|
//显示选择器
|
||||||
|
datePickerShow(e) {
|
||||||
|
if (e.target.dataset.disabled) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.setData({
|
||||||
|
[`dateMap.${e.target.dataset.id}.show`]: true
|
||||||
|
});
|
||||||
|
},
|
||||||
|
//隐藏时间选择器
|
||||||
|
datePickerHide(id) {
|
||||||
|
if (typeof id === 'object') {
|
||||||
|
id = id.target.id;
|
||||||
|
}
|
||||||
|
this.setData({
|
||||||
|
[`dateMap.${id}.show`]: false
|
||||||
|
});
|
||||||
|
},
|
||||||
|
//设置选择器时间
|
||||||
|
setPickerTime(e) {
|
||||||
|
const {dateMap} = this.data;
|
||||||
|
const { startTime, endTime } = e.detail;
|
||||||
|
const date = dateMap[e.target.id];
|
||||||
|
if (!date.hasChoose){
|
||||||
|
date.hasChoose = true;
|
||||||
|
date.error = null;
|
||||||
|
}
|
||||||
|
date.show = false;
|
||||||
|
date.startDate = date.completeTime ? startTime :startTime.split(' ')[0];
|
||||||
|
date.endDate = date.completeTime ?endTime :endTime.split(' ')[0];
|
||||||
|
this.updateData(`dateMap.${e.target.id}`,date);
|
||||||
|
},
|
||||||
|
//输入框
|
||||||
|
onInput(e) {
|
||||||
|
const { value } = e.detail;
|
||||||
|
const info = this.data.inputMap[e.target.id] || {};
|
||||||
|
if (!info) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
info.value = e.detail.value;
|
||||||
|
info.error = null;
|
||||||
|
if (info.rules && info.value) {
|
||||||
|
for (let val of info.rules) {
|
||||||
|
if (!info.value.match(val.regular)) {
|
||||||
|
info.error = val.tips || '格式有误';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.updateData(`inputMap.${e.target.id}`, info);
|
||||||
|
},
|
||||||
|
//picker选择
|
||||||
|
onPickerChange(e) {
|
||||||
|
const { id } = e.target;
|
||||||
|
const picker = this.data.pickerMap[id];
|
||||||
|
if(!picker.hasChoose){
|
||||||
|
picker.hasChoose = true;
|
||||||
|
picker.error = null;
|
||||||
|
}
|
||||||
|
picker.idx = e.detail.value;
|
||||||
|
picker.data = this.data.pickers.filter(val => val.id === id)[0].range[e.detail.value];
|
||||||
|
this.updateData(`pickerMap.${e.target.id}`, picker);
|
||||||
|
},
|
||||||
|
// 选择文件
|
||||||
|
onFileRead(e) {
|
||||||
|
console.log(e);
|
||||||
|
for (let val of e.detail.file) {
|
||||||
|
const size = this.data.fileMap[e.target.id].original.maxSize;
|
||||||
|
if (val.size > size * 1024 * 1024) {
|
||||||
|
wx.showToast({
|
||||||
|
title: `请选择${size}MB以内的文件`,
|
||||||
|
icon: 'none'
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const files = this.data.fileMap[e.target.id];
|
||||||
|
files.error = null;
|
||||||
|
files.list = files.list.concat(e.detail.file);
|
||||||
|
this.updateData(`fileMap.${e.target.id}`, files);
|
||||||
|
},
|
||||||
|
//删除文件
|
||||||
|
onFileDelete(e) {
|
||||||
|
console.log(e);
|
||||||
|
const files = this.data.fileMap[e.target.id].list;
|
||||||
|
files.splice(e.detail.index, 1);
|
||||||
|
this.updateData(`fileMap.${e.target.id}.list`, files);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
@ -0,0 +1,8 @@
|
||||||
|
{
|
||||||
|
"component": true,
|
||||||
|
"usingComponents": {
|
||||||
|
"van-icon": "./vant/icon/index",
|
||||||
|
"van-uploader": "./vant/uploader/index",
|
||||||
|
"time-picker": "./components/timePicker/timePicker"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,72 @@
|
||||||
|
<!--components/dynamicForm/index.wxml-->
|
||||||
|
|
||||||
|
<view class="form-box">
|
||||||
|
<block wx:for="{{formData}}" wx:key="id">
|
||||||
|
<!-- input输入框 -->
|
||||||
|
<view class="form-row ipt-row " wx:if="{{item.type==='input'}}">
|
||||||
|
<view class="form-lable {{item.isRequired?'required':'' +''}}">{{item.lable}}</view>
|
||||||
|
<view style="width:100%">
|
||||||
|
<input wx:if="{{!item.disabled}}" class="field {{item.disabled?'disabled':''}}"
|
||||||
|
type="{{inputMap[item.id].original.inputType || 'text'}}" maxlength="{{item.maxLength || -1}}"
|
||||||
|
bindinput="onInput" id="{{item.id}}" value="{{item.defaultValue || ''}}"
|
||||||
|
disabled="{{item.disabled}}" placeholder="{{inputMap[item.id].placeholder || '请填写内容'}}" />
|
||||||
|
<view class="field disabled" wx:else>{{item.defaultValue || ''}}</view>
|
||||||
|
<view class="error-info" wx:if="{{inputMap[item.id].error}}">{{inputMap[item.id].error}}</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<!-- picker选择器 -->
|
||||||
|
<view class="form-row flex-start" wx:elif="{{item.type==='picker'}}">
|
||||||
|
<view class="form-lable {{item.isRequired?'required':''}}">{{item.lable}}</view>
|
||||||
|
<view style="width:100%">
|
||||||
|
<view wx:if="{{!item.disabled}}" class="picker-row {{item.disabled?'disabled':''}}">
|
||||||
|
<picker class="field" range="{{item.range}}" disabled="{{item.disabled}}" id="{{item.id}}" value="{{pickerMap[item.id].idx}}"
|
||||||
|
range-key="name" bindchange="onPickerChange">
|
||||||
|
{{pickerMap[item.id].hasChoose?item.range[pickerMap[item.id].idx].name:'请选择'}}
|
||||||
|
</picker>
|
||||||
|
<van-icon class="row-icon" name="arrow"></van-icon>
|
||||||
|
</view>
|
||||||
|
<view class="field disabled" wx:else>{{pickerMap[item.id].hasChoose?item.range[pickerMap[item.id].idx].name:''}}</view>
|
||||||
|
<view class="error-info" wx:if="{{pickerMap[item.id].error}}">{{pickerMap[item.id].error}}</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<!-- 日期选择器 -->
|
||||||
|
<view class="form-row flex-start " wx:elif="{{item.type==='date'}}">
|
||||||
|
<view class="form-lable {{item.isRequired?'required':''}}">{{item.lable}}</view>
|
||||||
|
<view style="width:100%">
|
||||||
|
<view class="picker-row">
|
||||||
|
<view class="field {{item.disabled?'disabled':''}}" bindtap="datePickerShow" data-disabled="{{item.disabled}}" data-id="{{item.id}}">{{dateMap[item.id].hasChoose?(dateMap[item.id].config.endDate?dateMap[item.id].startDate+' ~ ' + dateMap[item.id].endDate: dateMap[item.id].startDate):'请选择'}}</view>
|
||||||
|
<time-picker pickerShow="{{dateMap[item.id].show}}" id="{{item.id}}" wx:if="{{!isPickerRender}}" bind:hidePicker="datePickerHide"
|
||||||
|
bind:setPickerTime="setPickerTime" config="{{dateMap[item.id].original.config}}"></time-picker>
|
||||||
|
<van-icon class="row-icon" name="arrow"></van-icon>
|
||||||
|
</view>
|
||||||
|
<view class="error-info" wx:if="{{dateMap[item.id].error}}">{{dateMap[item.id].error}}</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<!-- 文本框 -->
|
||||||
|
<view class="textarea-box" wx:elif="{{item.type==='textarea'}}">
|
||||||
|
<view class="flex mb-24">
|
||||||
|
<view class="area-lable {{item.isRequired?'required':''}}">{{item.lable}}</view>
|
||||||
|
<view class="error-info" wx:if="{{inputMap[item.id].error}}">{{inputMap[item.id].error}}</view>
|
||||||
|
</view>
|
||||||
|
<view class="text-area {{item.disabled?'disabled':''}}">
|
||||||
|
<textarea style="width:100%" value="{{item.defaultValue || ''}}" disabled="{{item.disabled}}" placeholder="{{inputMap[item.id].placeholder || '请填写内容'}}"
|
||||||
|
id="{{item.id}}" bindinput="onInput" auto-height="{{true}}" maxlength="{{item.maxLength || -1}}" name=""
|
||||||
|
cols="30" rows="10"></textarea>
|
||||||
|
<view wx:if="{{item.maxLength}}" class="text-num">{{inputMap[item.id].value.length||0}}/{{item.maxLength}}
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<!-- 文件上传 -->
|
||||||
|
<view class="img-box" wx:elif="{{item.type==='file'}}">
|
||||||
|
<!-- <view class="area-lable mb-24 {{item.isRequired?'required':''}}">{{item.lable}}</view> -->
|
||||||
|
<view class="flex mb-24">
|
||||||
|
<view class="area-lable {{item.isRequired?'required':''}}">{{item.lable}}</view>
|
||||||
|
<view class="error-info" wx:if="{{fileMap[item.id].error}}">{{fileMap[item.id].error}}</view>
|
||||||
|
</view>
|
||||||
|
<van-uploader file-list="{{ fileMap[item.id].list }}" preview-size="196rpx" max-count="{{fileMap[item.id].original.maxCount || 9}}"
|
||||||
|
disabled="{{fileMap[item.id].original.disabled || false}}" accept="{{fileMap[item.id].original.accept || 'image'}}" id="{{item.id}}" multiple image-fit="aspectFill"
|
||||||
|
bind:after-read="onFileRead" bind:delete="onFileDelete" />
|
||||||
|
</view>
|
||||||
|
</block>
|
||||||
|
</view>
|
||||||
|
<button wx:if="{{showSubmitBtn}}" class='form-btn' bindtap="formSubmit">提交</button>
|
||||||
|
|
@ -0,0 +1,119 @@
|
||||||
|
/* components/dynamicForm/index.wxss */
|
||||||
|
.page{
|
||||||
|
background-color: #eeeeef;
|
||||||
|
padding-top: 1px;
|
||||||
|
padding-bottom: 1px;
|
||||||
|
}
|
||||||
|
.flex{
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
.form-box{
|
||||||
|
padding: 0 30rpx 0px;
|
||||||
|
padding-right: 0;
|
||||||
|
margin: 30rpx;
|
||||||
|
box-sizing: border-box;
|
||||||
|
border-top: 1px solid #eee;
|
||||||
|
border-radius: 10rpx;
|
||||||
|
background-color: #fff;
|
||||||
|
}
|
||||||
|
.form-row{
|
||||||
|
position: relative;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
padding: 25rpx 0;
|
||||||
|
font-size: 30rpx;
|
||||||
|
border-bottom: 1px solid #eee;
|
||||||
|
}
|
||||||
|
.ipt-row{
|
||||||
|
align-items: flex-start;
|
||||||
|
}
|
||||||
|
.flex-start{
|
||||||
|
align-items: flex-start;
|
||||||
|
}
|
||||||
|
.picker-row{
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
.form-row:last-child{
|
||||||
|
border-bottom: none;
|
||||||
|
}
|
||||||
|
.form-lable{
|
||||||
|
position: relative;
|
||||||
|
min-width: 120rpx;
|
||||||
|
max-width: 200rpx;
|
||||||
|
word-break: break-all;
|
||||||
|
padding-right: 30rpx;
|
||||||
|
flex-shrink: 0;
|
||||||
|
flex-grow: 0;
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
.field{
|
||||||
|
width: 100%;
|
||||||
|
flex-grow: 1;
|
||||||
|
min-height: 45rpx;
|
||||||
|
padding-right: 30rpx;
|
||||||
|
box-sizing: border-box;
|
||||||
|
line-height: 45rpx;
|
||||||
|
}
|
||||||
|
.error-info{
|
||||||
|
font-size: 24rpx;
|
||||||
|
color: #f00;
|
||||||
|
}
|
||||||
|
.required::before{
|
||||||
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
|
left: -18rpx;
|
||||||
|
transform: translateY(-35%);
|
||||||
|
content: '*';
|
||||||
|
color: #f00;
|
||||||
|
font-size: 36rpx;
|
||||||
|
}
|
||||||
|
.form-btn{
|
||||||
|
margin: 60rpx auto;
|
||||||
|
width: 400rpx;
|
||||||
|
background-color: #17e;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
.row-icon{
|
||||||
|
padding-right: 20rpx;
|
||||||
|
}
|
||||||
|
.img-box{
|
||||||
|
padding-top: 25rpx;
|
||||||
|
/* padding-bottom: 25rpx; */
|
||||||
|
}
|
||||||
|
.mb-24{
|
||||||
|
margin-bottom: 24rpx;
|
||||||
|
}
|
||||||
|
.area-lable{
|
||||||
|
position: relative;
|
||||||
|
font-size: 30rpx;
|
||||||
|
margin-right: 20rpx;
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
.textarea-box{
|
||||||
|
padding-top: 20rpx;
|
||||||
|
}
|
||||||
|
.text-area{
|
||||||
|
position: relative;
|
||||||
|
width: 630rpx;
|
||||||
|
padding: 20rpx;
|
||||||
|
padding-bottom: 60rpx;
|
||||||
|
font-size: 30rpx;
|
||||||
|
min-height: 200rpx;
|
||||||
|
box-sizing: border-box;
|
||||||
|
border-radius: 8rpx;
|
||||||
|
border: 1px solid #eee;
|
||||||
|
}
|
||||||
|
.text-num{
|
||||||
|
position: absolute;
|
||||||
|
right: 20rpx;
|
||||||
|
bottom: 10px;
|
||||||
|
text-align: right;
|
||||||
|
color: #999;
|
||||||
|
}
|
||||||
|
|
||||||
|
.disabled{
|
||||||
|
opacity: 0.3;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,29 @@
|
||||||
|
const formatTime = date => {
|
||||||
|
if (!date) {
|
||||||
|
date = new Date();
|
||||||
|
}
|
||||||
|
if(typeof date === 'string'){
|
||||||
|
date = new Date(date);
|
||||||
|
if(!date){
|
||||||
|
date = new Date(date.replace(/-/g, '/'));//兼容IOS new Date()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(typeof date === 'number'){
|
||||||
|
date = new Date(date);
|
||||||
|
}
|
||||||
|
const year = date.getFullYear();
|
||||||
|
const month = date.getMonth() + 1;
|
||||||
|
const day = date.getDate();
|
||||||
|
const hour = date.getHours();
|
||||||
|
const minute = date.getMinutes();
|
||||||
|
const second = date.getSeconds();
|
||||||
|
|
||||||
|
return [year, month, day].map(formatNumber).join('-') + ' ' + [hour, minute, second].map(formatNumber).join(':');
|
||||||
|
};
|
||||||
|
|
||||||
|
const formatNumber = n => {
|
||||||
|
n = n.toString();
|
||||||
|
return n[1] ? n : '0' + n;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default formatTime;
|
||||||
|
|
@ -0,0 +1,7 @@
|
||||||
|
export declare const RED = "#ee0a24";
|
||||||
|
export declare const BLUE = "#1989fa";
|
||||||
|
export declare const WHITE = "#fff";
|
||||||
|
export declare const GREEN = "#07c160";
|
||||||
|
export declare const ORANGE = "#ff976a";
|
||||||
|
export declare const GRAY = "#323233";
|
||||||
|
export declare const GRAY_DARK = "#969799";
|
||||||
|
|
@ -0,0 +1,7 @@
|
||||||
|
export const RED = '#ee0a24';
|
||||||
|
export const BLUE = '#1989fa';
|
||||||
|
export const WHITE = '#fff';
|
||||||
|
export const GREEN = '#07c160';
|
||||||
|
export const ORANGE = '#ff976a';
|
||||||
|
export const GRAY = '#323233';
|
||||||
|
export const GRAY_DARK = '#969799';
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
import { VantComponentOptions, CombinedComponentInstance } from '../definitions/index';
|
||||||
|
declare function VantComponent<Data, Props, Methods>(vantOptions?: VantComponentOptions<Data, Props, Methods, CombinedComponentInstance<Data, Props, Methods>>): void;
|
||||||
|
export { VantComponent };
|
||||||
|
|
@ -0,0 +1,48 @@
|
||||||
|
import { basic } from '../mixins/basic';
|
||||||
|
import { observe } from '../mixins/observer/index';
|
||||||
|
function mapKeys(source, target, map) {
|
||||||
|
Object.keys(map).forEach(key => {
|
||||||
|
if (source[key]) {
|
||||||
|
target[map[key]] = source[key];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
function VantComponent(vantOptions = {}) {
|
||||||
|
const options = {};
|
||||||
|
mapKeys(vantOptions, options, {
|
||||||
|
data: 'data',
|
||||||
|
props: 'properties',
|
||||||
|
mixins: 'behaviors',
|
||||||
|
methods: 'methods',
|
||||||
|
beforeCreate: 'created',
|
||||||
|
created: 'attached',
|
||||||
|
mounted: 'ready',
|
||||||
|
relations: 'relations',
|
||||||
|
destroyed: 'detached',
|
||||||
|
classes: 'externalClasses'
|
||||||
|
});
|
||||||
|
const { relation } = vantOptions;
|
||||||
|
if (relation) {
|
||||||
|
options.relations = Object.assign(options.relations || {}, {
|
||||||
|
[`../${relation.name}/index`]: relation
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// add default externalClasses
|
||||||
|
options.externalClasses = options.externalClasses || [];
|
||||||
|
options.externalClasses.push('custom-class');
|
||||||
|
// add default behaviors
|
||||||
|
options.behaviors = options.behaviors || [];
|
||||||
|
options.behaviors.push(basic);
|
||||||
|
// map field to form-field behavior
|
||||||
|
if (vantOptions.field) {
|
||||||
|
options.behaviors.push('wx://form-field');
|
||||||
|
}
|
||||||
|
// add default options
|
||||||
|
options.options = {
|
||||||
|
multipleSlots: true,
|
||||||
|
addGlobalClass: true
|
||||||
|
};
|
||||||
|
observe(vantOptions, options);
|
||||||
|
Component(options);
|
||||||
|
}
|
||||||
|
export { VantComponent };
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
.van-ellipsis{overflow:hidden;white-space:nowrap;text-overflow:ellipsis}.van-multi-ellipsis--l2{-webkit-line-clamp:2}.van-multi-ellipsis--l2,.van-multi-ellipsis--l3{display:-webkit-box;overflow:hidden;text-overflow:ellipsis;-webkit-box-orient:vertical}.van-multi-ellipsis--l3{-webkit-line-clamp:3}.van-clearfix:after{display:table;clear:both;content:""}.van-hairline,.van-hairline--bottom,.van-hairline--left,.van-hairline--right,.van-hairline--surround,.van-hairline--top,.van-hairline--top-bottom{position:relative}.van-hairline--bottom:after,.van-hairline--left:after,.van-hairline--right:after,.van-hairline--surround:after,.van-hairline--top-bottom:after,.van-hairline--top:after,.van-hairline:after{position:absolute;box-sizing:border-box;-webkit-transform-origin:center;transform-origin:center;content:" ";pointer-events:none;top:-50%;right:-50%;bottom:-50%;left:-50%;border:0 solid #eee;-webkit-transform:scale(.5);transform:scale(.5)}.van-hairline--top:after{border-top-width:1px}.van-hairline--left:after{border-left-width:1px}.van-hairline--right:after{border-right-width:1px}.van-hairline--bottom:after{border-bottom-width:1px}.van-hairline--top-bottom:after{border-width:1px 0}.van-hairline--surround:after{border-width:1px}
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
.van-clearfix:after{display:table;clear:both;content:""}
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
.van-ellipsis{overflow:hidden;white-space:nowrap;text-overflow:ellipsis}.van-multi-ellipsis--l2{-webkit-line-clamp:2}.van-multi-ellipsis--l2,.van-multi-ellipsis--l3{display:-webkit-box;overflow:hidden;text-overflow:ellipsis;-webkit-box-orient:vertical}.van-multi-ellipsis--l3{-webkit-line-clamp:3}
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
.van-hairline,.van-hairline--bottom,.van-hairline--left,.van-hairline--right,.van-hairline--surround,.van-hairline--top,.van-hairline--top-bottom{position:relative}.van-hairline--bottom:after,.van-hairline--left:after,.van-hairline--right:after,.van-hairline--surround:after,.van-hairline--top-bottom:after,.van-hairline--top:after,.van-hairline:after{position:absolute;box-sizing:border-box;-webkit-transform-origin:center;transform-origin:center;content:" ";pointer-events:none;top:-50%;right:-50%;bottom:-50%;left:-50%;border:0 solid #eee;-webkit-transform:scale(.5);transform:scale(.5)}.van-hairline--top:after{border-top-width:1px}.van-hairline--left:after{border-left-width:1px}.van-hairline--right:after{border-right-width:1px}.van-hairline--bottom:after{border-bottom-width:1px}.van-hairline--top-bottom:after{border-width:1px 0}.van-hairline--surround:after{border-width:1px}
|
||||||
|
|
@ -0,0 +1,8 @@
|
||||||
|
/// <reference types="miniprogram-api-typings" />
|
||||||
|
export declare function isDef(value: any): boolean;
|
||||||
|
export declare function isObj(x: any): boolean;
|
||||||
|
export declare function isNumber(value: any): boolean;
|
||||||
|
export declare function range(num: number, min: number, max: number): number;
|
||||||
|
export declare function nextTick(fn: Function): void;
|
||||||
|
export declare function getSystemInfoSync(): WechatMiniprogram.GetSystemInfoSuccessCallbackResult;
|
||||||
|
export declare function addUnit(value?: string | number): string | undefined;
|
||||||
|
|
@ -0,0 +1,32 @@
|
||||||
|
export function isDef(value) {
|
||||||
|
return value !== undefined && value !== null;
|
||||||
|
}
|
||||||
|
export function isObj(x) {
|
||||||
|
const type = typeof x;
|
||||||
|
return x !== null && (type === 'object' || type === 'function');
|
||||||
|
}
|
||||||
|
export function isNumber(value) {
|
||||||
|
return /^\d+(\.\d+)?$/.test(value);
|
||||||
|
}
|
||||||
|
export function range(num, min, max) {
|
||||||
|
return Math.min(Math.max(num, min), max);
|
||||||
|
}
|
||||||
|
export function nextTick(fn) {
|
||||||
|
setTimeout(() => {
|
||||||
|
fn();
|
||||||
|
}, 1000 / 30);
|
||||||
|
}
|
||||||
|
let systemInfo = null;
|
||||||
|
export function getSystemInfoSync() {
|
||||||
|
if (systemInfo == null) {
|
||||||
|
systemInfo = wx.getSystemInfoSync();
|
||||||
|
}
|
||||||
|
return systemInfo;
|
||||||
|
}
|
||||||
|
export function addUnit(value) {
|
||||||
|
if (!isDef(value)) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
value = String(value);
|
||||||
|
return isNumber(value) ? `${value}px` : value;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
export {};
|
||||||
|
|
@ -0,0 +1,27 @@
|
||||||
|
import { VantComponent } from '../common/component';
|
||||||
|
VantComponent({
|
||||||
|
props: {
|
||||||
|
dot: Boolean,
|
||||||
|
info: null,
|
||||||
|
size: null,
|
||||||
|
color: String,
|
||||||
|
customStyle: String,
|
||||||
|
classPrefix: {
|
||||||
|
type: String,
|
||||||
|
value: 'van-icon'
|
||||||
|
},
|
||||||
|
name: {
|
||||||
|
type: String,
|
||||||
|
observer(val) {
|
||||||
|
this.setData({
|
||||||
|
isImageName: val.indexOf('/') !== -1
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
onClick() {
|
||||||
|
this.$emit('click');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
{
|
||||||
|
"component": true,
|
||||||
|
"usingComponents": {
|
||||||
|
"van-info": "../info/index"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,20 @@
|
||||||
|
<!-- <wxs src="../wxs/utils.wxs" module="utils" /> -->
|
||||||
|
|
||||||
|
<view
|
||||||
|
class="custom-class {{ classPrefix }} {{ isImageName ? 'van-icon--image' : classPrefix + '-' + name }}"
|
||||||
|
style="color: {{ color }};font-size: {{ size }}rpx;{{ customStyle }}"
|
||||||
|
bind:tap="onClick"
|
||||||
|
>
|
||||||
|
<!-- <van-info
|
||||||
|
wx:if="{{ info !== null || dot }}"
|
||||||
|
dot="{{ dot }}"
|
||||||
|
info="{{ info }}"
|
||||||
|
custom-class="van-icon__info"
|
||||||
|
/> -->
|
||||||
|
<image
|
||||||
|
wx:if="{{ isImageName }}"
|
||||||
|
src="{{ name }}"
|
||||||
|
mode="aspectFit"
|
||||||
|
class="van-icon__image"
|
||||||
|
/>
|
||||||
|
</view>
|
||||||
File diff suppressed because one or more lines are too long
|
|
@ -0,0 +1 @@
|
||||||
|
export {};
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
import { VantComponent } from '../common/component';
|
||||||
|
|
||||||
|
VantComponent({
|
||||||
|
props: {
|
||||||
|
dot: Boolean,
|
||||||
|
info: null,
|
||||||
|
customStyle: String
|
||||||
|
},
|
||||||
|
data: {
|
||||||
|
// classBem: utils.bem('info', { dot })
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
{
|
||||||
|
"component": true
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,8 @@
|
||||||
|
<!-- <wxs src="../wxs/utils.wxs" module="utils" /> -->
|
||||||
|
|
||||||
|
<view
|
||||||
|
wx:if="{{ info !== null && info !== '' || dot }}"
|
||||||
|
class="custom-class van-info "
|
||||||
|
style="{{ customStyle }}"
|
||||||
|
>{{ dot ? '' : info }}</view>
|
||||||
|
<!-- <view>{{ utils.bem('info', { dot }) }}</view> -->
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
@import '../common/index.wxss';.van-info{position:absolute;top:0;right:0;box-sizing:border-box;white-space:nowrap;text-align:center;-webkit-transform:translate(50%,-50%);transform:translate(50%,-50%);-webkit-transform-origin:100%;transform-origin:100%;min-width:16px;min-width:var(--info-size,16px);padding:0 3px;padding:var(--info-padding,0 3px);color:#fff;color:var(--info-color,#fff);font-weight:500;font-weight:var(--info-font-weight,500);font-size:12px;font-size:var(--info-font-size,12px);font-family:PingFang SC,Helvetica Neue,Arial,sans-serif;font-family:var(--info-font-family,PingFang SC,Helvetica Neue,Arial,sans-serif);line-height:14px;line-height:calc(var(--info-size, 16px) - var(--info-border-width, 1px)*2);background-color:#ee0a24;background-color:var(--info-background-color,#ee0a24);border:1px solid #fff;border:var(--info-border-width,1px) solid var(--white,#fff);border-radius:16px;border-radius:var(--info-size,16px)}.van-info--dot{min-width:0;border-radius:100%;width:8px;width:var(--info-dot-size,8px);height:8px;height:var(--info-dot-size,8px);background-color:#ee0a24;background-color:var(--info-dot-color,#ee0a24)}
|
||||||
|
|
@ -0,0 +1,22 @@
|
||||||
|
export var basic = Behavior({
|
||||||
|
methods: {
|
||||||
|
$emit: function $emit() {
|
||||||
|
this.triggerEvent.apply(this, arguments);
|
||||||
|
},
|
||||||
|
getRect: function getRect(selector, all) {
|
||||||
|
var _this = this;
|
||||||
|
|
||||||
|
return new Promise(function (resolve) {
|
||||||
|
wx.createSelectorQuery().in(_this)[all ? 'selectAll' : 'select'](selector).boundingClientRect(function (rect) {
|
||||||
|
if (all && Array.isArray(rect) && rect.length) {
|
||||||
|
resolve(rect);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!all && rect) {
|
||||||
|
resolve(rect);
|
||||||
|
}
|
||||||
|
}).exec();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
@ -0,0 +1,15 @@
|
||||||
|
export var button = Behavior({
|
||||||
|
properties: {
|
||||||
|
id: String,
|
||||||
|
sessionFrom: String,
|
||||||
|
appParameter: String,
|
||||||
|
sendMessageImg: String,
|
||||||
|
sendMessagePath: String,
|
||||||
|
showMessageCard: String,
|
||||||
|
sendMessageTitle: String,
|
||||||
|
lang: {
|
||||||
|
type: String,
|
||||||
|
value: 'en'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
@ -0,0 +1,39 @@
|
||||||
|
var isIPhoneX = null;
|
||||||
|
|
||||||
|
function getIsIPhoneX() {
|
||||||
|
return new Promise(function (resolve, reject) {
|
||||||
|
if (isIPhoneX !== null) {
|
||||||
|
resolve(isIPhoneX);
|
||||||
|
} else {
|
||||||
|
wx.getSystemInfo({
|
||||||
|
success: function success(_ref) {
|
||||||
|
var model = _ref.model,
|
||||||
|
screenHeight = _ref.screenHeight;
|
||||||
|
var iphoneX = /iphone x/i.test(model);
|
||||||
|
var iphoneNew = /iPhone11/i.test(model) && screenHeight === 812;
|
||||||
|
isIPhoneX = iphoneX || iphoneNew;
|
||||||
|
resolve(isIPhoneX);
|
||||||
|
},
|
||||||
|
fail: reject
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export var iphonex = Behavior({
|
||||||
|
properties: {
|
||||||
|
safeAreaInsetBottom: {
|
||||||
|
type: Boolean,
|
||||||
|
value: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created: function created() {
|
||||||
|
var _this = this;
|
||||||
|
|
||||||
|
getIsIPhoneX().then(function (isIPhoneX) {
|
||||||
|
_this.set({
|
||||||
|
isIPhoneX: isIPhoneX
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
@ -0,0 +1,24 @@
|
||||||
|
export var link = Behavior({
|
||||||
|
properties: {
|
||||||
|
url: String,
|
||||||
|
linkType: {
|
||||||
|
type: String,
|
||||||
|
value: 'navigateTo'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
jumpLink: function jumpLink(urlKey) {
|
||||||
|
if (urlKey === void 0) {
|
||||||
|
urlKey = 'url';
|
||||||
|
}
|
||||||
|
|
||||||
|
var url = this.data[urlKey];
|
||||||
|
|
||||||
|
if (url) {
|
||||||
|
wx[this.data.linkType]({
|
||||||
|
url: url
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
@ -0,0 +1,43 @@
|
||||||
|
export var behavior = Behavior({
|
||||||
|
created: function created() {
|
||||||
|
var _this = this;
|
||||||
|
|
||||||
|
if (!this.$options) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var cache = {};
|
||||||
|
|
||||||
|
var _this$$options = this.$options(),
|
||||||
|
computed = _this$$options.computed;
|
||||||
|
|
||||||
|
var keys = Object.keys(computed);
|
||||||
|
|
||||||
|
this.calcComputed = function () {
|
||||||
|
var needUpdate = {};
|
||||||
|
keys.forEach(function (key) {
|
||||||
|
var value = computed[key].call(_this);
|
||||||
|
|
||||||
|
if (cache[key] !== value) {
|
||||||
|
cache[key] = needUpdate[key] = value;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return needUpdate;
|
||||||
|
};
|
||||||
|
},
|
||||||
|
attached: function attached() {
|
||||||
|
this.set();
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
// set data and set computed data
|
||||||
|
set: function set(data, callback) {
|
||||||
|
if (data) {
|
||||||
|
this.setData(data, callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.calcComputed) {
|
||||||
|
this.setData(this.calcComputed());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
@ -0,0 +1,38 @@
|
||||||
|
import { behavior } from './behavior';
|
||||||
|
import { observeProps } from './props';
|
||||||
|
export function observe(vantOptions, options) {
|
||||||
|
var watch = vantOptions.watch,
|
||||||
|
computed = vantOptions.computed;
|
||||||
|
options.behaviors.push(behavior);
|
||||||
|
|
||||||
|
if (watch) {
|
||||||
|
var props = options.properties || {};
|
||||||
|
Object.keys(watch).forEach(function (key) {
|
||||||
|
if (key in props) {
|
||||||
|
var prop = props[key];
|
||||||
|
|
||||||
|
if (prop === null || !('type' in prop)) {
|
||||||
|
prop = {
|
||||||
|
type: prop
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
prop.observer = watch[key];
|
||||||
|
props[key] = prop;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
options.properties = props;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (computed) {
|
||||||
|
options.methods = options.methods || {};
|
||||||
|
|
||||||
|
options.methods.$options = function () {
|
||||||
|
return vantOptions;
|
||||||
|
};
|
||||||
|
|
||||||
|
if (options.properties) {
|
||||||
|
observeProps(options.properties);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,32 @@
|
||||||
|
export function observeProps(props) {
|
||||||
|
if (!props) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Object.keys(props).forEach(function (key) {
|
||||||
|
var prop = props[key];
|
||||||
|
|
||||||
|
if (prop === null || !('type' in prop)) {
|
||||||
|
prop = {
|
||||||
|
type: prop
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
var _prop = prop,
|
||||||
|
observer = _prop.observer;
|
||||||
|
|
||||||
|
prop.observer = function () {
|
||||||
|
if (observer) {
|
||||||
|
if (typeof observer === 'string') {
|
||||||
|
observer = this[observer];
|
||||||
|
}
|
||||||
|
|
||||||
|
observer.apply(this, arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.set();
|
||||||
|
};
|
||||||
|
|
||||||
|
props[key] = prop;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,22 @@
|
||||||
|
export var openType = Behavior({
|
||||||
|
properties: {
|
||||||
|
openType: String
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
bindGetUserInfo: function bindGetUserInfo(event) {
|
||||||
|
this.$emit('getuserinfo', event.detail);
|
||||||
|
},
|
||||||
|
bindContact: function bindContact(event) {
|
||||||
|
this.$emit('contact', event.detail);
|
||||||
|
},
|
||||||
|
bindGetPhoneNumber: function bindGetPhoneNumber(event) {
|
||||||
|
this.$emit('getphonenumber', event.detail);
|
||||||
|
},
|
||||||
|
bindOpenSetting: function bindOpenSetting(event) {
|
||||||
|
this.$emit('opensetting', event.detail);
|
||||||
|
},
|
||||||
|
bindError: function bindError(event) {
|
||||||
|
this.$emit('error', event.detail);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
@ -0,0 +1,21 @@
|
||||||
|
export var touch = Behavior({
|
||||||
|
methods: {
|
||||||
|
touchStart: function touchStart(event) {
|
||||||
|
this.direction = '';
|
||||||
|
this.deltaX = 0;
|
||||||
|
this.deltaY = 0;
|
||||||
|
this.offsetX = 0;
|
||||||
|
this.offsetY = 0;
|
||||||
|
this.startX = event.touches[0].clientX;
|
||||||
|
this.startY = event.touches[0].clientY;
|
||||||
|
},
|
||||||
|
touchMove: function touchMove(event) {
|
||||||
|
var touch = event.touches[0];
|
||||||
|
this.deltaX = touch.clientX - this.startX;
|
||||||
|
this.deltaY = touch.clientY - this.startY;
|
||||||
|
this.offsetX = Math.abs(this.deltaX);
|
||||||
|
this.offsetY = Math.abs(this.deltaY);
|
||||||
|
this.direction = this.offsetX > this.offsetY ? 'horizontal' : this.offsetX < this.offsetY ? 'vertical' : '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
@ -0,0 +1,73 @@
|
||||||
|
export var transition = function transition(showDefaultValue) {
|
||||||
|
return Behavior({
|
||||||
|
properties: {
|
||||||
|
customStyle: String,
|
||||||
|
show: {
|
||||||
|
type: Boolean,
|
||||||
|
value: showDefaultValue,
|
||||||
|
observer: 'observeShow'
|
||||||
|
},
|
||||||
|
duration: {
|
||||||
|
type: Number,
|
||||||
|
value: 300
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data: {
|
||||||
|
type: '',
|
||||||
|
inited: false,
|
||||||
|
display: false,
|
||||||
|
supportAnimation: true
|
||||||
|
},
|
||||||
|
attached: function attached() {
|
||||||
|
if (this.data.show) {
|
||||||
|
this.show();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.detectSupport();
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
detectSupport: function detectSupport() {
|
||||||
|
var _this = this;
|
||||||
|
|
||||||
|
wx.getSystemInfo({
|
||||||
|
success: function success(info) {
|
||||||
|
if (info && info.system && info.system.indexOf('iOS 8') === 0) {
|
||||||
|
_this.set({
|
||||||
|
supportAnimation: false
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
observeShow: function observeShow(value) {
|
||||||
|
if (value) {
|
||||||
|
this.show();
|
||||||
|
} else {
|
||||||
|
if (this.data.supportAnimation) {
|
||||||
|
this.set({
|
||||||
|
type: 'leave'
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
this.set({
|
||||||
|
display: false
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
show: function show() {
|
||||||
|
this.set({
|
||||||
|
inited: true,
|
||||||
|
display: true,
|
||||||
|
type: 'enter'
|
||||||
|
});
|
||||||
|
},
|
||||||
|
onAnimationEnd: function onAnimationEnd() {
|
||||||
|
if (!this.data.show) {
|
||||||
|
this.set({
|
||||||
|
display: false
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
export {};
|
||||||
|
|
@ -0,0 +1,180 @@
|
||||||
|
import { VantComponent } from '../common/component';
|
||||||
|
import { isImageFile } from './utils';
|
||||||
|
|
||||||
|
VantComponent({
|
||||||
|
props: {
|
||||||
|
disabled: Boolean,
|
||||||
|
multiple: Boolean,
|
||||||
|
uploadText: String,
|
||||||
|
useBeforeRead: Boolean,
|
||||||
|
previewSize: {
|
||||||
|
type: null,
|
||||||
|
value: 90
|
||||||
|
},
|
||||||
|
name: {
|
||||||
|
type: [Number, String],
|
||||||
|
value: ''
|
||||||
|
},
|
||||||
|
accept: {
|
||||||
|
type: String,
|
||||||
|
value: 'image'
|
||||||
|
},
|
||||||
|
sizeType: {
|
||||||
|
type: Array,
|
||||||
|
value: ['original', 'compressed']
|
||||||
|
},
|
||||||
|
capture: {
|
||||||
|
type: Array,
|
||||||
|
value: ['album', 'camera']
|
||||||
|
},
|
||||||
|
fileList: {
|
||||||
|
type: Array,
|
||||||
|
value: [],
|
||||||
|
observer: 'formatFileList'
|
||||||
|
},
|
||||||
|
maxSize: {
|
||||||
|
type: Number,
|
||||||
|
value: Number.MAX_VALUE
|
||||||
|
},
|
||||||
|
maxCount: {
|
||||||
|
type: Number,
|
||||||
|
value: 100
|
||||||
|
},
|
||||||
|
deletable: {
|
||||||
|
type: Boolean,
|
||||||
|
value: true
|
||||||
|
},
|
||||||
|
previewImage: {
|
||||||
|
type: Boolean,
|
||||||
|
value: true
|
||||||
|
},
|
||||||
|
previewFullImage: {
|
||||||
|
type: Boolean,
|
||||||
|
value: true
|
||||||
|
},
|
||||||
|
imageFit: {
|
||||||
|
type: String,
|
||||||
|
value: 'scaleToFill'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data: {
|
||||||
|
lists: [],
|
||||||
|
computedPreviewSize: '',
|
||||||
|
isInCount: true
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
formatFileList() {
|
||||||
|
const { fileList = [], maxCount } = this.data;
|
||||||
|
const lists = fileList.map(item => (Object.assign(Object.assign({}, item), { isImage: typeof item.isImage === 'undefined' ? isImageFile(item) : item.isImage })));
|
||||||
|
this.setData({ lists, isInCount: lists.length < maxCount });
|
||||||
|
},
|
||||||
|
startUpload() {
|
||||||
|
if (this.data.disabled)
|
||||||
|
return;
|
||||||
|
const { name = '', capture, maxCount, multiple, maxSize, accept, sizeType,videoCfg={}, lists, useBeforeRead = false // 是否定义了 beforeRead
|
||||||
|
} = this.data;
|
||||||
|
let chooseFile = null;
|
||||||
|
const newMaxCount = maxCount - lists.length;
|
||||||
|
// 设置为只选择图片的时候使用 chooseImage 来实现
|
||||||
|
if (accept === 'image') {
|
||||||
|
chooseFile = new Promise((resolve, reject) => {
|
||||||
|
wx.chooseImage({
|
||||||
|
count: multiple ? (newMaxCount > 9 ? 9 : newMaxCount) : 1,
|
||||||
|
sourceType: capture,
|
||||||
|
sizeType,
|
||||||
|
success: resolve,
|
||||||
|
fail: reject
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else if (accept === 'video'){
|
||||||
|
chooseFile = new Promise((resolve, reject) => {
|
||||||
|
wx.chooseMedia({
|
||||||
|
count: videoCfg.count || 9,
|
||||||
|
mediaType: ['video'],
|
||||||
|
sourceType: videoCfg.sourceType || ['album', 'camera'],
|
||||||
|
maxDuration: videoCfg.maxDuration || 10,
|
||||||
|
camera: videoCfg.camera || 'back',
|
||||||
|
success: (res)=>{
|
||||||
|
res.isVideo = true;
|
||||||
|
resolve(res);
|
||||||
|
},
|
||||||
|
fail: reject
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
chooseFile = new Promise((resolve, reject) => {
|
||||||
|
wx.chooseMessageFile({
|
||||||
|
count: multiple ? newMaxCount : 1,
|
||||||
|
type: 'file',
|
||||||
|
success: resolve,
|
||||||
|
fail: reject
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
chooseFile
|
||||||
|
.then((res) => {
|
||||||
|
const file = multiple ? res.tempFiles : res.tempFiles[0];
|
||||||
|
// 检查文件大小
|
||||||
|
if (file instanceof Array) {
|
||||||
|
const sizeEnable = file.every(item => item.size <= maxSize);
|
||||||
|
if (!sizeEnable) {
|
||||||
|
this.$emit('oversize', { name });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (file.size > maxSize) {
|
||||||
|
this.$emit('oversize', { name });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let upData = { file, name };
|
||||||
|
if(res.isVideo){
|
||||||
|
file.map(val=>{
|
||||||
|
val.isVideo = true;
|
||||||
|
return val;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// 触发上传之前的钩子函数
|
||||||
|
if (useBeforeRead) {
|
||||||
|
this.$emit('before-read', {
|
||||||
|
file,
|
||||||
|
name,
|
||||||
|
callback: (result) => {
|
||||||
|
if (result) {
|
||||||
|
// 开始上传
|
||||||
|
this.$emit('after-read', upData);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this.$emit('after-read', upData);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
this.$emit('error', error);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
deleteItem(event) {
|
||||||
|
const { index } = event.currentTarget.dataset;
|
||||||
|
this.$emit('delete', { index, name: this.data.name });
|
||||||
|
},
|
||||||
|
doPreviewImage(event) {
|
||||||
|
if (!this.data.previewFullImage)
|
||||||
|
return;
|
||||||
|
const curUrl = event.currentTarget.dataset.url;
|
||||||
|
const images = this.data.lists
|
||||||
|
.filter(item => item.isImage)
|
||||||
|
.map(item => item.url || item.path);
|
||||||
|
this.$emit('click-preview', { url: curUrl, name: this.data.name });
|
||||||
|
wx.previewImage({
|
||||||
|
urls: images,
|
||||||
|
current: curUrl,
|
||||||
|
fail() {
|
||||||
|
wx.showToast({ title: '预览图片失败', icon: 'none' });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
{
|
||||||
|
"component": true,
|
||||||
|
"usingComponents": {
|
||||||
|
"van-icon": "../icon/index"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,65 @@
|
||||||
|
<!-- <wxs src="../wxs/utils.wxs" module="utils" /> -->
|
||||||
|
|
||||||
|
<view class="van-uploader">
|
||||||
|
<view class="van-uploader__wrapper">
|
||||||
|
<!-- 预览样式 -->
|
||||||
|
<view
|
||||||
|
wx:if="{{ previewImage }}"
|
||||||
|
wx:for="{{ lists }}"
|
||||||
|
wx:key="index"
|
||||||
|
class="van-uploader__preview"
|
||||||
|
>
|
||||||
|
<image
|
||||||
|
wx:if="{{ item.isImage }}"
|
||||||
|
mode="{{ imageFit }}"
|
||||||
|
src="{{ item.url || item.path }}"
|
||||||
|
alt="{{ item.name || ('图片' + index) }}"
|
||||||
|
class="van-uploader__preview-image"
|
||||||
|
style="width: {{ previewSize }}; height: {{ previewSize }};"
|
||||||
|
data-url="{{ item.url || item.path }}"
|
||||||
|
bind:tap="doPreviewImage"
|
||||||
|
/>
|
||||||
|
<view
|
||||||
|
wx:elif="{{ item.isVideo }}"
|
||||||
|
class="van-uploader__preview"
|
||||||
|
style="width:280rpx; height:280rpx;"
|
||||||
|
class="van-uploader__preview"
|
||||||
|
>
|
||||||
|
<video class="van-uploader__preview-video" data-url="{{ item.url || item.path }}" style="width:280rpx; height:280rpx;" src="{{ item.url || item.tempFilePath }}" controls></video>
|
||||||
|
</view>
|
||||||
|
<view
|
||||||
|
wx:else
|
||||||
|
class="van-uploader__file"
|
||||||
|
style="width: {{ previewSize }}; height: {{ previewSize }};"
|
||||||
|
>
|
||||||
|
<van-icon name="description" class="van-uploader__file-icon" />
|
||||||
|
<view class="van-uploader__file-name van-ellipsis">{{ item.name || item.url || item.path }}</view>
|
||||||
|
</view>
|
||||||
|
<van-icon
|
||||||
|
wx:if="{{ deletable && !disabled }}"
|
||||||
|
name="clear"
|
||||||
|
size='40'
|
||||||
|
class="van-uploader__preview-delete"
|
||||||
|
data-index="{{ index }}"
|
||||||
|
bind:tap="deleteItem"
|
||||||
|
/>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 上传样式 -->
|
||||||
|
<block wx:if="{{ isInCount && !disabled }}">
|
||||||
|
<view class="van-uploader__slot" bind:tap="startUpload">
|
||||||
|
<slot />
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 默认上传样式 -->
|
||||||
|
<view
|
||||||
|
class="van-uploader__upload"
|
||||||
|
style="width: {{ previewSize }}; height: {{ previewSize }};"
|
||||||
|
bind:tap="startUpload"
|
||||||
|
>
|
||||||
|
<van-icon name="plus" size='40' class="van-uploader__upload-icon" />
|
||||||
|
<text wx:if="{{ uploadText }}" class="van-uploader__upload-text">{{ uploadText }}</text>
|
||||||
|
</view>
|
||||||
|
</block>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
@import '../common/index.wxss';.van-uploader{position:relative;display:inline-block}.van-uploader__wrapper{display:-webkit-flex;display:flex;-webkit-flex-wrap:wrap;flex-wrap:wrap}.van-uploader__slot:empty{display:none}.van-uploader__slot:not(:empty)+.van-uploader__upload{display:none!important}.van-uploader__upload{position:relative;display:-webkit-flex;display:flex;-webkit-flex-direction:column;flex-direction:column;-webkit-align-items:center;align-items:center;-webkit-justify-content:center;justify-content:center;box-sizing:border-box;width:80px;height:80px;margin:0 20rpx 20rpx 0;background-color:#fff;border:2px dashed #e0e0f0;border-radius:8px}.van-uploader__upload-icon{display:inline-block;width:48rpx;height:48rpx;color:#969799;font-size:24px}.van-uploader__upload-text{margin-top:8px;color:#969799;font-size:12px}.van-uploader__preview{position:relative;margin:0 20rpx 20rpx 0}.van-uploader__preview-image{display:block;width:80px;height:80px;border-radius:8px}
|
||||||
|
.van-uploader__preview-video{display:block;width:80px;height:80px;border-radius:8px;overflow: hidden}
|
||||||
|
.van-uploader__preview-delete{position:absolute;top:-8px;right:-8px;color:#969799;font-size:18px;background-color:#fff;border-radius:100%}.van-uploader__file{display:-webkit-flex;display:flex;-webkit-flex-direction:column;flex-direction:column;-webkit-align-items:center;align-items:center;-webkit-justify-content:center;justify-content:center;width:80px;height:80px;background-color:#f7f8fa;border-radius:8px}.van-uploader__file-icon{display:inline-block;width:20px;height:20px;color:#646566;font-size:20px}.van-uploader__file-name{box-sizing:border-box;width:100%;margin-top:8px;padding:0 5px;color:#646566;font-size:12px;text-align:center}
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
interface File {
|
||||||
|
path: string;
|
||||||
|
url: string;
|
||||||
|
size: number;
|
||||||
|
name: string;
|
||||||
|
type: string;
|
||||||
|
time: number;
|
||||||
|
image: boolean;
|
||||||
|
}
|
||||||
|
export declare function isImageUrl(url: string): boolean;
|
||||||
|
export declare function isImageFile(item: File): boolean;
|
||||||
|
export {};
|
||||||
|
|
@ -0,0 +1,16 @@
|
||||||
|
const IMAGE_EXT = ['jpeg', 'jpg', 'gif', 'png', 'svg'];
|
||||||
|
export function isImageUrl(url) {
|
||||||
|
return IMAGE_EXT.some(ext => url.indexOf(`.${ext}`) !== -1);
|
||||||
|
}
|
||||||
|
export function isImageFile(item) {
|
||||||
|
if (item.type) {
|
||||||
|
return item.type.indexOf('image') === 0;
|
||||||
|
}
|
||||||
|
if (item.path) {
|
||||||
|
return isImageUrl(item.path);
|
||||||
|
}
|
||||||
|
if (item.url) {
|
||||||
|
return isImageUrl(item.url);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,14 @@
|
||||||
|
/* eslint-disable */
|
||||||
|
var REGEXP = getRegExp('^\d+(\.\d+)?$');
|
||||||
|
|
||||||
|
function addUnit(value) {
|
||||||
|
if (value == null) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
return REGEXP.test('' + value) ? value + 'px' : value;
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
addUnit: addUnit
|
||||||
|
};
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
function isArray(array) {
|
||||||
|
return array && array.constructor === 'Array';
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports.isArray = isArray;
|
||||||
|
|
@ -0,0 +1,38 @@
|
||||||
|
var array = require('./array.wxs');
|
||||||
|
var object = require('./object.wxs');
|
||||||
|
var PREFIX = 'van-';
|
||||||
|
|
||||||
|
function join(name, mods) {
|
||||||
|
name = PREFIX + name;
|
||||||
|
mods = mods.map(function(mod) {
|
||||||
|
return name + '--' + mod;
|
||||||
|
});
|
||||||
|
mods.unshift(name);
|
||||||
|
return mods.join(' ');
|
||||||
|
}
|
||||||
|
|
||||||
|
function traversing(mods, conf) {
|
||||||
|
if (!conf) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof conf === 'string' || typeof conf === 'number') {
|
||||||
|
mods.push(conf);
|
||||||
|
} else if (array.isArray(conf)) {
|
||||||
|
conf.forEach(function(item) {
|
||||||
|
traversing(mods, item);
|
||||||
|
});
|
||||||
|
} else if (typeof conf === 'object') {
|
||||||
|
object.keys(conf).forEach(function(key) {
|
||||||
|
conf[key] && mods.push(key);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function bem(name, conf) {
|
||||||
|
var mods = [];
|
||||||
|
traversing(mods, conf);
|
||||||
|
return join(name, mods);
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports.bem = bem;
|
||||||
|
|
@ -0,0 +1,54 @@
|
||||||
|
/**
|
||||||
|
* Simple memoize
|
||||||
|
* wxs doesn't support fn.apply, so this memoize only support up to 2 args
|
||||||
|
*/
|
||||||
|
|
||||||
|
function isPrimitive(value) {
|
||||||
|
var type = typeof value;
|
||||||
|
return (
|
||||||
|
type === 'boolean' ||
|
||||||
|
type === 'number' ||
|
||||||
|
type === 'string' ||
|
||||||
|
type === 'undefined' ||
|
||||||
|
value === null
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// mock simple fn.call in wxs
|
||||||
|
function call(fn, args) {
|
||||||
|
if (args.length === 2) {
|
||||||
|
return fn(args[0], args[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (args.length === 1) {
|
||||||
|
return fn(args[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return fn();
|
||||||
|
}
|
||||||
|
|
||||||
|
function serializer(args) {
|
||||||
|
if (args.length === 1 && isPrimitive(args[0])) {
|
||||||
|
return args[0];
|
||||||
|
}
|
||||||
|
var obj = {};
|
||||||
|
for (var i = 0; i < args.length; i++) {
|
||||||
|
obj['key' + i] = args[i];
|
||||||
|
}
|
||||||
|
return JSON.stringify(obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
function memoize(fn) {
|
||||||
|
var cache = {};
|
||||||
|
|
||||||
|
return function() {
|
||||||
|
var key = serializer(arguments);
|
||||||
|
if (cache[key] === undefined) {
|
||||||
|
cache[key] = call(fn, arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
return cache[key];
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports.memoize = memoize;
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
/* eslint-disable */
|
||||||
|
var REGEXP = getRegExp('{|}|"', 'g');
|
||||||
|
|
||||||
|
function keys(obj) {
|
||||||
|
return JSON.stringify(obj)
|
||||||
|
.replace(REGEXP, '')
|
||||||
|
.split(',')
|
||||||
|
.map(function(item) {
|
||||||
|
return item.split(':')[0];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports.keys = keys;
|
||||||
|
|
@ -0,0 +1,10 @@
|
||||||
|
/* eslint-disable */
|
||||||
|
var bem = require('./bem.wxs').bem;
|
||||||
|
var memoize = require('./memoize.wxs').memoize;
|
||||||
|
var addUnit = require('./add-unit.wxs').addUnit;
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
bem: memoize(bem),
|
||||||
|
memoize: memoize,
|
||||||
|
addUnit: addUnit
|
||||||
|
};
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
<?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"><svg t="1621915089686" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2807" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M762.78272 154.624h-44.032a96.81408 96.81408 0 0 0-46.92992-51.31776A98.06848 98.06848 0 0 0 578.92352 35.84H445.07648a98.06848 98.06848 0 0 0-92.88192 67.49184A96.81408 96.81408 0 0 0 305.25952 154.624h-44.032C176.47104 154.624 107.52 226.26816 107.52 314.31168v519.30624C107.52 921.6512 176.47104 993.28 261.21728 993.28h501.56544C847.52896 993.28 916.48 921.6512 916.48 833.61792V314.31168c0-88.04352-68.95104-159.68768-153.69728-159.68768z m-372.736 8.86784a34.92864 34.92864 0 0 0 27.21792-31.744 27.96544 27.96544 0 0 1 27.80672-26.0352h133.84704a27.96032 27.96032 0 0 1 27.80672 26.0352 34.93376 34.93376 0 0 0 27.21792 31.744 27.93984 27.93984 0 0 1-6.144 55.1936H396.19072a27.93984 27.93984 0 0 1-6.13888-55.168z m456.59648 670.12608c0 49.50016-37.62176 89.77408-83.86048 89.77408H261.21728c-46.23872 0-83.86048-40.27392-83.86048-89.77408V314.31168c0-49.50528 37.62176-89.7792 83.86048-89.7792h43.32544a97.84832 97.84832 0 0 0 91.648 64.06144h231.62368a97.8432 97.8432 0 0 0 91.648-64.06144h43.33056c46.23872 0 83.86048 40.27392 83.86048 89.7792v519.30624zM739.84 375.65952H279.79264a34.944 34.944 0 0 0 0 69.888H739.84a34.944 34.944 0 0 0 0-69.888z m-460.04736 254.64832h324.74112a34.944 34.944 0 0 0 0-69.88288H279.79264a34.944 34.944 0 0 0 0 69.88288z m383.24736 114.87744H279.79264a34.944 34.944 0 0 0 0 69.88288H663.04a34.944 34.944 0 0 0 0-69.88288z" fill="#595BB3" p-id="2808"></path></svg>
|
||||||
|
After Width: | Height: | Size: 1.7 KiB |
|
|
@ -0,0 +1 @@
|
||||||
|
<?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"><svg t="1621915136519" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4543" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M692.949333 838.101333c30.933333 17.408 61.653333 26.197333 92.117334 26.197334 30.464 0 61.184-8.789333 92.117333-26.197334V960l-83.712-44.202667a15.530667 15.530667 0 0 0-14.250667-0.128l-86.4 44.202667v-121.770667h0.128zM810.666667 106.666667a42.666667 42.666667 0 0 1 42.666666 42.666666v298.666667h-128a170.666667 170.666667 0 0 0-170.453333 162.133333l-0.213333 8.533334v298.666666H213.333333a42.666667 42.666667 0 0 1-42.666666-42.666666v-725.333334a42.666667 42.666667 0 0 1 42.666666-42.666666h597.333334z m-25.6 426.666666c84.906667 0 153.6 68.138667 153.6 152.405334 0 84.224-68.693333 152.362667-153.6 152.362666s-153.6-68.138667-153.6-152.362666c0-84.266667 68.693333-152.405333 153.6-152.405334z m0 60.885334l-32.554667 47.018666-55.04 16.213334 35.114667 45.226666-1.536 57.002667 54.016-19.029333 54.186666 19.029333-1.536-57.002667 35.114667-45.226666-55.210667-16.213334-32.554666-47.018666zM490.666667 405.333333h-170.666667a21.333333 21.333333 0 0 0-20.992 17.493334L298.666667 426.666667v21.333333a21.333333 21.333333 0 0 0 17.493333 20.992L320 469.333333h170.666667a21.333333 21.333333 0 0 0 20.992-17.493333L512 448V426.666667a21.333333 21.333333 0 0 0-21.333333-21.333334z m128-170.666666h-298.666667a21.333333 21.333333 0 0 0-20.992 17.493333L298.666667 256v21.333333a21.333333 21.333333 0 0 0 17.493333 20.992L320 298.666667h298.666667a21.333333 21.333333 0 0 0 20.992-17.493334L640 277.333333V256a21.333333 21.333333 0 0 0-21.333333-21.333333z" fill="#d81e06" p-id="4544"></path></svg>
|
||||||
|
After Width: | Height: | Size: 1.8 KiB |
|
|
@ -0,0 +1,68 @@
|
||||||
|
// pages/admin/exam/add.js
|
||||||
|
Page({
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 页面的初始数据
|
||||||
|
*/
|
||||||
|
data: {
|
||||||
|
form:{
|
||||||
|
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 生命周期函数--监听页面加载
|
||||||
|
*/
|
||||||
|
onLoad: function (options) {
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 生命周期函数--监听页面初次渲染完成
|
||||||
|
*/
|
||||||
|
onReady: function () {
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 生命周期函数--监听页面显示
|
||||||
|
*/
|
||||||
|
onShow: function () {
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 生命周期函数--监听页面隐藏
|
||||||
|
*/
|
||||||
|
onHide: function () {
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 生命周期函数--监听页面卸载
|
||||||
|
*/
|
||||||
|
onUnload: function () {
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 页面相关事件处理函数--监听用户下拉动作
|
||||||
|
*/
|
||||||
|
onPullDownRefresh: function () {
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 页面上拉触底事件的处理函数
|
||||||
|
*/
|
||||||
|
onReachBottom: function () {
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户点击右上角分享
|
||||||
|
*/
|
||||||
|
onShareAppMessage: function () {
|
||||||
|
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
{
|
||||||
|
"usingComponents": {}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,81 @@
|
||||||
|
<!--pages/admin/exam/add.wxml-->
|
||||||
|
<view class="page__title" style="text-align:center">新建考试</view>
|
||||||
|
<view class="weui-cells__title">基本信息</view>
|
||||||
|
<view class="weui-cells weui-cells_form">
|
||||||
|
<view class="weui-cell weui-cell_active">
|
||||||
|
<view class="weui-cell__hd"><label class="weui-label">考试名称</label></view>
|
||||||
|
<view class="weui-cell__bd">
|
||||||
|
<input class="weui-input" placeholder="填写考试名称" placeholder-class="weui-input__placeholder"
|
||||||
|
value="{{form.name}}" />
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="weui-cell weui-cell_active">
|
||||||
|
<view class="weui-cell__hd">
|
||||||
|
<label class="weui-label">考试地点</label>
|
||||||
|
</view>
|
||||||
|
<view class="weui-cell__bd">
|
||||||
|
<input class="weui-input" placeholder="填写考试地点" placeholder-class="weui-input__placeholder" type="number"
|
||||||
|
value="{{form.place}}" />
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="weui-cell weui-cell_active">
|
||||||
|
<view class="weui-cell__hd">
|
||||||
|
<label class="weui-label">工作类别</label>
|
||||||
|
</view>
|
||||||
|
<view class="weui-cell__bd">
|
||||||
|
<input class="weui-input" placeholder="填写您的快递单号" placeholder-class="weui-input__placeholder"
|
||||||
|
bindinput="kdInput" />
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="weui-cell weui-cell_active">
|
||||||
|
<view class="weui-cell__hd">
|
||||||
|
<label class="weui-label">参考机会</label>
|
||||||
|
</view>
|
||||||
|
<view class="weui-cell__bd">
|
||||||
|
<input class="weui-input" placeholder="填写可参考次数" placeholder-class="weui-input__placeholder"
|
||||||
|
value="3" />
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="weui-cell weui-cell_active">
|
||||||
|
<view class="weui-cell__hd">
|
||||||
|
<label class="weui-label">开启时间</label>
|
||||||
|
</view>
|
||||||
|
<view class="weui-cell__bd">
|
||||||
|
<input class="weui-input" placeholder="选择考试开启时间" placeholder-class="weui-input__placeholder"
|
||||||
|
bindinput="addressInput" />
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="weui-cell weui-cell_active">
|
||||||
|
<view class="weui-cell__hd">
|
||||||
|
<label class="weui-label">关闭时间</label>
|
||||||
|
</view>
|
||||||
|
<view class="weui-cell__bd">
|
||||||
|
<input class="weui-input" placeholder="选择考试关闭时间" placeholder-class="weui-input__placeholder"
|
||||||
|
bindinput="addressInput" />
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="weui-cells__title">监考人信息</view>
|
||||||
|
<view class="weui-cells weui-cells_form">
|
||||||
|
<view class="weui-cell weui-cell_active">
|
||||||
|
<view class="weui-cell__hd">
|
||||||
|
<label class="weui-label">姓名</label>
|
||||||
|
</view>
|
||||||
|
<view class="weui-cell__bd">
|
||||||
|
<input class="weui-input" placeholder="填写监考人姓名" placeholder-class="weui-input__placeholder"
|
||||||
|
value="{{form.proctor_name}}" />
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="weui-cell weui-cell_active">
|
||||||
|
<view class="weui-cell__hd">
|
||||||
|
<label class="weui-label">联系方式</label>
|
||||||
|
</view>
|
||||||
|
<view class="weui-cell__bd">
|
||||||
|
<input class="weui-input" placeholder="填写监考人联系方式" placeholder-class="weui-input__placeholder"
|
||||||
|
value="{{form.proctor_phone}}" />
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view style="margin-top:16rpx">
|
||||||
|
<a class="weui-btn weui-btn_primary" bindtap="submit">确定</a>
|
||||||
|
</view>
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
/* pages/admin/exam/add.wxss */
|
||||||
|
|
@ -0,0 +1,146 @@
|
||||||
|
const app = getApp()
|
||||||
|
const api = require("../../../utils/request.js");
|
||||||
|
Page({
|
||||||
|
data: {
|
||||||
|
formData: [
|
||||||
|
{
|
||||||
|
type: 'input',
|
||||||
|
id:'name',
|
||||||
|
lable:'考试名称',
|
||||||
|
isRequired: true,//是否必填
|
||||||
|
maxLength: 20,//最大长度
|
||||||
|
defaultValue:'',//初始值
|
||||||
|
rules:[//规则验证数组
|
||||||
|
{
|
||||||
|
regular: '^\\S*$',//正则字符串
|
||||||
|
tips: '不能有空格'//错误提示
|
||||||
|
},
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'input',
|
||||||
|
id:'place',
|
||||||
|
lable:'考试地点',
|
||||||
|
isRequired: true,//是否必填
|
||||||
|
maxLength: 50,//最大长度
|
||||||
|
defaultValue:'',//初始值
|
||||||
|
rules:[//规则验证数组
|
||||||
|
{
|
||||||
|
regular: '^\\S*$',//正则字符串
|
||||||
|
tips: '不能有空格'//错误提示
|
||||||
|
},
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'input',
|
||||||
|
id: 'chance',
|
||||||
|
lable: '考试机会',
|
||||||
|
defaultValue: 3,
|
||||||
|
inputType: 'digit', //对应input组件type值(text,number)
|
||||||
|
placeholder: '请填写数字',
|
||||||
|
isRequired: true,//是否必填
|
||||||
|
//disabled:true,
|
||||||
|
rules: [
|
||||||
|
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'picker',
|
||||||
|
id: 'workscope',
|
||||||
|
lable: '工作类别',
|
||||||
|
defaultIdx:0,//默认选择索引
|
||||||
|
// disabled:true,
|
||||||
|
isRequired:true,
|
||||||
|
range:[
|
||||||
|
{
|
||||||
|
id: 0,
|
||||||
|
name: '正常'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 1,
|
||||||
|
name: '异常'
|
||||||
|
},
|
||||||
|
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'date',
|
||||||
|
id: 'daterange',
|
||||||
|
lable: '开关时间',
|
||||||
|
isRequired: true,
|
||||||
|
/* 显示完整时间包含时分秒;当使用endDate的时候关闭,不要同时打开, 否则日期将会换行;
|
||||||
|
与config中的colum属性共同设置
|
||||||
|
*/
|
||||||
|
completeTime:true, //显示完整时间, 包含时分秒
|
||||||
|
config: {
|
||||||
|
endDate: true,
|
||||||
|
dateLimit: true,
|
||||||
|
// initStartTime: "2020-01-01 12:32:44",
|
||||||
|
// initEndTime: "2020-12-01 12:32:44",
|
||||||
|
column: "minute",//day、hour、minute、secend
|
||||||
|
limitStartTime: "2000-01-01 00:00:59",
|
||||||
|
limitEndTime: "2100-01-01 00:00:59"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'input',
|
||||||
|
id:'proctor_name',
|
||||||
|
lable:'监考人姓名',
|
||||||
|
isRequired: true,//是否必填
|
||||||
|
maxLength: 50,//最大长度
|
||||||
|
defaultValue:'',//初始值
|
||||||
|
rules:[//规则验证数组
|
||||||
|
{
|
||||||
|
regular: '^\\S*$',//正则字符串
|
||||||
|
tips: '不能有空格'//错误提示
|
||||||
|
},
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'input',
|
||||||
|
id:'proctor_phone',
|
||||||
|
lable:'监考人联系方式',
|
||||||
|
isRequired: true,//是否必填
|
||||||
|
maxLength: 50,//最大长度
|
||||||
|
defaultValue:'',//初始值
|
||||||
|
rules:[//规则验证数组
|
||||||
|
{
|
||||||
|
regular: '^\\S*$',//正则字符串
|
||||||
|
tips: '不能有空格'//错误提示
|
||||||
|
},
|
||||||
|
]
|
||||||
|
},
|
||||||
|
],
|
||||||
|
toSubmit: Math.random()
|
||||||
|
},
|
||||||
|
onFormSubmit(e){
|
||||||
|
console.log('表单提交: ', e);
|
||||||
|
let x = {};
|
||||||
|
x.opentime = e.daterange.startDate;
|
||||||
|
x.endtime = e.daterange.endDate;
|
||||||
|
x.name = e.name
|
||||||
|
x.place = e.place
|
||||||
|
x.chance = e.chance
|
||||||
|
x.workscope = e.workscope
|
||||||
|
x.proctor_name = e.proctor_name
|
||||||
|
x.proctor_phone = e.proctor_phone
|
||||||
|
console.log(x)
|
||||||
|
},
|
||||||
|
onFormChange(e){
|
||||||
|
console.log('表单变化: ',e);
|
||||||
|
},
|
||||||
|
//变更数值, 触发表单提交事件
|
||||||
|
toSubmitChange(){
|
||||||
|
this.setData({
|
||||||
|
toSubmit: Math.random()
|
||||||
|
})
|
||||||
|
},
|
||||||
|
onLoad: function () {
|
||||||
|
api.requesta('/examtest/workscope/?can_exam=true', 'GET').then(res=>{
|
||||||
|
this.data.formData[3].range=res.data
|
||||||
|
this.setData({
|
||||||
|
formData: this.data.formData
|
||||||
|
})
|
||||||
|
})
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
{
|
||||||
|
"usingComponents": {
|
||||||
|
"d-form": "/components/dynamicForm/index"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,4 @@
|
||||||
|
<!--pages/admin/exam/add2.wxml-->
|
||||||
|
<d-form formData="{{formData}}" showSubmitBtn="{{false}}" toSubmit="{{toSubmit}}" bind:dynamicFormChange="onFormChange" bind:dynamicFormSubmit="onFormSubmit"></d-form>
|
||||||
|
|
||||||
|
<button bindtap="toSubmitChange" type="primary">确认</button>
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
/* pages/admin/exam/add2.wxss */
|
||||||
|
|
@ -0,0 +1,86 @@
|
||||||
|
// pages/admin/index.js
|
||||||
|
const api = require("../../utils/request.js");
|
||||||
|
Page({
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 页面的初始数据
|
||||||
|
*/
|
||||||
|
data: {
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 生命周期函数--监听页面加载
|
||||||
|
*/
|
||||||
|
onLoad: function (options) {
|
||||||
|
this.setData({
|
||||||
|
admininfo:getApp().globalData.admininfo
|
||||||
|
})
|
||||||
|
},
|
||||||
|
logout: function(){
|
||||||
|
wx.redirectTo({
|
||||||
|
url: '/pages/admin/login?type=nologin',
|
||||||
|
})
|
||||||
|
},
|
||||||
|
bindmp: function(){
|
||||||
|
wx.login({
|
||||||
|
success: res => {
|
||||||
|
// 发送 res.code 到后台换取 openId, sessionKey, unionId
|
||||||
|
api.requesta('/rbac/user/bindmp/','POST', {code:res.code}).then(res=>{
|
||||||
|
getApp().globalData.admininfo.mpopenid = res.data.mpopenid
|
||||||
|
wx.redirectTo({
|
||||||
|
url: '/pages/admin/index',
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* 生命周期函数--监听页面初次渲染完成
|
||||||
|
*/
|
||||||
|
onReady: function () {
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 生命周期函数--监听页面显示
|
||||||
|
*/
|
||||||
|
onShow: function () {
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 生命周期函数--监听页面隐藏
|
||||||
|
*/
|
||||||
|
onHide: function () {
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 生命周期函数--监听页面卸载
|
||||||
|
*/
|
||||||
|
onUnload: function () {
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 页面相关事件处理函数--监听用户下拉动作
|
||||||
|
*/
|
||||||
|
onPullDownRefresh: function () {
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 页面上拉触底事件的处理函数
|
||||||
|
*/
|
||||||
|
onReachBottom: function () {
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户点击右上角分享
|
||||||
|
*/
|
||||||
|
onShareAppMessage: function () {
|
||||||
|
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
@ -0,0 +1,4 @@
|
||||||
|
{
|
||||||
|
"usingComponents": {},
|
||||||
|
"navigationBarTitleText": "管理员控制台"
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,53 @@
|
||||||
|
<!--pages/admin/index.wxml-->
|
||||||
|
<view class="page">
|
||||||
|
<view class="page__bd">
|
||||||
|
<view class="weui-cells weui-cells_after-title" style="margin-top:0px">
|
||||||
|
<view class="weui-panel__bd">
|
||||||
|
<view class="weui-media-box weui-media-box_appmsg">
|
||||||
|
<view class="weui-media-box__bd weui-media-box__bd_in-appmsg">
|
||||||
|
<view class="weui-media-box__title">
|
||||||
|
<span>账号:</span>
|
||||||
|
<span style="font-weight:bold;">{{admininfo.username}}</span>
|
||||||
|
</view>
|
||||||
|
<view class="weui-media-box__desc">昵称:
|
||||||
|
<span>{{ admininfo.name }}</span>
|
||||||
|
</view>
|
||||||
|
<view class="weui-media-box__desc">角色:
|
||||||
|
<span>{{ admininfo.roles }}</span>
|
||||||
|
</view>
|
||||||
|
<view class="weui-media-box__desc" wx:if="{{admininfo.mpopenid}}">
|
||||||
|
已绑定微信
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view style="text-align:right;padding-right:8rpx">
|
||||||
|
<button type="primary" size="mini" bindtap="bindmp" wx:if="{{!admininfo.mpopenid}}">绑定微信</button>
|
||||||
|
<button type="warn" size="mini" bindtap="logout" style="margin-left:4rpx">退出</button>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="weui-cells__title">功能列表</view>
|
||||||
|
<view class="weui-cells weui-cells_after-title">
|
||||||
|
<view class="weui-grids">
|
||||||
|
<navigator class="weui-grid" url="/pages/admin/exam/add2">
|
||||||
|
<view class="weui-grid__icon">
|
||||||
|
<image src="/images/suiji.svg" alt></image>
|
||||||
|
</view>
|
||||||
|
<view class="weui-grid__label">发布考试</view>
|
||||||
|
</navigator>
|
||||||
|
<a class="weui-grid" bindtap="goYati">
|
||||||
|
<view class="weui-grid__icon">
|
||||||
|
<image src="/images/examtest.svg" alt></image>
|
||||||
|
</view>
|
||||||
|
<view class="weui-grid__label">考试记录</view>
|
||||||
|
</a>
|
||||||
|
<navigator class="weui-grid" url="/pages/cuoti/index">
|
||||||
|
<view class="weui-grid__icon">
|
||||||
|
<image src="/images/candidate.svg" alt></image>
|
||||||
|
</view>
|
||||||
|
<view class="weui-grid__label">出证记录</view>
|
||||||
|
</navigator>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
/* pages/admin/index.wxss */
|
||||||
|
.weui-grids {
|
||||||
|
border-top:none;
|
||||||
|
}
|
||||||
|
.weui-grid {
|
||||||
|
width: 25%;
|
||||||
|
border-right:none;
|
||||||
|
border-bottom:none;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,116 @@
|
||||||
|
// pages/admin/login.js
|
||||||
|
const api = require("../../utils/request.js");
|
||||||
|
Page({
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 页面的初始数据
|
||||||
|
*/
|
||||||
|
data: {
|
||||||
|
form:{
|
||||||
|
username:'',
|
||||||
|
password:''
|
||||||
|
}
|
||||||
|
},
|
||||||
|
usernameChange: function (e) {
|
||||||
|
this.data.form.username = e.detail.value
|
||||||
|
},
|
||||||
|
passwordChange: function (e) {
|
||||||
|
this.data.form.password = e.detail.value
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* 生命周期函数--监听页面加载
|
||||||
|
*/
|
||||||
|
onLoad: function (options) {
|
||||||
|
if(options.type=='nologin'){
|
||||||
|
|
||||||
|
}else{
|
||||||
|
this.mplogin()
|
||||||
|
}
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 生命周期函数--监听页面初次渲染完成
|
||||||
|
*/
|
||||||
|
onReady: function () {
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 生命周期函数--监听页面显示
|
||||||
|
*/
|
||||||
|
onShow: function () {
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 生命周期函数--监听页面隐藏
|
||||||
|
*/
|
||||||
|
onHide: function () {
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 生命周期函数--监听页面卸载
|
||||||
|
*/
|
||||||
|
onUnload: function () {
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 页面相关事件处理函数--监听用户下拉动作
|
||||||
|
*/
|
||||||
|
onPullDownRefresh: function () {
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 页面上拉触底事件的处理函数
|
||||||
|
*/
|
||||||
|
onReachBottom: function () {
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户点击右上角分享
|
||||||
|
*/
|
||||||
|
onShareAppMessage: function () {
|
||||||
|
|
||||||
|
},
|
||||||
|
denglu: function ( ) {
|
||||||
|
var form = this.data.form
|
||||||
|
api.requesta('/token/', 'POST', form).then(res => {
|
||||||
|
getApp().globalData.admintoken = res.data.token;
|
||||||
|
api.requesta('/rbac/user/info/', 'GET').then(res=>{
|
||||||
|
getApp().globalData.admininfo = res.data
|
||||||
|
wx.showToast({
|
||||||
|
title: '登录成功',
|
||||||
|
icon: 'none'
|
||||||
|
})
|
||||||
|
wx.redirectTo({
|
||||||
|
url: '/pages/admin/index',
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
},
|
||||||
|
mplogin: function(){
|
||||||
|
wx.showLoading({
|
||||||
|
title: '自动登陆中',
|
||||||
|
mask:true
|
||||||
|
})
|
||||||
|
wx.login({
|
||||||
|
success: res => {
|
||||||
|
// 发送 res.code 到后台换取 openId, sessionKey, unionId
|
||||||
|
api.requesta('/rbac/user/mplogin/','POST', {code:res.code}).then(res=>{
|
||||||
|
getApp().globalData.admintoken = res.data.token;
|
||||||
|
api.requesta('/rbac/user/info/', 'GET').then(res=>{
|
||||||
|
getApp().globalData.admininfo = res.data
|
||||||
|
wx.redirectTo({
|
||||||
|
url: '/pages/admin/index',
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
@ -0,0 +1,4 @@
|
||||||
|
{
|
||||||
|
"usingComponents": {},
|
||||||
|
"navigationBarTitleText": "管理员登录"
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,33 @@
|
||||||
|
<!--pages/admin/login.wxml-->
|
||||||
|
<view class="page">
|
||||||
|
<view class="page__hd" >
|
||||||
|
<view class="page__title" style="text-align:center">中科辐射学堂</view>
|
||||||
|
<view class="page__desc" style="text-align:center">管理员登录</view>
|
||||||
|
</view>
|
||||||
|
<view class="page__bd">
|
||||||
|
<view class="weui-cells weui-cells_after-title">
|
||||||
|
<view class="weui-cell weui-cell_input">
|
||||||
|
<view class="weui-cell__hd">
|
||||||
|
<view class="weui-label">账号</view>
|
||||||
|
</view>
|
||||||
|
<view class="weui-cell__bd">
|
||||||
|
<input class="weui-input" placeholder="请输入管理员账号" bindinput="usernameChange" />
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="weui-cell weui-cell_input">
|
||||||
|
<view class="weui-cell__hd">
|
||||||
|
<view class="weui-label">密码</view>
|
||||||
|
</view>
|
||||||
|
<view class="weui-cell__bd">
|
||||||
|
<input class="weui-input" placeholder="请输入密码" bindinput="passwordChange" type="password"/>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<button class="weui-btn" type="primary" bindtap="denglu">登陆</button>
|
||||||
|
</view>
|
||||||
|
<view class="weui-footer weui-footer_fixed-bottom">
|
||||||
|
<!-- <view class="weui-footer__text" bindtap="intro">点击下载系统/小程序文档介绍</view> -->
|
||||||
|
<view class="weui-footer__text">Copyright © 2018-2021 国检集团</view>
|
||||||
|
<view class="weui-footer__text">中存大数据提供技术支持</view>
|
||||||
|
</view>
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
/* pages/admin/login.wxss */
|
||||||
|
|
@ -107,6 +107,11 @@ Page({
|
||||||
url: '/pages/main/main',
|
url: '/pages/main/main',
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
goadmin: function(){
|
||||||
|
wx.redirectTo({
|
||||||
|
url: '/pages/admin/login',
|
||||||
|
})
|
||||||
|
},
|
||||||
denglu: function (data) {
|
denglu: function (data) {
|
||||||
api.request('/crm/consumer/register/', 'POST', data).then(res => {
|
api.request('/crm/consumer/register/', 'POST', data).then(res => {
|
||||||
getApp().onLaunch()
|
getApp().onLaunch()
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,7 @@
|
||||||
</view>
|
</view>
|
||||||
<view class="weui-footer weui-footer_fixed-bottom">
|
<view class="weui-footer weui-footer_fixed-bottom">
|
||||||
<!-- <view class="weui-footer__text" bindtap="intro">点击下载系统/小程序文档介绍</view> -->
|
<!-- <view class="weui-footer__text" bindtap="intro">点击下载系统/小程序文档介绍</view> -->
|
||||||
<view class="weui-footer__text">Copyright © 2018-2020 国检集团</view>
|
<view style="color:blue" bindtap="goadmin">管理员入口</view>
|
||||||
|
<view class="weui-footer__text">Copyright © 2018-2021 国检集团</view>
|
||||||
<view class="weui-footer__text">中存大数据提供技术支持</view>
|
<view class="weui-footer__text">中存大数据提供技术支持</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
@ -72,6 +72,13 @@
|
||||||
<view class="weui-cell__ft weui-cell__ft_in-access" style="color:red"></view>
|
<view class="weui-cell__ft weui-cell__ft_in-access" style="color:red"></view>
|
||||||
</navigator>
|
</navigator>
|
||||||
</view>
|
</view>
|
||||||
|
<view class="weui-cells__title">管理员操作台</view>
|
||||||
|
<view class="weui-cells weui-cells_after-title">
|
||||||
|
<navigator url="/pages/admin/login" class="weui-cell weui-cell_access">
|
||||||
|
<view class="weui-cell__bd">管理员入口</view>
|
||||||
|
<view class="weui-cell__ft weui-cell__ft_in-access" style="color:red"></view>
|
||||||
|
</navigator>
|
||||||
|
</view>
|
||||||
<view class="weui-footer weui-footer_fixed-bottom">
|
<view class="weui-footer weui-footer_fixed-bottom">
|
||||||
<!-- <view class="weui-footer__text" bindtap="intro">点击下载系统/小程序文档介绍</view> -->
|
<!-- <view class="weui-footer__text" bindtap="intro">点击下载系统/小程序文档介绍</view> -->
|
||||||
<view class="weui-footer__text">更多服务请联系课程顾问</view>
|
<view class="weui-footer__text">更多服务请联系课程顾问</view>
|
||||||
|
|
|
||||||
|
|
@ -21,13 +21,15 @@
|
||||||
"checkSiteMap": true,
|
"checkSiteMap": true,
|
||||||
"uploadWithSourceMap": true,
|
"uploadWithSourceMap": true,
|
||||||
"compileHotReLoad": false,
|
"compileHotReLoad": false,
|
||||||
"useMultiFrameRuntime": false,
|
"useMultiFrameRuntime": true,
|
||||||
"useApiHook": true,
|
"useApiHook": true,
|
||||||
|
"useApiHostProcess": false,
|
||||||
"babelSetting": {
|
"babelSetting": {
|
||||||
"ignore": [],
|
"ignore": [],
|
||||||
"disablePlugins": [],
|
"disablePlugins": [],
|
||||||
"outputPath": ""
|
"outputPath": ""
|
||||||
},
|
},
|
||||||
|
"enableEngineNative": false,
|
||||||
"bundle": false,
|
"bundle": false,
|
||||||
"useIsolateContext": true,
|
"useIsolateContext": true,
|
||||||
"useCompilerModule": true,
|
"useCompilerModule": true,
|
||||||
|
|
@ -38,7 +40,7 @@
|
||||||
"minifyWXSS": true
|
"minifyWXSS": true
|
||||||
},
|
},
|
||||||
"compileType": "miniprogram",
|
"compileType": "miniprogram",
|
||||||
"libVersion": "2.14.1",
|
"libVersion": "2.16.1",
|
||||||
"appid": "wxf1e9471c93f05ad6",
|
"appid": "wxf1e9471c93f05ad6",
|
||||||
"projectname": "test_mini",
|
"projectname": "test_mini",
|
||||||
"debugOptions": {
|
"debugOptions": {
|
||||||
|
|
|
||||||
|
|
@ -51,6 +51,57 @@ function request(url, method, data) {
|
||||||
return promise;
|
return promise;
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {
|
function requesta(url, method, data) {
|
||||||
request: request
|
let promise = new Promise((resolve, reject) => {
|
||||||
|
wx.showNavigationBarLoading();
|
||||||
|
wx.request({
|
||||||
|
url: getApp().globalData.host + url,
|
||||||
|
method: method,
|
||||||
|
data: data,
|
||||||
|
header:{
|
||||||
|
'Authorization': 'JWT ' + getApp().globalData.admintoken
|
||||||
|
},
|
||||||
|
success: (res => {
|
||||||
|
if (res.data.code >= 200 && res.data.code < 400) {
|
||||||
|
resolve(res.data);
|
||||||
|
}else if(res.data.code == 401){
|
||||||
|
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
var msg = '请求错误'
|
||||||
|
if(res.data.msg){
|
||||||
|
msg = res.data.msg
|
||||||
|
}
|
||||||
|
if (msg.indexOf('该操作的权限')!=-1){
|
||||||
|
msg = '权限不足或账户过期,请联系课程顾问'
|
||||||
|
}
|
||||||
|
wx.showToast({
|
||||||
|
title: msg,
|
||||||
|
icon: 'none',
|
||||||
|
duration: 1000
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
}),
|
||||||
|
fail: (res => {
|
||||||
|
wx.showToast({
|
||||||
|
title: '请求出错',
|
||||||
|
icon: 'none',
|
||||||
|
duration: 1500
|
||||||
|
})
|
||||||
|
console.log(res)
|
||||||
|
reject('网络出错');
|
||||||
|
}),
|
||||||
|
complete: function () {
|
||||||
|
wx.hideNavigationBarLoading();
|
||||||
|
}
|
||||||
|
|
||||||
|
})
|
||||||
|
})
|
||||||
|
return promise;
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
request: request,
|
||||||
|
requesta: requesta
|
||||||
}
|
}
|
||||||
|
|
@ -16,8 +16,7 @@ from rest_framework.response import Response
|
||||||
from rest_framework.views import APIView
|
from rest_framework.views import APIView
|
||||||
from rest_framework.viewsets import ModelViewSet
|
from rest_framework.viewsets import ModelViewSet
|
||||||
from rest_framework_jwt.authentication import JSONWebTokenAuthentication
|
from rest_framework_jwt.authentication import JSONWebTokenAuthentication
|
||||||
from rest_framework_jwt.serializers import (jwt_encode_handler,
|
from rest_framework_jwt.serializers import jwt_encode_handler
|
||||||
jwt_payload_handler)
|
|
||||||
from rest_framework_jwt.settings import api_settings
|
from rest_framework_jwt.settings import api_settings
|
||||||
|
|
||||||
from crm.zhenzismsclient import ZhenziSmsClient
|
from crm.zhenzismsclient import ZhenziSmsClient
|
||||||
|
|
@ -35,16 +34,12 @@ from rbac.models import UserProfile
|
||||||
from django.http import Http404
|
from django.http import Http404
|
||||||
from .spider import getZs
|
from .spider import getZs
|
||||||
import time
|
import time
|
||||||
appid = 'wxf1e9471c93f05ad6'
|
from server.config import *
|
||||||
secret = '4bf7f9bd6c52634586bbe792a1f0a834'
|
|
||||||
sms_appid = '100172'
|
|
||||||
sms_appsecret = '00b8681c-0ce6-41c8-a867-904c1891c78a'
|
|
||||||
sms_url = 'https://sms.zhenzikj.com'
|
|
||||||
|
|
||||||
def jwt_payload_handler(user):
|
def my_payload_handler(user, dtype="admin"):
|
||||||
payload = {
|
payload = {
|
||||||
'user_id': user.pk,
|
'user_id': user.pk,
|
||||||
'type':'consumer',
|
'type':dtype,
|
||||||
'exp': datetime.utcnow() + api_settings.JWT_EXPIRATION_DELTA
|
'exp': datetime.utcnow() + api_settings.JWT_EXPIRATION_DELTA
|
||||||
}
|
}
|
||||||
if api_settings.JWT_ALLOW_REFRESH:
|
if api_settings.JWT_ALLOW_REFRESH:
|
||||||
|
|
@ -571,7 +566,7 @@ class ConsumerMPLoginView(APIView):
|
||||||
session_key = info['session_key']
|
session_key = info['session_key']
|
||||||
consumer = Consumer.objects.get_or_create(openid = openid)[0]
|
consumer = Consumer.objects.get_or_create(openid = openid)[0]
|
||||||
serializer = ConsumerDetailSerializer(instance=consumer)
|
serializer = ConsumerDetailSerializer(instance=consumer)
|
||||||
payload = jwt_payload_handler(consumer)
|
payload = my_payload_handler(consumer, 'consumer')
|
||||||
token = jwt_encode_handler(payload)
|
token = jwt_encode_handler(payload)
|
||||||
return Response({"token":token,"session_key":session_key, "openid":openid, "userinfo":serializer.data})
|
return Response({"token":token,"session_key":session_key, "openid":openid, "userinfo":serializer.data})
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,18 @@
|
||||||
|
# Generated by Django 3.0.4 on 2021-05-25 02:23
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('rbac', '0005_userprofile_bcompany'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='userprofile',
|
||||||
|
name='mpopenid',
|
||||||
|
field=models.CharField(blank=True, max_length=100, null=True, unique=True, verbose_name='小程序openid'),
|
||||||
|
),
|
||||||
|
]
|
||||||
|
|
@ -152,6 +152,7 @@ class UserProfile(AbstractUser):
|
||||||
|
|
||||||
pname = models.CharField('所属省份', max_length=100, null=True, blank=True)
|
pname = models.CharField('所属省份', max_length=100, null=True, blank=True)
|
||||||
bcompany = models.ForeignKey('crm.company', verbose_name='所属公司', null=True, blank=True, on_delete=models.SET_NULL)
|
bcompany = models.ForeignKey('crm.company', verbose_name='所属公司', null=True, blank=True, on_delete=models.SET_NULL)
|
||||||
|
mpopenid = models.CharField(max_length=100, verbose_name='小程序openid', unique=True, null=True, blank=True)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
verbose_name = "用户信息"
|
verbose_name = "用户信息"
|
||||||
|
|
|
||||||
|
|
@ -1,28 +1,35 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
import json
|
||||||
from operator import itemgetter
|
from operator import itemgetter
|
||||||
|
|
||||||
|
import requests
|
||||||
# import jwt
|
# import jwt
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.contrib.auth import authenticate,login,logout
|
from django.contrib.auth import authenticate, login, logout
|
||||||
from django.contrib.auth.hashers import check_password
|
from django.contrib.auth.hashers import check_password, make_password
|
||||||
from django_filters.rest_framework import DjangoFilterBackend
|
from django_filters.rest_framework import DjangoFilterBackend
|
||||||
from django.contrib.auth.hashers import make_password
|
from rest_framework import status
|
||||||
from rest_framework.decorators import action
|
from rest_framework.decorators import action, authentication_classes
|
||||||
from rest_framework.filters import SearchFilter, OrderingFilter
|
from rest_framework.filters import OrderingFilter, SearchFilter
|
||||||
from rest_framework.generics import ListAPIView
|
from rest_framework.generics import ListAPIView
|
||||||
from rest_framework.permissions import IsAuthenticated
|
from rest_framework.permissions import IsAuthenticated
|
||||||
from rest_framework.response import Response
|
from rest_framework.response import Response
|
||||||
from rest_framework.views import APIView
|
from rest_framework.views import APIView
|
||||||
from rest_framework.viewsets import ModelViewSet
|
from rest_framework.viewsets import ModelViewSet
|
||||||
from rest_framework import status
|
|
||||||
|
|
||||||
from utils.custom import CommonPagination
|
|
||||||
from utils.child import get_child_queryset
|
from utils.child import get_child_queryset
|
||||||
from ..models import UserProfile, Menu, Organization
|
from utils.custom import CommonPagination
|
||||||
|
|
||||||
|
from ..models import Menu, Organization, UserProfile
|
||||||
|
from ..permission import (RbacPermission, get_all_menu_queryset,
|
||||||
|
get_permission_list)
|
||||||
from ..serializers.menu_serializer import MenuSerializer
|
from ..serializers.menu_serializer import MenuSerializer
|
||||||
from ..serializers.user_serializer import UserListSerializer, UserCreateSerializer, UserModifySerializer, \
|
from ..serializers.user_serializer import (UserCreateSerializer,
|
||||||
UserInfoListSerializer
|
UserInfoListSerializer,
|
||||||
from ..permission import get_all_menu_queryset,get_permission_list,RbacPermission
|
UserListSerializer,
|
||||||
|
UserModifySerializer)
|
||||||
|
from server.config import *
|
||||||
|
from rest_framework_jwt.serializers import jwt_encode_handler
|
||||||
|
from crm.views import my_payload_handler
|
||||||
|
|
||||||
class UserLogoutView(APIView):
|
class UserLogoutView(APIView):
|
||||||
authentication_classes = ()
|
authentication_classes = ()
|
||||||
|
|
@ -47,6 +54,8 @@ class UserInfoView(APIView):
|
||||||
# 'avatar': request._request._current_scheme_host + '/media/' + str(user.image),
|
# 'avatar': request._request._current_scheme_host + '/media/' + str(user.image),
|
||||||
'avatar': user.avatar,
|
'avatar': user.avatar,
|
||||||
'perms': perms,
|
'perms': perms,
|
||||||
|
'roles':user.roles.values_list('name', flat=True),
|
||||||
|
'mpopenid': user.mpopenid
|
||||||
}
|
}
|
||||||
|
|
||||||
return Response(data)
|
return Response(data)
|
||||||
|
|
@ -59,6 +68,7 @@ class UserInfoView(APIView):
|
||||||
|
|
||||||
from utils.pagination import PageOrNot
|
from utils.pagination import PageOrNot
|
||||||
|
|
||||||
|
|
||||||
class UserViewSet(PageOrNot, ModelViewSet):
|
class UserViewSet(PageOrNot, ModelViewSet):
|
||||||
"""
|
"""
|
||||||
用户管理:增删改查
|
用户管理:增删改查
|
||||||
|
|
@ -136,3 +146,38 @@ class UserViewSet(PageOrNot, ModelViewSet):
|
||||||
else:
|
else:
|
||||||
return Response({'error':'旧密码错误!'})
|
return Response({'error':'旧密码错误!'})
|
||||||
|
|
||||||
|
@action(methods=['post'], detail=False, permission_classes=[], authentication_classes=[])
|
||||||
|
def mplogin(self, request, pk=None):
|
||||||
|
"""
|
||||||
|
小程序登录
|
||||||
|
"""
|
||||||
|
code = request.data['code']
|
||||||
|
info = requests.get('https://api.weixin.qq.com/sns/jscode2session?appid='+appid+'&secret='+secret+'&js_code=' +
|
||||||
|
code+'&grant_type=authorization_code').content.decode('utf-8')
|
||||||
|
info = json.loads(info)
|
||||||
|
openid = info['openid']
|
||||||
|
session_key = info['session_key']
|
||||||
|
try:
|
||||||
|
user = UserProfile.objects.get(mpopenid = openid)
|
||||||
|
payload = my_payload_handler(user)
|
||||||
|
token = jwt_encode_handler(payload)
|
||||||
|
return Response({"token":token,"session_key":session_key, "openid":openid})
|
||||||
|
except:
|
||||||
|
return Response({'error':'自动登录失败!'})
|
||||||
|
|
||||||
|
@action(methods=['post'], detail=False, permission_classes=[IsAuthenticated])
|
||||||
|
def bindmp(self, request, pk=None):
|
||||||
|
"""
|
||||||
|
绑定微信
|
||||||
|
"""
|
||||||
|
user = request.user
|
||||||
|
code = request.data['code']
|
||||||
|
info = requests.get('https://api.weixin.qq.com/sns/jscode2session?appid='+appid+'&secret='+secret+'&js_code=' +
|
||||||
|
code+'&grant_type=authorization_code').content.decode('utf-8')
|
||||||
|
info = json.loads(info)
|
||||||
|
openid = info['openid']
|
||||||
|
user.mpopenid = openid
|
||||||
|
user.save()
|
||||||
|
return Response({'mpopenid':openid})
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
appid = 'wxf1e9471c93f05ad6'
|
||||||
|
secret = '4bf7f9bd6c52634586bbe792a1f0a834'
|
||||||
|
sms_appid = '100172'
|
||||||
|
sms_appsecret = '00b8681c-0ce6-41c8-a867-904c1891c78a'
|
||||||
|
sms_url = 'https://sms.zhenzikj.com'
|
||||||
|
|
@ -45,7 +45,11 @@ class FitJSONRenderer(JSONRenderer):
|
||||||
response = renderer_context.get("response")
|
response = renderer_context.get("response")
|
||||||
response_body.code = response.status_code
|
response_body.code = response.status_code
|
||||||
if response_body.code >= 400: # drf异常
|
if response_body.code >= 400: # drf异常
|
||||||
response_body.msg = data['detail'] if 'detail' in data else data
|
if isinstance(data, dict):
|
||||||
|
data = data[list(data.keys())[0]]
|
||||||
|
if isinstance(data, list):
|
||||||
|
data = data[0]
|
||||||
|
response_body.msg = data
|
||||||
elif data and 'error' in data and data['error']:# 自传异常,key为error
|
elif data and 'error' in data and data['error']:# 自传异常,key为error
|
||||||
response_body.code = data.get("code",400)
|
response_body.code = data.get("code",400)
|
||||||
response_body.msg = data.get("error", "")
|
response_body.msg = data.get("error", "")
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue