会议室
This commit is contained in:
parent
76660dd3f4
commit
d61d99653d
33
components/noData.vue
Normal file
33
components/noData.vue
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
<template>
|
||||||
|
<view class="container">
|
||||||
|
<view class="no-data">
|
||||||
|
<image src="/static/imgs/noData.png"></image>
|
||||||
|
<view class="">
|
||||||
|
暂无数据...
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.no-data{
|
||||||
|
width: 300rpx;
|
||||||
|
height: 330rpx;
|
||||||
|
margin: 0 auto;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
image{
|
||||||
|
width:100%;
|
||||||
|
// margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
view{
|
||||||
|
color: #666;
|
||||||
|
font-size: 20rpx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
132
components/signature.vue
Normal file
132
components/signature.vue
Normal file
@ -0,0 +1,132 @@
|
|||||||
|
<template>
|
||||||
|
<!-- pages/signature/signature.wxml -->
|
||||||
|
<view class="signature-container">
|
||||||
|
<!-- 签名画布 -->
|
||||||
|
<canvas canvas-id="signatureCanvas" disable-scroll="true" bindtouchstart="handleTouchStart"
|
||||||
|
bindtouchmove="handleTouchMove" bindtouchend="handleTouchEnd"
|
||||||
|
style="width: 100%; border: 1px solid #ccc;"></canvas>
|
||||||
|
|
||||||
|
<!-- 操作按钮 -->
|
||||||
|
<view class="button-group">
|
||||||
|
<button bindtap="clearCanvas">清除</button>
|
||||||
|
<button bindtap="saveSignature" type="primary">保存签名</button>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 签名预览 -->
|
||||||
|
<image wx:if="signatureImage" :src="signatureImage" style="width: 100%; margin-top: 20px;"></image>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: "signature",
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
signatureImage: '', // 保存的签名图片
|
||||||
|
ctx: null, // Canvas 上下文
|
||||||
|
points: [], // 记录绘制路径
|
||||||
|
};
|
||||||
|
},
|
||||||
|
onReady() {
|
||||||
|
// 初始化 Canvas 上下文
|
||||||
|
this.setData({
|
||||||
|
ctx: wx.createCanvasContext('signatureCanvas')
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
// 触摸开始
|
||||||
|
handleTouchStart(e) {
|
||||||
|
const {
|
||||||
|
x,
|
||||||
|
y
|
||||||
|
} = e.touches[0];
|
||||||
|
this.data.points = [{
|
||||||
|
x,
|
||||||
|
y
|
||||||
|
}];
|
||||||
|
},
|
||||||
|
|
||||||
|
// 触摸移动
|
||||||
|
handleTouchMove(e) {
|
||||||
|
const {
|
||||||
|
x,
|
||||||
|
y
|
||||||
|
} = e.touches[0];
|
||||||
|
const points = this.data.points;
|
||||||
|
points.push({
|
||||||
|
x,
|
||||||
|
y
|
||||||
|
});
|
||||||
|
|
||||||
|
// 绘制路径
|
||||||
|
if (points.length >= 2) {
|
||||||
|
this.drawLine(points[points.length - 2], points[points.length - 1]);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// 触摸结束
|
||||||
|
handleTouchEnd() {
|
||||||
|
this.data.points = [];
|
||||||
|
},
|
||||||
|
|
||||||
|
// 绘制线段
|
||||||
|
drawLine(start, end) {
|
||||||
|
const ctx = this.data.ctx;
|
||||||
|
ctx.setStrokeStyle('#000'); // 线条颜色
|
||||||
|
ctx.setLineWidth(3); // 线条宽度
|
||||||
|
ctx.setLineCap('round'); // 圆角线条
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.moveTo(start.x, start.y);
|
||||||
|
ctx.lineTo(end.x, end.y);
|
||||||
|
ctx.stroke();
|
||||||
|
ctx.draw(true); // 实时绘制
|
||||||
|
},
|
||||||
|
|
||||||
|
// 清除画布
|
||||||
|
clearCanvas() {
|
||||||
|
this.data.ctx.clearRect(0, 0, 300, 400); // 需根据实际画布宽高调整
|
||||||
|
this.data.ctx.draw(true);
|
||||||
|
this.setData({
|
||||||
|
signatureImage: ''
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
// 保存签名
|
||||||
|
saveSignature() {
|
||||||
|
wx.canvasToTempFilePath({
|
||||||
|
canvasId: 'signatureCanvas',
|
||||||
|
success: (res) => {
|
||||||
|
this.setData({
|
||||||
|
signatureImage: res.tempFilePath
|
||||||
|
});
|
||||||
|
wx.showToast({
|
||||||
|
title: '签名已保存'
|
||||||
|
});
|
||||||
|
// 这里可以上传到服务器或传递给其他页面
|
||||||
|
},
|
||||||
|
fail: (err) => {
|
||||||
|
console.error('保存失败:', err);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
/* pages/signature/signature.wxss */
|
||||||
|
.signature-container {
|
||||||
|
padding: 20px;
|
||||||
|
height: 60vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
.button-group {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
margin-top: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
flex: 1;
|
||||||
|
margin: 0 10px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
13
pages.json
13
pages.json
@ -202,6 +202,19 @@
|
|||||||
"navigationStyle": "default",
|
"navigationStyle": "default",
|
||||||
"usingComponents": {}
|
"usingComponents": {}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path" : "pages/meetingDetail/ceshi/ceshi",
|
||||||
|
"style" :
|
||||||
|
{
|
||||||
|
"navigationBarTitleText" : ""
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "pages/sign/sign",
|
||||||
|
"style": {
|
||||||
|
"navigationBarTitleText": "电子签名"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
],
|
],
|
||||||
|
|||||||
@ -26,19 +26,83 @@
|
|||||||
<view class="date-section">
|
<view class="date-section">
|
||||||
<view class="section-header">
|
<view class="section-header">
|
||||||
<u-icon name="calendar" size="38" color="#2979ff"></u-icon>
|
<u-icon name="calendar" size="38" color="#2979ff"></u-icon>
|
||||||
<text class="section-title">选择日期</text>
|
<text class="section-title">申请时间</text>
|
||||||
</view>
|
</view>
|
||||||
<view class="date-display" @click="showCalendar = true">
|
<view class="date-display" @click="showCalendar = true">
|
||||||
<text>{{ formattedSelectedDate }}</text>
|
<text>{{ formattedSelectedDate }}</text>
|
||||||
<u-icon name="arrow-right" color="#999"></u-icon>
|
<u-icon name="arrow-right" color="#999"></u-icon>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
<view class="date-section">
|
||||||
|
<view class="section-header">
|
||||||
|
<u-icon name="tags" size="38" color="#2979ff"></u-icon>
|
||||||
|
<text class="section-title">事由主题</text>
|
||||||
|
</view>
|
||||||
|
<view>
|
||||||
|
<checkbox-group @change="thingCheckboxChange" v-model="thingTheme">
|
||||||
|
<label v-for="item in thingThemes">
|
||||||
|
<checkbox :value="item.value" style="transform:scale(0.7)" /><text
|
||||||
|
style="font-size: 12px;color: #333333;">{{item.name}}</text>
|
||||||
|
</label>
|
||||||
|
</checkbox-group>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="date-section">
|
||||||
|
<view class="section-header">
|
||||||
|
<u-icon name="man-add" size="38" color="#2979ff"></u-icon>
|
||||||
|
<text class="section-title">申请人类型</text>
|
||||||
|
</view>
|
||||||
|
<view class="date-display" @click="showApplyType = true">
|
||||||
|
<view class="">{{applyName}}</view>
|
||||||
|
<u-icon slot="right" name="arrow-right"></u-icon>
|
||||||
|
</view>
|
||||||
|
<view v-show="applyName=='单位申请'" style="margin-top: 10px;background-color: #f8f9fa;">
|
||||||
|
<u--input placeholder="请输入单位全称" border="null" v-model="companyName"></u--input>
|
||||||
|
</view>
|
||||||
|
<view v-show="applyName=='个人申请'">
|
||||||
|
<view class="" style="margin-top: 10px;background-color: #f8f9fa;">
|
||||||
|
<u--input placeholder="请输入姓名" border="null" v-model="userName"></u--input>
|
||||||
|
</view>
|
||||||
|
<view class="" style="margin-top: 10px;background-color: #f8f9fa;">
|
||||||
|
<u--input placeholder="请输入身份证号" border="null" v-model="userCard"></u--input>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="date-section">
|
||||||
|
<view class="section-header">
|
||||||
|
<u-icon name="man-add" size="38" color="#2979ff"></u-icon>
|
||||||
|
<text class="section-title">负责人</text>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view>
|
||||||
|
<view class="" style="margin-top: 10px;background-color: #f8f9fa;">
|
||||||
|
<u--input placeholder="请输入负责人姓名" border="null" v-model="chargeName"></u--input>
|
||||||
|
</view>
|
||||||
|
<view class="" style="margin-top: 10px;background-color: #f8f9fa;">
|
||||||
|
<u--input placeholder="请输入负责人电话" border="null" v-model="chargePhone"></u--input>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="date-section">
|
||||||
|
<view class="section-header">
|
||||||
|
<u-icon name="pushpin" size="38" color="#2979ff"></u-icon>
|
||||||
|
<text class="section-title">申请场次及人数</text>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view>
|
||||||
|
<view class="" style="margin-top: 10px;background-color: #f8f9fa;">
|
||||||
|
<u--input placeholder="请输入场次" border="null" v-model="session"></u--input>
|
||||||
|
</view>
|
||||||
|
<view class="" style="margin-top: 10px;background-color: #f8f9fa;">
|
||||||
|
<u--input placeholder="请输入人数" border="null" v-model="num"></u--input>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
<!-- 时间选择 -->
|
<!-- 时间选择 -->
|
||||||
<view class="time-section">
|
<view class="time-section">
|
||||||
<view class="section-header">
|
<view class="section-header">
|
||||||
<u-icon name="clock" size="34" color="#2979ff"></u-icon>
|
<u-icon name="clock" size="30" color="#2979ff"></u-icon>
|
||||||
<text class="section-title">选择时间段</text>
|
<text class="section-title">借用时间</text>
|
||||||
</view>
|
</view>
|
||||||
<view class="time-picker">
|
<view class="time-picker">
|
||||||
<view class="time-selector" @click="showStartTimePicker = true">
|
<view class="time-selector" @click="showStartTimePicker = true">
|
||||||
@ -56,20 +120,24 @@
|
|||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
<view class="date-section">
|
||||||
<!-- 新增备注输入区域 -->
|
|
||||||
<view class="remark-section">
|
|
||||||
<view class="section-header">
|
<view class="section-header">
|
||||||
<u-icon name="edit-pen" size="34" color="#2979ff"></u-icon>
|
<u-icon name="list-dot" size="38" color="#2979ff"></u-icon>
|
||||||
<text class="section-title">备注信息</text>
|
<text class="section-title">使用情况</text>
|
||||||
|
</view>
|
||||||
|
<view>
|
||||||
|
<checkbox-group @change="usagesCheckboxChange" v-model="usage">
|
||||||
|
<label v-for="item in usages">
|
||||||
|
<checkbox :value="item.value" style="transform:scale(0.7)" /><text
|
||||||
|
style="font-size: 12px;color: #333333;">{{item.name}}</text>
|
||||||
|
</label>
|
||||||
|
</checkbox-group>
|
||||||
</view>
|
</view>
|
||||||
<u--textarea v-model="remark" placeholder="请输入备注信息(选填)" count maxlength="200" height="120" border="none"
|
|
||||||
:customStyle="{background: '#f8f9fa', borderRadius: '12rpx', padding: '20rpx'}"></u--textarea>
|
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<!-- 预定须知卡片 -->
|
<!-- 预定须知卡片 -->
|
||||||
<view class="notice-card">
|
<!-- <view class="notice-card">
|
||||||
<view class="card-header">
|
<view class="card-header">
|
||||||
<u-icon name="info-circle" size="34" color="#2979ff"></u-icon>
|
<u-icon name="info-circle" size="34" color="#2979ff"></u-icon>
|
||||||
<text class="card-title">预订须知</text>
|
<text class="card-title">预订须知</text>
|
||||||
@ -80,11 +148,12 @@
|
|||||||
<text class="notice-content">{{ item }}</text>
|
<text class="notice-content">{{ item }}</text>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view> -->
|
||||||
|
|
||||||
<!-- 底部固定操作栏 -->
|
<!-- 底部固定操作栏 -->
|
||||||
<view class="action-bar">
|
<view class="action-bar">
|
||||||
<u-button type="primary" shape="circle" @click="handleBook">立即预订</u-button>
|
<!-- <u-button type="primary" shape="circle" @click="handleBook">立即预订</u-button> -->
|
||||||
|
<u-button type="primary" shape="circle" @click="signatureShow=true">立即预订</u-button>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<!-- 日历组件 -->
|
<!-- 日历组件 -->
|
||||||
@ -92,11 +161,21 @@
|
|||||||
@confirm="handleDateConfirm" @close="showCalendar = false" :mask-close-able="true"></u-calendar>
|
@confirm="handleDateConfirm" @close="showCalendar = false" :mask-close-able="true"></u-calendar>
|
||||||
|
|
||||||
<!-- 时间选择器 -->
|
<!-- 时间选择器 -->
|
||||||
<u-datetime-picker :show="showStartTimePicker" v-model="startTimePickerValue" mode="time" format="HH:mm"
|
<u-datetime-picker :show="showStartTimePicker" v-model="startTimePickerValue" :min-date="Date.now()"
|
||||||
@confirm="handleStartTimeConfirm" @cancel="showStartTimePicker = false"></u-datetime-picker>
|
:mode="mode" @confirm="handleStartTimeConfirm" @cancel="showStartTimePicker = false"
|
||||||
|
ref="startTimePicker"></u-datetime-picker>
|
||||||
|
|
||||||
|
<u-datetime-picker :show="showEndTimePicker" v-model="endTimePickerValue" :min-date="Date.now()" :mode="mode"
|
||||||
|
@confirm="handleEndTimeConfirm" @cancel="showEndTimePicker = false" ref="endTimePicker"></u-datetime-picker>
|
||||||
|
<u-picker :show="showApplyType" :columns="applyTypeColumns" @confirm="applyConfirm"
|
||||||
|
@cancel="showApplyType=false"></u-picker>
|
||||||
|
|
||||||
|
<u-popup :show="signatureShow" :round="10" mode="bottom" closeOnClickOverlay>
|
||||||
|
<view>
|
||||||
|
|
||||||
|
</view>
|
||||||
|
</u-popup>
|
||||||
|
|
||||||
<u-datetime-picker :show="showEndTimePicker" v-model="endTimePickerValue" mode="time" format="HH:mm"
|
|
||||||
@confirm="handleEndTimeConfirm" @cancel="showEndTimePicker = false"></u-datetime-picker>
|
|
||||||
</view>
|
</view>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@ -115,10 +194,12 @@
|
|||||||
} from '@/utils/timeFormat';
|
} from '@/utils/timeFormat';
|
||||||
import {
|
import {
|
||||||
applyType,
|
applyType,
|
||||||
usage,
|
usages,
|
||||||
thingTheme
|
thingThemes
|
||||||
} from '@/utils/dict.js'
|
} from '@/utils/dict.js'
|
||||||
|
import signature from '../../components/signature.vue';
|
||||||
export default {
|
export default {
|
||||||
|
components:{signature},
|
||||||
data() {
|
data() {
|
||||||
const now = new Date();
|
const now = new Date();
|
||||||
const year = now.getFullYear();
|
const year = now.getFullYear();
|
||||||
@ -136,21 +217,39 @@
|
|||||||
if (endHours >= 24) endHours = 0;
|
if (endHours >= 24) endHours = 0;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
chargeName: '',
|
||||||
|
chargePhone: '',
|
||||||
|
companyName: '',
|
||||||
|
userCard: '',
|
||||||
|
userName: '',
|
||||||
|
session:'',
|
||||||
|
num:'',
|
||||||
// 会议室图片数组
|
// 会议室图片数组
|
||||||
|
thingTheme: [],
|
||||||
|
thingThemes: thingThemes.getAll(),
|
||||||
|
usage:[],
|
||||||
|
usages:usages.getAll(),
|
||||||
list1: [],
|
list1: [],
|
||||||
detail: {},
|
detail: {},
|
||||||
|
signatureShow:false,
|
||||||
|
isSelfStudy: true, //dateTime,yearmonth
|
||||||
|
mode: 'datetime',
|
||||||
|
precision: null,
|
||||||
// 日历控制(默认隐藏)
|
// 日历控制(默认隐藏)
|
||||||
showCalendar: false,
|
showCalendar: false,
|
||||||
calendarKey: 0,
|
calendarKey: 0,
|
||||||
|
showApplyType: false,
|
||||||
|
applyTypeColumns: [
|
||||||
|
['个人申请', '单位申请']
|
||||||
|
],
|
||||||
|
applyName: '',
|
||||||
// 时间选择器控制
|
// 时间选择器控制
|
||||||
showStartTimePicker: false,
|
showStartTimePicker: false,
|
||||||
showEndTimePicker: false,
|
showEndTimePicker: false,
|
||||||
|
|
||||||
// 使用字符串格式的时间
|
// 使用字符串格式的时间
|
||||||
startTimePickerValue: `${startHours.toString().padStart(2, '0')}:${startMinutes.toString().padStart(2, '0')}`,
|
startTimePickerValue: `${year}-${month}-${day}`,
|
||||||
endTimePickerValue: `${endHours.toString().padStart(2, '0')}:${endMinutes.toString().padStart(2, '0')}`,
|
endTimePickerValue: ``,
|
||||||
|
|
||||||
// 日期相关
|
// 日期相关
|
||||||
selectedDate: `${year}-${month}-${day}`,
|
selectedDate: `${year}-${month}-${day}`,
|
||||||
@ -158,8 +257,8 @@
|
|||||||
maxDate: `${year + 1}-12-31`,
|
maxDate: `${year + 1}-12-31`,
|
||||||
|
|
||||||
// 时间相关
|
// 时间相关
|
||||||
selectedStartTime: `${startHours.toString().padStart(2, '0')}:${startMinutes.toString().padStart(2, '0')}`,
|
selectedStartTime: ``,
|
||||||
selectedEndTime: `${endHours.toString().padStart(2, '0')}:${endMinutes.toString().padStart(2, '0')}`,
|
selectedEndTime: ``,
|
||||||
startTimeValue: `${startHours.toString().padStart(2, '0')}:${startMinutes.toString().padStart(2, '0')}`,
|
startTimeValue: `${startHours.toString().padStart(2, '0')}:${startMinutes.toString().padStart(2, '0')}`,
|
||||||
endTimeValue: `${endHours.toString().padStart(2, '0')}:${endMinutes.toString().padStart(2, '0')}`,
|
endTimeValue: `${endHours.toString().padStart(2, '0')}:${endMinutes.toString().padStart(2, '0')}`,
|
||||||
|
|
||||||
@ -167,7 +266,7 @@
|
|||||||
remark: '',
|
remark: '',
|
||||||
|
|
||||||
noticeList: [
|
noticeList: [
|
||||||
'每次预订时间单位为小时,最少0.5小时起预订。',
|
'',
|
||||||
'使用优惠券支付,取消预订后优惠券会自动退还。',
|
'使用优惠券支付,取消预订后优惠券会自动退还。',
|
||||||
'使用微信、支付宝支付,取消订单后需要转社区运营人员进行退款。',
|
'使用微信、支付宝支付,取消订单后需要转社区运营人员进行退款。',
|
||||||
'系统不支持自动退款。',
|
'系统不支持自动退款。',
|
||||||
@ -176,30 +275,48 @@
|
|||||||
Id: '',
|
Id: '',
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
onReady() {
|
||||||
|
// 微信小程序需要用此写法
|
||||||
|
// this.$refs.startTimePicker.setFormatter(this.formatter)
|
||||||
|
// this.$refs.endTimePicker.setFormatter(this.formatter)
|
||||||
|
},
|
||||||
onLoad(options) {
|
onLoad(options) {
|
||||||
if (options && options.Id) {
|
if (options && options.Id) {
|
||||||
this.Id = options.Id;
|
this.Id = options.Id;
|
||||||
console.log(applyType.getAll())
|
this.mode = options.isSelfStudy === 'true' ? 'year-month' : 'datetime'
|
||||||
console.log("====", this.Id)
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
formattedSelectedDate() {
|
formattedSelectedDate() {
|
||||||
if (!this.selectedDate) return '请选择日期';
|
if (!this.selectedDate) return '请选择日期';
|
||||||
|
console.log(this.selectedDate)
|
||||||
|
// const date = new Date(this.selectedDate);
|
||||||
|
// const weekdays = ['周日', '周一', '周二', '周三', '周四', '周五', '周六'];
|
||||||
|
// const month = date.getMonth() + 1;
|
||||||
|
// const day = date.getDate();
|
||||||
|
// const weekday = weekdays[date.getDay()];
|
||||||
|
|
||||||
const date = new Date(this.selectedDate);
|
// return `${month}月${day}日 ${weekday}`;
|
||||||
const weekdays = ['周日', '周一', '周二', '周三', '周四', '周五', '周六'];
|
return this.selectedDate
|
||||||
const month = date.getMonth() + 1;
|
|
||||||
const day = date.getDate();
|
|
||||||
const weekday = weekdays[date.getDay()];
|
|
||||||
|
|
||||||
return `${month}月${day}日 ${weekday}`;
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
this.getDetail();
|
this.getDetail();
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
formatter(type, value) {
|
||||||
|
if (type === 'year') {
|
||||||
|
return `${value}年`
|
||||||
|
}
|
||||||
|
if (type === 'month') {
|
||||||
|
return `${value}月`
|
||||||
|
}
|
||||||
|
if (type === 'day') {
|
||||||
|
return `${value}日`
|
||||||
|
}
|
||||||
|
|
||||||
|
return value
|
||||||
|
},
|
||||||
// 获取详情页面
|
// 获取详情页面
|
||||||
async getDetail() {
|
async getDetail() {
|
||||||
try {
|
try {
|
||||||
@ -221,6 +338,17 @@
|
|||||||
console.error('获取详情失败:', err);
|
console.error('获取详情失败:', err);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
thingCheckboxChange(e) {
|
||||||
|
console.log(e);
|
||||||
|
},
|
||||||
|
usagesCheckboxChange(e){
|
||||||
|
console.log(e);
|
||||||
|
},
|
||||||
|
applyConfirm(e) {
|
||||||
|
console.log(e)
|
||||||
|
this.applyName = e.value[0]
|
||||||
|
this.showApplyType = false
|
||||||
|
},
|
||||||
handleDateConfirm(e) {
|
handleDateConfirm(e) {
|
||||||
let selectedDate;
|
let selectedDate;
|
||||||
|
|
||||||
@ -245,20 +373,27 @@
|
|||||||
},
|
},
|
||||||
|
|
||||||
handleStartTimeConfirm(e) {
|
handleStartTimeConfirm(e) {
|
||||||
this.selectedStartTime = e.value;
|
const date = new Date(e.value)
|
||||||
this.startTimePickerValue = e.value;
|
const dateString = this.mode === 'year-month' ? `${date.getFullYear()}-${date.getMonth()+1}` :
|
||||||
|
`${date.getFullYear()}-${date.getMonth()+1}-${date.getDate()} ${date.getHours()}:00`
|
||||||
|
this.selectedStartTime = dateString;
|
||||||
|
this.startTimePickerValue = dateString;
|
||||||
this.showStartTimePicker = false;
|
this.showStartTimePicker = false;
|
||||||
this.adjustEndTime();
|
// this.adjustEndTime();
|
||||||
},
|
},
|
||||||
|
|
||||||
handleEndTimeConfirm(e) {
|
handleEndTimeConfirm(e) {
|
||||||
this.selectedEndTime = e.value;
|
const date = new Date(e.value)
|
||||||
this.endTimePickerValue = e.value;
|
const dateString = this.mode === 'year-month' ? `${date.getFullYear()}-${date.getMonth()+1}` :
|
||||||
|
`${date.getFullYear()}-${date.getMonth()+1}-${date.getDate()} ${date.getHours()}:00`
|
||||||
|
this.selectedEndTime = dateString;
|
||||||
|
this.endTimePickerValue = dateString;
|
||||||
this.showEndTimePicker = false;
|
this.showEndTimePicker = false;
|
||||||
this.validateTime();
|
// this.validateTime();
|
||||||
},
|
},
|
||||||
|
|
||||||
adjustEndTime() {
|
adjustEndTime() {
|
||||||
|
console.log(this.selectedStartTime)
|
||||||
const [startH, startM] = this.selectedStartTime.split(':').map(Number);
|
const [startH, startM] = this.selectedStartTime.split(':').map(Number);
|
||||||
let [endH, endM] = this.selectedEndTime.split(':').map(Number);
|
let [endH, endM] = this.selectedEndTime.split(':').map(Number);
|
||||||
|
|
||||||
@ -448,42 +583,62 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* 时间选择区域 */
|
/* 时间选择区域 */
|
||||||
|
|
||||||
|
|
||||||
.time-section {
|
.time-section {
|
||||||
|
flex: 1;
|
||||||
margin-bottom: 32rpx;
|
margin-bottom: 32rpx;
|
||||||
|
|
||||||
|
.time-selector {
|
||||||
|
flex: 1
|
||||||
|
}
|
||||||
|
|
||||||
|
.time-label {
|
||||||
|
font-size: 26rpx;
|
||||||
|
color: #666;
|
||||||
|
margin-bottom: 8rpx;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.time-display {
|
||||||
|
padding: 20rpx;
|
||||||
|
background: #f8f9fa;
|
||||||
|
border-radius: 12rpx;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 28rpx;
|
||||||
|
color: #333;
|
||||||
|
height: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-header {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 16rpx;
|
||||||
|
font-size: 28rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-title {
|
||||||
|
font-size: 28rpx;
|
||||||
|
color: #333;
|
||||||
|
margin-left: 8rpx;
|
||||||
|
}
|
||||||
|
|
||||||
.time-picker {
|
.time-picker {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 16rpx;
|
gap: 16rpx;
|
||||||
}
|
}
|
||||||
|
|
||||||
.time-selector {
|
|
||||||
flex: 1;
|
|
||||||
|
|
||||||
.time-label {
|
|
||||||
font-size: 26rpx;
|
|
||||||
color: #666;
|
|
||||||
margin-bottom: 8rpx;
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
|
|
||||||
.time-display {
|
|
||||||
padding: 20rpx;
|
|
||||||
background: #f8f9fa;
|
|
||||||
border-radius: 12rpx;
|
|
||||||
text-align: center;
|
|
||||||
font-size: 28rpx;
|
|
||||||
color: #333;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.time-separator {
|
.time-separator {
|
||||||
color: #999;
|
color: #999;
|
||||||
font-size: 28rpx;
|
font-size: 28rpx;
|
||||||
padding-top: 28rpx;
|
padding-top: 28rpx;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* 新增备注区域 */
|
/* 新增备注区域 */
|
||||||
.remark-section {
|
.remark-section {
|
||||||
margin-top: 24rpx;
|
margin-top: 24rpx;
|
||||||
|
|||||||
@ -31,8 +31,7 @@
|
|||||||
<!-- 预约记录列表 -->
|
<!-- 预约记录列表 -->
|
||||||
<view class="order-list" v-else>
|
<view class="order-list" v-else>
|
||||||
<view v-if="orderList.length === 0" class="empty-container">
|
<view v-if="orderList.length === 0" class="empty-container">
|
||||||
<u-icon name="list" class="empty-icon" size="48"></u-icon>
|
<noData />
|
||||||
<text class="empty-text">暂无预约记录</text>
|
|
||||||
</view>
|
</view>
|
||||||
<view class="order-item" v-for="(item, index) in orderList" :key="index">
|
<view class="order-item" v-for="(item, index) in orderList" :key="index">
|
||||||
<view class="order-header" @click="goDetail(item.roomInfo || item)">
|
<view class="order-header" @click="goDetail(item.roomInfo || item)">
|
||||||
@ -105,9 +104,11 @@
|
|||||||
formatRelativeTime
|
formatRelativeTime
|
||||||
} from '@/utils/timeFormat';
|
} from '@/utils/timeFormat';
|
||||||
import instructionVue from '../../components/instruction.vue';
|
import instructionVue from '../../components/instruction.vue';
|
||||||
|
import noData from '../../components/noData.vue'
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
instructionVue
|
instructionVue,
|
||||||
|
noData
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
@ -129,7 +130,7 @@
|
|||||||
],
|
],
|
||||||
IMAGE_BASE_URL,
|
IMAGE_BASE_URL,
|
||||||
tabsReady: false,
|
tabsReady: false,
|
||||||
show: true,
|
show: false,
|
||||||
title: '使用说明',
|
title: '使用说明',
|
||||||
content: '',
|
content: '',
|
||||||
tabList: [{
|
tabList: [{
|
||||||
@ -253,7 +254,7 @@
|
|||||||
|
|
||||||
// 安全获取ID(兼容各种可能的字段名)
|
// 安全获取ID(兼容各种可能的字段名)
|
||||||
const id = item.id;
|
const id = item.id;
|
||||||
|
const isSelfStudy=item.title==='自习室'?'true':'false'
|
||||||
if (!id) {
|
if (!id) {
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
title: '会议室信息异常',
|
title: '会议室信息异常',
|
||||||
@ -263,7 +264,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
uni.navigateTo({
|
uni.navigateTo({
|
||||||
url: `/pages/meetingDetail/index?Id=${encodeURIComponent(id)}`, // 使用encodeURIComponent防止特殊字符问题
|
url: `/pages/meetingDetail/index?Id=${encodeURIComponent(id)}&isSelfStudy=${isSelfStudy}`, // 使用encodeURIComponent防止特殊字符问题
|
||||||
success: () => {
|
success: () => {
|
||||||
console.log('导航成功,ID:', id);
|
console.log('导航成功,ID:', id);
|
||||||
},
|
},
|
||||||
|
|||||||
145
pages/sign/pickerColor.vue
Normal file
145
pages/sign/pickerColor.vue
Normal file
@ -0,0 +1,145 @@
|
|||||||
|
<template>
|
||||||
|
<view v-show="isShow">
|
||||||
|
<view class="shade" @tap="hide">
|
||||||
|
<view class="pop">
|
||||||
|
<view class="list flex_col" v-for="(item,index) in colorArr" :key="index">
|
||||||
|
<view v-for="(v,i) in item" :key="i" :style="{'backgroundColor':v}" :data-color="v"
|
||||||
|
:data-index="index" :data-i="i" :class="{'active':(index==pickerArr[0] && i==pickerArr[1])}"
|
||||||
|
@tap.stop="picker"></view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: 'picker-color',
|
||||||
|
props: {
|
||||||
|
isShow: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
bottom: {
|
||||||
|
type: Number,
|
||||||
|
default: 0,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
colorArr: [
|
||||||
|
['#000000', '#111111', '#222222', '#333333', '#444444', '#666666', '#999999', '#CCCCCC', '#EEEEEE',
|
||||||
|
'#FFFFFF'
|
||||||
|
],
|
||||||
|
['#ff0000', '#ff0033', '#ff3399', '#ff33cc', '#cc00ff', '#9900ff', '#cc00cc', '#cc0099', '#cc3399',
|
||||||
|
'#cc0066'
|
||||||
|
],
|
||||||
|
['#cc3300', '#cc6600', '#ff9933', '#ff9966', '#ff9999', '#ff99cc', '#ff99ff', '#cc66ff', '#9966ff',
|
||||||
|
'#cc33ff'
|
||||||
|
],
|
||||||
|
['#663300', '#996600', '#996633', '#cc9900', '#a58800', '#cccc00', '#ffff66', '#ffff99', '#ffffcc',
|
||||||
|
'#ffcccc'
|
||||||
|
],
|
||||||
|
['#336600', '#669900', '#009900', '#009933', '#00cc00', '#66ff66', '#339933', '#339966', '#009999',
|
||||||
|
'#33cccc'
|
||||||
|
],
|
||||||
|
['#003366', '#336699', '#3366cc', '#0099ff', '#000099', '#0000cc', '#660066', '#993366', '#993333',
|
||||||
|
'#800000'
|
||||||
|
]
|
||||||
|
],
|
||||||
|
pickerColor: '',
|
||||||
|
pickerArr: [-1, -1]
|
||||||
|
};
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
picker(e) {
|
||||||
|
let data = e.currentTarget.dataset;
|
||||||
|
this.pickerColor = data.color;
|
||||||
|
this.pickerArr = [data.index, data.i];
|
||||||
|
this.$emit("callback", this.pickerColor);
|
||||||
|
},
|
||||||
|
hide() {
|
||||||
|
this.$emit("callback", '');
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.shade {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
background-color: rgba(0, 0, 0, 0.5);
|
||||||
|
z-index: 99;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center
|
||||||
|
}
|
||||||
|
|
||||||
|
.pop {
|
||||||
|
border-radius: 8px;
|
||||||
|
background-color: #fff;
|
||||||
|
z-index: 100;
|
||||||
|
padding: 12upx;
|
||||||
|
font-size: 32upx;
|
||||||
|
transform: rotate(90deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.flex_col {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
flex-wrap: nowrap;
|
||||||
|
justify-content: flex-start;
|
||||||
|
align-items: center;
|
||||||
|
align-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.list {
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
|
.list>view {
|
||||||
|
width: 60upx;
|
||||||
|
height: 60upx;
|
||||||
|
margin: 5upx;
|
||||||
|
box-sizing: border-box;
|
||||||
|
border-radius: 3px;
|
||||||
|
box-shadow: 0 0 2px #ccc;
|
||||||
|
}
|
||||||
|
|
||||||
|
.list .active {
|
||||||
|
box-shadow: 0 0 2px #09f;
|
||||||
|
transform: scale(1.05, 1.05);
|
||||||
|
}
|
||||||
|
|
||||||
|
.preview {
|
||||||
|
width: 180upx;
|
||||||
|
height: 60upx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.value {
|
||||||
|
margin: 0 40upx;
|
||||||
|
flex-grow: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ok {
|
||||||
|
width: 160upx;
|
||||||
|
height: 60upx;
|
||||||
|
line-height: 60upx;
|
||||||
|
text-align: center;
|
||||||
|
background-color: #ff9933;
|
||||||
|
color: #fff;
|
||||||
|
border-radius: 4px;
|
||||||
|
letter-spacing: 3px;
|
||||||
|
font-size: 32upx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ok:active {
|
||||||
|
background-color: rgb(255, 107, 34);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
596
pages/sign/sign.vue
Normal file
596
pages/sign/sign.vue
Normal file
@ -0,0 +1,596 @@
|
|||||||
|
<template>
|
||||||
|
<view>
|
||||||
|
<view class="wrapper">
|
||||||
|
<view class="handBtn">
|
||||||
|
<!-- #ifdef MP-WEIXIN -->
|
||||||
|
<image @click="selectColorEvent('black','#1A1A1A')"
|
||||||
|
:src="selectColor === 'black' ? '/static/other/color_black_selected.png' : '/static/other/color_black.png'"
|
||||||
|
class="black-select"></image>
|
||||||
|
<image @click="selectColorEvent('red','#ca262a')"
|
||||||
|
:src="selectColor === 'red' ? '/static/other/color_red_selected.png' : '/static/other/color_red.png'"
|
||||||
|
class="red-select"></image>
|
||||||
|
<!-- #endif -->
|
||||||
|
<!-- #ifndef MP-WEIXIN -->
|
||||||
|
<div class="color_pic" :style="{background:lineColor}" @click="showPickerColor=true"></div>
|
||||||
|
<!-- #endif -->
|
||||||
|
<button @click="clear" class="delBtn">清空</button>
|
||||||
|
<button @click="saveCanvasAsImg" class="saveBtn">保存</button>
|
||||||
|
<button @click="previewCanvasImg" class="previewBtn">预览</button>
|
||||||
|
<button @click="undo" class="undoBtn">撤销</button>
|
||||||
|
<button @click="subCanvas" class="subBtn">完成</button>
|
||||||
|
</view>
|
||||||
|
<view class="handCenter">
|
||||||
|
<canvas class="handWriting" :disable-scroll="true" @touchstart="uploadScaleStart"
|
||||||
|
@touchmove="uploadScaleMove" @touchend="uploadScaleEnd" canvas-id="handWriting"></canvas>
|
||||||
|
</view>
|
||||||
|
<view class="handRight">
|
||||||
|
<view class="handTitle">请签名</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<pickerColor :isShow="showPickerColor" :bottom="0" @callback='getPickerColor' />
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import pickerColor from "./pickerColor.vue"
|
||||||
|
export default {
|
||||||
|
components: {
|
||||||
|
pickerColor
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
showPickerColor: false,
|
||||||
|
ctx: '',
|
||||||
|
canvasWidth: 0,
|
||||||
|
canvasHeight: 0,
|
||||||
|
selectColor: 'black',
|
||||||
|
lineColor: '#1A1A1A',
|
||||||
|
points: [],
|
||||||
|
historyList: [],
|
||||||
|
canAddHistory: true,
|
||||||
|
getImagePath: () => {
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
uni.canvasToTempFilePath({
|
||||||
|
canvasId: 'handWriting',
|
||||||
|
fileType: 'png',
|
||||||
|
quality: 1, //图片质量
|
||||||
|
success: res => resolve(res.tempFilePath),
|
||||||
|
})
|
||||||
|
})
|
||||||
|
},
|
||||||
|
toDataURL: void 0,
|
||||||
|
requestAnimationFrame: void 0,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
props: { //可用于修改的参数放在props里 也可单独放在外面做成组件调用 传值
|
||||||
|
minSpeed: { //画笔最小速度
|
||||||
|
type: Number,
|
||||||
|
default: 1.5
|
||||||
|
},
|
||||||
|
minWidth: { //线条最小粗度
|
||||||
|
type: Number,
|
||||||
|
default: 3,
|
||||||
|
},
|
||||||
|
maxWidth: { //线条最大粗度
|
||||||
|
type: Number,
|
||||||
|
default: 10
|
||||||
|
},
|
||||||
|
openSmooth: { //开启平滑线条(笔锋)
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
maxHistoryLength: { //历史最大长度
|
||||||
|
type: Number,
|
||||||
|
default: 20
|
||||||
|
},
|
||||||
|
maxWidthDiffRate: { //最大差异率
|
||||||
|
type: Number,
|
||||||
|
default: 20
|
||||||
|
},
|
||||||
|
bgColor: { //背景色
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
},
|
||||||
|
onLoad() {
|
||||||
|
this.ctx = uni.createCanvasContext("handWriting");
|
||||||
|
this.$nextTick(() => {
|
||||||
|
uni.createSelectorQuery().select('.handCenter').boundingClientRect(rect => {
|
||||||
|
this.canvasWidth = rect.width;
|
||||||
|
this.canvasHeight = rect.height;
|
||||||
|
this.drawBgColor()
|
||||||
|
})
|
||||||
|
.exec();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
getPickerColor(color) {
|
||||||
|
this.showPickerColor = false;
|
||||||
|
if (color) {
|
||||||
|
this.lineColor = color;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// 笔迹开始
|
||||||
|
uploadScaleStart(e) {
|
||||||
|
this.canAddHistory = true
|
||||||
|
this.ctx.setStrokeStyle(this.lineColor)
|
||||||
|
this.ctx.setLineCap("round") //'butt'、'round'、'square'
|
||||||
|
},
|
||||||
|
// 笔迹移动
|
||||||
|
uploadScaleMove(e) {
|
||||||
|
let temX = e.changedTouches[0].x
|
||||||
|
let temY = e.changedTouches[0].y
|
||||||
|
this.initPoint(temX, temY)
|
||||||
|
this.onDraw()
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* 触摸结束
|
||||||
|
*/
|
||||||
|
uploadScaleEnd() {
|
||||||
|
this.canAddHistory = true;
|
||||||
|
this.points = [];
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* 记录点属性
|
||||||
|
*/
|
||||||
|
initPoint(x, y) {
|
||||||
|
var point = {
|
||||||
|
x: x,
|
||||||
|
y: y,
|
||||||
|
t: Date.now()
|
||||||
|
};
|
||||||
|
var prePoint = this.points.slice(-1)[0];
|
||||||
|
if (prePoint && (prePoint.t === point.t || prePoint.x === x && prePoint.y === y)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (prePoint && this.openSmooth) {
|
||||||
|
var prePoint2 = this.points.slice(-2, -1)[0];
|
||||||
|
point.distance = Math.sqrt(Math.pow(point.x - prePoint.x, 2) + Math.pow(point.y - prePoint.y, 2));
|
||||||
|
point.speed = point.distance / (point.t - prePoint.t || 0.1);
|
||||||
|
point.lineWidth = this.getLineWidth(point.speed);
|
||||||
|
if (prePoint2 && prePoint2.lineWidth && prePoint.lineWidth) {
|
||||||
|
var rate = (point.lineWidth - prePoint.lineWidth) / prePoint.lineWidth;
|
||||||
|
var maxRate = this.maxWidthDiffRate / 100;
|
||||||
|
maxRate = maxRate > 1 ? 1 : maxRate < 0.01 ? 0.01 : maxRate;
|
||||||
|
if (Math.abs(rate) > maxRate) {
|
||||||
|
var per = rate > 0 ? maxRate : -maxRate;
|
||||||
|
point.lineWidth = prePoint.lineWidth * (1 + per);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.points.push(point);
|
||||||
|
this.points = this.points.slice(-3);
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* @param {Object}
|
||||||
|
* 线宽
|
||||||
|
*/
|
||||||
|
getLineWidth(speed) {
|
||||||
|
var minSpeed = this.minSpeed > 10 ? 10 : this.minSpeed < 1 ? 1 : this.minSpeed; //1.5
|
||||||
|
var addWidth = (this.maxWidth - this.minWidth) * speed / minSpeed;
|
||||||
|
var lineWidth = Math.max(this.maxWidth - addWidth, this.minWidth);
|
||||||
|
return Math.min(lineWidth, this.maxWidth);
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* 绘画逻辑
|
||||||
|
*/
|
||||||
|
onDraw() {
|
||||||
|
if (this.points.length < 2) return;
|
||||||
|
this.addHistory();
|
||||||
|
var point = this.points.slice(-1)[0];
|
||||||
|
var prePoint = this.points.slice(-2, -1)[0];
|
||||||
|
let that = this
|
||||||
|
var onDraw = function onDraw() {
|
||||||
|
if (that.openSmooth) {
|
||||||
|
that.drawSmoothLine(prePoint, point);
|
||||||
|
} else {
|
||||||
|
that.drawNoSmoothLine(prePoint, point);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if (typeof this.requestAnimationFrame === 'function') {
|
||||||
|
this.requestAnimationFrame(function() {
|
||||||
|
return onDraw();
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
onDraw();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
//添加历史图片地址
|
||||||
|
addHistory() {
|
||||||
|
if (!this.maxHistoryLength || !this.canAddHistory) return;
|
||||||
|
this.canAddHistory = false;
|
||||||
|
if (!this.getImagePath) {
|
||||||
|
this.historyList.length++;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
//历史地址 (暂时无用)
|
||||||
|
let that = this
|
||||||
|
that.getImagePath().then(function(url) {
|
||||||
|
if (url) {
|
||||||
|
that.historyList.push(url)
|
||||||
|
that.historyList = that.historyList.slice(-that.maxHistoryLength);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
//画平滑线
|
||||||
|
drawSmoothLine(prePoint, point) {
|
||||||
|
var dis_x = point.x - prePoint.x;
|
||||||
|
var dis_y = point.y - prePoint.y;
|
||||||
|
|
||||||
|
if (Math.abs(dis_x) + Math.abs(dis_y) <= 2) {
|
||||||
|
point.lastX1 = point.lastX2 = prePoint.x + dis_x * 0.5;
|
||||||
|
point.lastY1 = point.lastY2 = prePoint.y + dis_y * 0.5;
|
||||||
|
} else {
|
||||||
|
point.lastX1 = prePoint.x + dis_x * 0.3;
|
||||||
|
point.lastY1 = prePoint.y + dis_y * 0.3;
|
||||||
|
point.lastX2 = prePoint.x + dis_x * 0.7;
|
||||||
|
point.lastY2 = prePoint.y + dis_y * 0.7;
|
||||||
|
}
|
||||||
|
point.perLineWidth = (prePoint.lineWidth + point.lineWidth) / 2;
|
||||||
|
if (typeof prePoint.lastX1 === 'number') {
|
||||||
|
this.drawCurveLine(prePoint.lastX2, prePoint.lastY2, prePoint.x, prePoint.y, point.lastX1, point
|
||||||
|
.lastY1, point.perLineWidth);
|
||||||
|
if (prePoint.isFirstPoint) return;
|
||||||
|
if (prePoint.lastX1 === prePoint.lastX2 && prePoint.lastY1 === prePoint.lastY2) return;
|
||||||
|
var data = this.getRadianData(prePoint.lastX1, prePoint.lastY1, prePoint.lastX2, prePoint.lastY2);
|
||||||
|
var points1 = this.getRadianPoints(data, prePoint.lastX1, prePoint.lastY1, prePoint.perLineWidth / 2);
|
||||||
|
var points2 = this.getRadianPoints(data, prePoint.lastX2, prePoint.lastY2, point.perLineWidth / 2);
|
||||||
|
this.drawTrapezoid(points1[0], points2[0], points2[1], points1[1]);
|
||||||
|
} else {
|
||||||
|
point.isFirstPoint = true;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
//画不平滑线
|
||||||
|
drawNoSmoothLine(prePoint, point) {
|
||||||
|
point.lastX = prePoint.x + (point.x - prePoint.x) * 0.5;
|
||||||
|
point.lastY = prePoint.y + (point.y - prePoint.y) * 0.5;
|
||||||
|
if (typeof prePoint.lastX === 'number') {
|
||||||
|
this.drawCurveLine(prePoint.lastX, prePoint.lastY, prePoint.x, prePoint.y, point.lastX, point.lastY,
|
||||||
|
this.maxWidth);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
//画线
|
||||||
|
drawCurveLine(x1, y1, x2, y2, x3, y3, lineWidth) {
|
||||||
|
lineWidth = Number(lineWidth.toFixed(1));
|
||||||
|
this.ctx.setLineWidth && this.ctx.setLineWidth(lineWidth);
|
||||||
|
this.ctx.lineWidth = lineWidth;
|
||||||
|
this.ctx.beginPath();
|
||||||
|
this.ctx.moveTo(Number(x1.toFixed(1)), Number(y1.toFixed(1)));
|
||||||
|
this.ctx.quadraticCurveTo(Number(x2.toFixed(1)), Number(y2.toFixed(1)), Number(x3.toFixed(1)), Number(y3
|
||||||
|
.toFixed(1)));
|
||||||
|
this.ctx.stroke();
|
||||||
|
this.ctx.draw && this.ctx.draw(true);
|
||||||
|
},
|
||||||
|
//画梯形
|
||||||
|
drawTrapezoid(point1, point2, point3, point4) {
|
||||||
|
this.ctx.beginPath();
|
||||||
|
this.ctx.moveTo(Number(point1.x.toFixed(1)), Number(point1.y.toFixed(1)));
|
||||||
|
this.ctx.lineTo(Number(point2.x.toFixed(1)), Number(point2.y.toFixed(1)));
|
||||||
|
this.ctx.lineTo(Number(point3.x.toFixed(1)), Number(point3.y.toFixed(1)));
|
||||||
|
this.ctx.lineTo(Number(point4.x.toFixed(1)), Number(point4.y.toFixed(1)));
|
||||||
|
this.ctx.setFillStyle && this.ctx.setFillStyle(this.lineColor);
|
||||||
|
this.ctx.fillStyle = this.lineColor;
|
||||||
|
this.ctx.fill();
|
||||||
|
this.ctx.draw && this.ctx.draw(true);
|
||||||
|
},
|
||||||
|
//获取弧度
|
||||||
|
getRadianData(x1, y1, x2, y2) {
|
||||||
|
var dis_x = x2 - x1;
|
||||||
|
var dis_y = y2 - y1;
|
||||||
|
if (dis_x === 0) {
|
||||||
|
return {
|
||||||
|
val: 0,
|
||||||
|
pos: -1
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if (dis_y === 0) {
|
||||||
|
return {
|
||||||
|
val: 0,
|
||||||
|
pos: 1
|
||||||
|
};
|
||||||
|
}
|
||||||
|
var val = Math.abs(Math.atan(dis_y / dis_x));
|
||||||
|
if (x2 > x1 && y2 < y1 || x2 < x1 && y2 > y1) {
|
||||||
|
return {
|
||||||
|
val: val,
|
||||||
|
pos: 1
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
val: val,
|
||||||
|
pos: -1
|
||||||
|
};
|
||||||
|
},
|
||||||
|
//获取弧度点
|
||||||
|
getRadianPoints(radianData, x, y, halfLineWidth) {
|
||||||
|
if (radianData.val === 0) {
|
||||||
|
if (radianData.pos === 1) {
|
||||||
|
return [{
|
||||||
|
x: x,
|
||||||
|
y: y + halfLineWidth
|
||||||
|
}, {
|
||||||
|
x: x,
|
||||||
|
y: y - halfLineWidth
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
return [{
|
||||||
|
y: y,
|
||||||
|
x: x + halfLineWidth
|
||||||
|
}, {
|
||||||
|
y: y,
|
||||||
|
x: x - halfLineWidth
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
var dis_x = Math.sin(radianData.val) * halfLineWidth;
|
||||||
|
var dis_y = Math.cos(radianData.val) * halfLineWidth;
|
||||||
|
if (radianData.pos === 1) {
|
||||||
|
return [{
|
||||||
|
x: x + dis_x,
|
||||||
|
y: y + dis_y
|
||||||
|
}, {
|
||||||
|
x: x - dis_x,
|
||||||
|
y: y - dis_y
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
return [{
|
||||||
|
x: x + dis_x,
|
||||||
|
y: y - dis_y
|
||||||
|
}, {
|
||||||
|
x: x - dis_x,
|
||||||
|
y: y + dis_y
|
||||||
|
}];
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* 背景色
|
||||||
|
*/
|
||||||
|
drawBgColor() {
|
||||||
|
if (!this.bgColor) return;
|
||||||
|
this.ctx.setFillStyle && this.ctx.setFillStyle(this.bgColor);
|
||||||
|
this.ctx.fillStyle = this.bgColor;
|
||||||
|
this.ctx.fillRect(0, 0, this.canvasWidth, this.canvasHeight);
|
||||||
|
this.ctx.draw && this.ctx.draw(true);
|
||||||
|
},
|
||||||
|
//图片绘制
|
||||||
|
drawByImage(url) {
|
||||||
|
this.ctx.clearRect(0, 0, this.canvasWidth, this.canvasHeight);
|
||||||
|
try {
|
||||||
|
this.ctx.drawImage(url, 0, 0, this.canvasWidth, this.canvasHeight);
|
||||||
|
this.ctx.draw && this.ctx.draw(true);
|
||||||
|
} catch (e) {
|
||||||
|
this.historyList.length = 0;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* 清空
|
||||||
|
*/
|
||||||
|
clear() {
|
||||||
|
this.ctx.clearRect(0, 0, this.canvasWidth, this.canvasHeight);
|
||||||
|
this.ctx.draw && this.ctx.draw();
|
||||||
|
this.drawBgColor();
|
||||||
|
this.historyList.length = 0;
|
||||||
|
},
|
||||||
|
//撤消
|
||||||
|
undo() {
|
||||||
|
if (!this.getImagePath || !this.historyList.length) return;
|
||||||
|
var pngURL = this.historyList.splice(-1)[0];
|
||||||
|
this.drawByImage(pngURL);
|
||||||
|
if (this.historyList.length === 0) {
|
||||||
|
this.clear();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
//是否为空
|
||||||
|
isEmpty() {
|
||||||
|
return this.historyList.length === 0;
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* @param {Object} str
|
||||||
|
* @param {Object} color
|
||||||
|
* 选择颜色
|
||||||
|
*/
|
||||||
|
selectColorEvent(str, color) {
|
||||||
|
this.selectColor = str;
|
||||||
|
this.lineColor = color;
|
||||||
|
this.ctx.setStrokeStyle(this.lineColor)
|
||||||
|
},
|
||||||
|
//完成
|
||||||
|
subCanvas() {
|
||||||
|
if (this.isEmpty()) {
|
||||||
|
uni.showToast({
|
||||||
|
title: '没有任何绘制内容哦',
|
||||||
|
icon: 'none',
|
||||||
|
});
|
||||||
|
return
|
||||||
|
}
|
||||||
|
uni.canvasToTempFilePath({
|
||||||
|
canvasId: 'handWriting',
|
||||||
|
fileType: 'png',
|
||||||
|
quality: 1, //图片质量
|
||||||
|
success(res) {
|
||||||
|
uni.showToast({
|
||||||
|
title: '以保存'
|
||||||
|
});
|
||||||
|
//保存到系统相册
|
||||||
|
uni.saveImageToPhotosAlbum({
|
||||||
|
filePath: res.tempFilePath,
|
||||||
|
success(res) {
|
||||||
|
uni.showToast({
|
||||||
|
title: '已成功保存到相册',
|
||||||
|
duration: 2000
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
//保存到相册
|
||||||
|
saveCanvasAsImg() {
|
||||||
|
uni.canvasToTempFilePath({
|
||||||
|
canvasId: 'handWriting',
|
||||||
|
fileType: 'png',
|
||||||
|
quality: 1, //图片质量
|
||||||
|
success(res) {
|
||||||
|
uni.saveImageToPhotosAlbum({
|
||||||
|
filePath: res.tempFilePath,
|
||||||
|
success(res) {
|
||||||
|
uni.showToast({
|
||||||
|
title: '已保存到相册',
|
||||||
|
duration: 2000
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
//预览
|
||||||
|
previewCanvasImg() {
|
||||||
|
uni.canvasToTempFilePath({
|
||||||
|
canvasId: 'handWriting',
|
||||||
|
fileType: 'jpg',
|
||||||
|
quality: 1, //图片质量
|
||||||
|
success(res) {
|
||||||
|
uni.previewImage({
|
||||||
|
urls: [res.tempFilePath] //预览图片 数组
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
page {
|
||||||
|
background: #fbfbfb;
|
||||||
|
height: auto;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wrapper {
|
||||||
|
width: 100%;
|
||||||
|
height: 95vh;
|
||||||
|
margin: 40rpx 0;
|
||||||
|
overflow: hidden;
|
||||||
|
display: flex;
|
||||||
|
align-content: center;
|
||||||
|
flex-direction: row;
|
||||||
|
justify-content: center;
|
||||||
|
font-size: 28rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.handWriting {
|
||||||
|
background: #fff;
|
||||||
|
width: 100%;
|
||||||
|
height: 95vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
.handRight {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.handCenter {
|
||||||
|
border: 4rpx dashed #e9e9e9;
|
||||||
|
flex: 5;
|
||||||
|
overflow: hidden;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
.handTitle {
|
||||||
|
transform: rotate(90deg);
|
||||||
|
flex: 1;
|
||||||
|
color: #666;
|
||||||
|
}
|
||||||
|
|
||||||
|
.handBtn button {
|
||||||
|
font-size: 28rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.handBtn {
|
||||||
|
height: 95vh;
|
||||||
|
display: inline-flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-content: space-between;
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.delBtn {
|
||||||
|
position: absolute;
|
||||||
|
top: 250rpx;
|
||||||
|
left: 0rpx;
|
||||||
|
transform: rotate(90deg);
|
||||||
|
color: #666;
|
||||||
|
}
|
||||||
|
|
||||||
|
.delBtn image {
|
||||||
|
position: absolute;
|
||||||
|
top: 13rpx;
|
||||||
|
left: 25rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.subBtn {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 52rpx;
|
||||||
|
left: -3rpx;
|
||||||
|
display: inline-flex;
|
||||||
|
transform: rotate(90deg);
|
||||||
|
background: #008ef6;
|
||||||
|
color: #fff;
|
||||||
|
margin-bottom: 30rpx;
|
||||||
|
text-align: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*Peach - 新增 - 保存*/
|
||||||
|
|
||||||
|
.saveBtn {
|
||||||
|
position: absolute;
|
||||||
|
top: 375rpx;
|
||||||
|
left: 0rpx;
|
||||||
|
transform: rotate(90deg);
|
||||||
|
color: #666;
|
||||||
|
}
|
||||||
|
|
||||||
|
.previewBtn {
|
||||||
|
position: absolute;
|
||||||
|
top: 500rpx;
|
||||||
|
left: 0rpx;
|
||||||
|
transform: rotate(90deg);
|
||||||
|
color: #666;
|
||||||
|
}
|
||||||
|
|
||||||
|
.undoBtn {
|
||||||
|
position: absolute;
|
||||||
|
top: 625rpx;
|
||||||
|
left: 0rpx;
|
||||||
|
transform: rotate(90deg);
|
||||||
|
color: #666;
|
||||||
|
}
|
||||||
|
|
||||||
|
.black-select {
|
||||||
|
width: 60rpx;
|
||||||
|
height: 60rpx;
|
||||||
|
position: absolute;
|
||||||
|
top: 30rpx;
|
||||||
|
left: 25rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.red-select {
|
||||||
|
width: 60rpx;
|
||||||
|
height: 60rpx;
|
||||||
|
position: absolute;
|
||||||
|
top: 140rpx;
|
||||||
|
left: 25rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.color_pic {
|
||||||
|
width: 70rpx;
|
||||||
|
height: 70rpx;
|
||||||
|
border-radius: 25px;
|
||||||
|
position: absolute;
|
||||||
|
top: 60rpx;
|
||||||
|
left: 18rpx;
|
||||||
|
border: 1px solid #ddd;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
Binary file not shown.
|
Before Width: | Height: | Size: 17 KiB |
BIN
static/imgs/noData.png
Normal file
BIN
static/imgs/noData.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 6.0 KiB |
BIN
static/other/color_black.png
Normal file
BIN
static/other/color_black.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 5.9 KiB |
BIN
static/other/color_black_selected.png
Normal file
BIN
static/other/color_black_selected.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.6 KiB |
BIN
static/other/color_red.png
Normal file
BIN
static/other/color_red.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 5.7 KiB |
BIN
static/other/color_red_selected.png
Normal file
BIN
static/other/color_red_selected.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.2 KiB |
@ -5,13 +5,13 @@ export const applyType=new dictManage([
|
|||||||
{value:2,name:'个人申请'},
|
{value:2,name:'个人申请'},
|
||||||
])
|
])
|
||||||
//使用情况
|
//使用情况
|
||||||
export const usage=new dictManage([
|
export const usages=new dictManage([
|
||||||
{value:1,name:'已复位'},
|
{value:1,name:'已复位'},
|
||||||
{value:2,name:'设置设备需维修'},
|
{value:2,name:'设置设备需维修'},
|
||||||
{value:1,name:'设施设备需照价赔偿'}
|
{value:1,name:'设施设备需照价赔偿'}
|
||||||
])
|
])
|
||||||
//事由主题
|
//事由主题
|
||||||
export const thingTheme=new dictManage([
|
export const thingThemes=new dictManage([
|
||||||
{value:1,name:'开会'},
|
{value:1,name:'开会'},
|
||||||
{value:2,name:'学术报告'},
|
{value:2,name:'学术报告'},
|
||||||
{value:3,name:'活动'},
|
{value:3,name:'活动'},
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user