This commit is contained in:
qiuyuan 2025-08-06 18:15:14 +08:00
commit 181cd1ec82
10 changed files with 549 additions and 192 deletions

23
App.vue
View File

@ -1,5 +1,28 @@
<script>
export default {
globalData: {
isLogin: false,
userInfo: null,
applyInfo:null
},
methods: {
checkLogin() {
return new Promise((resolve) => {
if (this.globalData.isLogin) {
resolve(true);
} else {
// token
const token = uni.getStorageSync('token');
if (token) {
this.globalData.isLogin = true;
resolve(true);
} else {
resolve(false);
}
}
});
}
},
onLaunch: function() {
console.log('App Launch')
},

View File

@ -4,6 +4,8 @@ import App from './App'
import Vue from 'vue'
import uView from "uview-ui";
Vue.use(uView);
// 2. 引入 uView 样式
import 'uview-ui/index.scss';
import './uni.promisify.adaptor'
uni.$u.config.unit = 'rpx'
Vue.config.productionTip = false

View File

@ -210,6 +210,12 @@
"style": {
"navigationBarTitleText": "电子签名"
}
},
{
"path": "pages/docList/index",
"style": {
"navigationBarTitleText": "文件下载"
}
}
],

79
pages/docList/index.vue Normal file
View File

@ -0,0 +1,79 @@
<template>
<view class="doc-page">
<view class="doc-content">
<view class="doc-file" v-for="item of docList" @click="downLoadFile(item)">
<image src="/static/imgs/word.png" alt="" srcset="" class="doc-img"/>
<view class="doc-name">{{item.name}}</view>
</view>
</view>
</view>
</template>
<script>
import {IMAGE_BASE_URL,BASE_URL} from '@/utils/config';
import {downloadPdfFiles} from '@/utils/download.js'
export default{
data(){
return{
docList:[],
nameList:{
'applyPdf':'申请表申请表申请表申请表申请表申请表申请表申请表申请表申请表',
'covenantPdf':'协议书'
}
}
},
onLoad(option) {
console.log(option);
console.log(JSON.parse(option.files));
const obj=JSON.parse(option.files)
this.docList=[
{name:'近山社区城市青年会客厅使用说明及申请表',url:BASE_URL+obj.covenantPdf},
{name:`${JSON.parse(option.isSelfStudy)?'近山社区自习室个人使用承诺书':'近山社区城市青年会客厅安全使用承诺书'}`,url:BASE_URL+obj.applyPdf},
]
},
methods:{
async downLoadFile(fileUrl){
const result = await downloadPdfFiles(fileUrl);
if(result.success==true){
// uni.navigateTo({
// url: `/pages/meetingList/index`
// });
}
}
}
}
</script>
<style scoped>
.doc-page{
width: 100vw;
height: 100vh;
/* margin: 10rpx; */
}
.doc-content{
margin: 10px;
}
.doc-file{
padding: 20rpx 10rpx;
display: flex;
align-items: center;
/* margin: 10px; */
/* border-bottom: 1px solid #c9c9c9; */
}
.doc-file:not(:last-child){
border-bottom: 1px solid #c9c9c9;
}
.doc-img{
width: 35px;
height: 35px;
}
.doc-name{
flex: 1;
color: #666666;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
</style>

View File

@ -39,50 +39,53 @@
<text class="section-title">事由主题</text>
</view>
<view>
<checkbox-group @change="thingCheckboxChange" v-model="thingTheme">
<radio-group @change="thingCheckboxChange">
<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>
<radio :value="item.value" style="transform:scale(0.7)"
:checked="item.value === applyTheme" />
<text style="font-size: 12px;color: #333333;">{{item.name}}</text>
</label>
</checkbox-group>
</radio-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="date-display" @click="showApplyTypeClick()">
<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;">
<view v-show="applyName=='单位申请'">
<view style="margin-top: 10px;background-color: #f8f9fa;">
<u--input placeholder="请输入单位全称" border="null" v-model="companyName"></u--input>
</view>
<view class="" style="margin-top: 10px;background-color: #f8f9fa;">
<u--input placeholder="请输入负责人姓名" border="null" v-model="concatName"></u--input>
</view>
<view class="" style="margin-top: 10px;background-color: #f8f9fa;">
<u--input placeholder="请输入负责人电话" border="null" type='tel' v-model="concatPhone"></u--input>
</view>
</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>
<u--input placeholder="请输入手机号" border="null" type="tel" v-model="userPhone"></u--input>
</view>
<view class="" style="margin-top: 10px;background-color: #f8f9fa;">
<u--input placeholder="请输入身份证号" border="null" type="idcard" v-model="userCardId"></u--input>
</view>
<view class="" style="margin-top: 10px;background-color: #f8f9fa;">
<u--input placeholder="请输入申请人地址" border="null" v-model="userAddress"></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>
@ -91,7 +94,7 @@
<view>
<view class="" style="margin-top: 10px;background-color: #f8f9fa;">
<u--input placeholder="请输入场次" border="null" v-model="session"></u--input>
<u--input placeholder="请输入场次" border="null" v-model="counter"></u--input>
</view>
<view class="" style="margin-top: 10px;background-color: #f8f9fa;">
<u--input placeholder="请输入人数" border="null" v-model="num"></u--input>
@ -108,19 +111,19 @@
<view class="time-selector" @click="showStartTimePicker = true">
<text class="time-label">开始</text>
<view class="time-display">
{{ selectedStartTime }}
{{ startTime }}
</view>
</view>
<view class="time-separator"></view>
<view class="time-selector" @click="showEndTimePicker = true">
<text class="time-label">结束</text>
<view class="time-display">
{{ selectedEndTime }}
{{ endTime }}
</view>
</view>
</view>
</view>
<view class="date-section">
<!-- <view class="date-section">
<view class="section-header">
<u-icon name="list-dot" size="38" color="#2979ff"></u-icon>
<text class="section-title">使用情况</text>
@ -133,27 +136,20 @@
</label>
</checkbox-group>
</view>
</view>
</view>
<!-- 预定须知卡片 -->
<!-- <view class="notice-card">
<view class="card-header">
<u-icon name="info-circle" size="34" color="#2979ff"></u-icon>
<text class="card-title">预订须知</text>
</view>
<view class="notice-list">
<view class="notice-item" v-for="(item, index) in noticeList" :key="index">
<text class="notice-index">{{ index + 1 }}.</text>
<text class="notice-content">{{ item }}</text>
</view>
</view>
</view> -->
<view class="date-section">
<view class="section-header">
<u-icon name="list-dot" size="38" color="#2979ff"></u-icon>
<text class="section-title">申请理由</text>
</view>
<view>
<u--input placeholder="请输入申请理由" border="null" v-model="reason"></u--input>
</view>
</view>
</view>
<!-- 底部固定操作栏 -->
<view class="action-bar">
<!-- <u-button type="primary" shape="circle" @click="handleBook">立即预订</u-button> -->
<u-button type="primary" shape="circle" @click="signatureShow=true">立即预订</u-button>
<u-button type="primary" shape="circle" @click="handleBook">立即预订</u-button>
</view>
<!-- 日历组件 -->
@ -170,12 +166,6 @@
<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>
</view>
</template>
@ -197,9 +187,9 @@
usages,
thingThemes
} from '@/utils/dict.js'
import signature from '../../components/signature.vue';
// import signature from '../sign/sign.vue';
export default {
components:{signature},
data() {
const now = new Date();
const year = now.getFullYear();
@ -217,15 +207,29 @@
if (endHours >= 24) endHours = 0;
return {
chargeName: '',
chargePhone: '',
companyName: '',
userCard: '',
userName: '',
session:'',
num:'',
applyRules: {
userPhone: '申请人手机号',
userName: '申请人姓名',
userCardId: '申请人身份证号',
userAddress: '申请人地址',
concatName: '负责人姓名',
concatPhone: '负责人电话',
companyName: '公司名称',
startTime: '开始时间',
endTime: '结束时间',
num: "人数",
counter: '场次'
},
userName: '丁',
userPhone: "13667879876",
userCardId: '1234',
userAddress: '北京二环',
counter: '10',
num: '100',
//
thingTheme: [],
applyTheme: 1,
applyArea:1,
thingThemes: thingThemes.getAll(),
usage: [],
usages: usages.getAll(),
@ -235,6 +239,9 @@
isSelfStudy: true, //dateTime,yearmonth
mode: 'datetime',
precision: null,
concatPhone: '',
reason: '',
applySign: '', //
//
showCalendar: false,
calendarKey: 0,
@ -242,7 +249,10 @@
applyTypeColumns: [
['个人申请', '单位申请']
],
applyName: '',
applyType: 1, //1 2
applyName: '个人申请',
concatName: '', //
concatPhone: '', //
//
showStartTimePicker: false,
showEndTimePicker: false,
@ -257,8 +267,8 @@
maxDate: `${year + 1}-12-31`,
//
selectedStartTime: ``,
selectedEndTime: ``,
startTime: `2025-08`,
endTime: `2025-10`,
startTimeValue: `${startHours.toString().padStart(2, '0')}:${startMinutes.toString().padStart(2, '0')}`,
endTimeValue: `${endHours.toString().padStart(2, '0')}:${endMinutes.toString().padStart(2, '0')}`,
@ -275,14 +285,10 @@
Id: '',
};
},
onReady() {
//
// this.$refs.startTimePicker.setFormatter(this.formatter)
// this.$refs.endTimePicker.setFormatter(this.formatter)
},
onLoad(options) {
if (options && options.Id) {
this.Id = options.Id;
this.isSelfStudy=JSON.parse(options.isSelfStudy)
this.mode = options.isSelfStudy === 'true' ? 'year-month' : 'datetime'
}
},
@ -304,18 +310,9 @@
this.getDetail();
},
methods: {
formatter(type, value) {
if (type === 'year') {
return `${value}`
}
if (type === 'month') {
return `${value}`
}
if (type === 'day') {
return `${value}`
}
return value
showApplyTypeClick(){
if(this.isSelfStudy) return
this.showApplyType=true
},
//
async getDetail() {
@ -339,15 +336,27 @@
}
},
thingCheckboxChange(e) {
console.log(e);
this.applyTheme = JSON.parse(e.detail.value)
},
areaCheckboxChange(e) {
this.applyArea = JSON.parse(e.detail.value)
},
usagesCheckboxChange(e) {
console.log(e);
},
applyConfirm(e) {
console.log(e)
console.log(e.value[0])
const list=['个人申请','单位申请']
this.applyName = e.value[0]
const index = list.findIndex((item) => item === e.value[0])
console.log(index)
if(index!=-1){
this.applyType = parseInt(index + 1)
this.showApplyType = false
}else{
console.log('未找到');
}
},
handleDateConfirm(e) {
let selectedDate;
@ -373,29 +382,54 @@
},
handleStartTimeConfirm(e) {
const date = new Date(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;
const date = new Date(e.value);
//
const padZero = num => num.toString().padStart(2, '0');
const year = date.getFullYear();
const month = padZero(date.getMonth() + 1); //
const day = padZero(date.getDate()); //
const hours = padZero(date.getHours()); //
const dateString = this.mode === 'year-month' ?
`${year}-${month}` // 2023-01
:
`${year}-${month}-${day} ${hours}:00`; // 2023-01-02 09:00
this.startTime = dateString;
this.startTimePickerValue = dateString;
this.showStartTimePicker = false;
// this.adjustEndTime();
},
handleEndTimeConfirm(e) {
const date = new Date(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;
const date = new Date(e.value);
//
const padZero = num => num.toString().padStart(2, '0');
const year = date.getFullYear();
const month = padZero(date.getMonth() + 1); //
const day = padZero(date.getDate()); //
const hours = padZero(date.getHours()); //
const dateString = this.mode === 'year-month' ?
`${year}-${month}` // 2023-01
:
`${year}-${month}-${day} ${hours}:00`; // 2023-01-02 09:00
this.endTime = dateString;
this.endTimePickerValue = dateString;
this.showEndTimePicker = false;
// this.validateTime();
console.log('格式化后的结束时间:', this.endTime);
// this.validateTime(); //
},
adjustEndTime() {
console.log(this.selectedStartTime)
const [startH, startM] = this.selectedStartTime.split(':').map(Number);
let [endH, endM] = this.selectedEndTime.split(':').map(Number);
console.log(this.startTime)
const [startH, startM] = this.startTime.split(':').map(Number);
let [endH, endM] = this.endTime.split(':').map(Number);
const startTotal = startH * 60 + startM;
let endTotal = endH * 60 + endM;
@ -404,15 +438,15 @@
endTotal = startTotal + 60;
endH = Math.floor(endTotal / 60);
endM = endTotal % 60;
this.selectedEndTime = `${endH.toString().padStart(2, '0')}:${endM.toString().padStart(2, '0')}`;
this.endTime = `${endH.toString().padStart(2, '0')}:${endM.toString().padStart(2, '0')}`;
this.endTimeValue = `${endH}:${endM}`;
this.endTimePickerValue = this.selectedEndTime;
this.endTimePickerValue = this.endTime;
}
},
validateTime() {
const [startH, startM] = this.selectedStartTime.split(':').map(Number);
const [endH, endM] = this.selectedEndTime.split(':').map(Number);
const [startH, startM] = this.startTime.split(':').map(Number);
const [endH, endM] = this.endTime.split(':').map(Number);
const duration = (endH * 60 + endM) - (startH * 60 + startM);
if (duration < 30) {
@ -423,29 +457,86 @@
this.adjustEndTime();
}
},
/**
* 验证对象属性是否为空Promise版
* @param {Object} obj - 要验证的对象
* @param {Object} applyRules - 验证规则对象
* @returns {Promise} 返回Promiseresolve通过验证reject失败信息
*/
validateObject(obj, applyRules = {}) {
return new Promise((resolve, reject) => {
//
if (!obj || typeof obj !== 'object') {
return reject(new Error('参数必须是一个对象'));
}
handleBook() {
this.validateTime();
//
const bookingInfo = {
startAt: new Date(`${this.selectedDate} ${this.selectedStartTime}`),
endAt: new Date(`${this.selectedDate} ${this.selectedEndTime}`),
remark: this.remark,
roomId: this.Id
};
console.log('提交的预订信息:', bookingInfo);
uni.showToast({
title: `已预订 ${this.formattedSelectedDate} ${this.selectedStartTime}-${this.selectedEndTime}`,
icon: 'none'
const keys = Object.keys(obj);
let firstInvalidKey = null;
console.log(keys);
//
for (const item of keys) {
console.log(item)
const value = obj[item];
console.log(value);
//
if ((value === '' || value === null) && applyRules.hasOwnProperty(item)) {
firstInvalidKey = item;
break;
}
}
console.log(firstInvalidKey)
if (firstInvalidKey) {
//
const errorMsg = `${applyRules[firstInvalidKey]}不能为空`;
reject(new Error(errorMsg));
} else {
resolve('所有属性验证通过');
}
});
},
async handleBook() {
try {
console.log(this.applyType);
let bookingInfo = {
roomId: this.Id,
applyType: this.applyType,
reason: this.reason,
applyTheme: this.applyTheme
};
if (this.applyType === 1) {
const userApplyInfo = {
userName: this.userName,
userPhone: this.userPhone,
userAddress: this.userAddress,
userCardId: this.userCardId,
startTime: this.startTime,
endTime: this.endTime,
counter: this.counter,
num: this.num
}
await this.validateObject(userApplyInfo, this.applyRules)
const applyInfo = Object.assign(bookingInfo, userApplyInfo)
// A
const app = getApp()
app.globalData.applyInfo = applyInfo
uni.navigateTo({
url: `/pages/sign/sign?isSelfStudy=${this.isSelfStudy}`
})
}
if (this.applyType === 2) {
const userApplyInfo = {
concatName: this.concatName,
concatPhone: this.concatPhone,
companyName: this.companyName,
startTime: this.startTime,
endTime: this.endTime,
counter: this.counter,
num: this.num
}
await this.validateObject(userApplyInfo, this.applyRules)
const applyInfo = Object.assign(bookingInfo, userApplyInfo)
// API
post('/api/v1/app_auth/metting-room/order/register', bookingInfo).then((res) => {
console.log("===res", res)
const res = await post('/api/v1/app_auth/metting-room/order/register', applyInfo)
if (!res || !res.success) {
throw new Error('会议室预定失败');
}
@ -453,26 +544,19 @@
title: '会议室预定成功!',
icon: 'success'
});
this.remark = null;
setTimeout(() => {
if(res.success==true){
uni.navigateTo({
url: `/pages/meetingList/index`,
success: () => {
console.log('导航成功ID:', id);
},
fail: (err) => {
console.error('导航失败:', err);
uni.showToast({
title: '打开详情页失败',
icon: 'none'
});
}
});
}, 4000)
url:`/pages/docList/index?files=${JSON.stringify(res.data)}&&isSelfStudy=${this.isSelfStudy}`
})
// this.submitBooking(bookingInfo);
}
}
} catch (error) {
uni.showToast({
title: error.message,
icon: 'none'
})
}
},
}
@ -688,6 +772,7 @@
padding: 20rpx;
background: #fff;
box-shadow: 0 -2rpx 12rpx rgba(0, 0, 0, 0.08);
z-index: 999;
.u-button {
height: 88rpx;

View File

@ -254,7 +254,7 @@
// ID
const id = item.id;
const isSelfStudy=item.title==='自习室'?'true':'false'
const isSelfStudy=item.title==='自习室'?true:false
if (!id) {
uni.showToast({
title: '会议室信息异常',

View File

@ -1,31 +1,33 @@
<template>
<view>
<view class="wrapper">
<!-- <view class="handRight">
<view class="handTitle">请签名</view>
</view> -->
<view class="handCenter">
<canvas class="handWriting" :disable-scroll="true" @touchstart="uploadScaleStart"
@touchmove="uploadScaleMove" @touchend="uploadScaleEnd" canvas-id="handWriting"></canvas>
</view>
<view class="handBtn">
<!-- #ifdef MP-WEIXIN -->
<image @click="selectColorEvent('black','#1A1A1A')"
<!-- <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>
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="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' />
@ -33,8 +35,10 @@
</template>
<script>
import { post } from "../../utils/request";
import pickerColor from "./pickerColor.vue"
import {IMAGE_BASE_URL,BASE_URL} from '@/utils/config';
import {downloadPdfFiles} from '@/utils/download.js'
export default {
components: {
pickerColor
@ -62,6 +66,8 @@
},
toDataURL: void 0,
requestAnimationFrame: void 0,
applyInfo:null,
isSelfStudy:true,
};
},
props: { //props
@ -94,7 +100,17 @@
default: ''
},
},
onLoad() {
onLoad(option) {
this.isSelfStudy=option.isSelfStudy
// A
const app = getApp()
if(app.globalData.applyInfo){
this.applyInfo=app.globalData.applyInfo
}else{
uni.navigateTo({
url:'/pages/meetingList/index'
})
}
this.ctx = uni.createCanvasContext("handWriting");
this.$nextTick(() => {
uni.createSelectorQuery().select('.handCenter').boundingClientRect(rect => {
@ -418,7 +434,7 @@
// 1.
try {
await this.saveToAlbum(res.tempFilePath);
// await this.saveToAlbum(res.tempFilePath);
// 2.
uni.showLoading({
@ -428,11 +444,31 @@
const uploadRes = await this.uploadSignature(res.tempFilePath);
uni.hideLoading();
this.applyInfo.applySign=uploadRes
const response=await post('/api/v1/app_auth/metting-room/order/register', this.applyInfo)
console.log("===response", response)
if (!response || !response.success) {
throw new Error('会议室预定失败');
}
if(response.success==true){
uni.navigateTo({
url:`/pages/docList/index?files=${JSON.stringify(response.data)}&&isSelfStudy=${this.isSelfStudy}`
})
}
uni.showToast({
title: '签名上传成功',
title: '会议室预定成功!',
icon: 'success'
});
// const result = await downloadPdfFiles(response);
// console.log(':', result);
// if(result.success==true){
// uni.navigateTo({
// url: `/pages/meetingList/index`
// });
// }
// 3.
// this.$emit('upload-success', {
// tempFilePath: res.tempFilePath,
@ -558,20 +594,21 @@
.wrapper {
width: 100%;
height: 95vh;
margin: 40rpx 0;
height: 100vh;
/* margin: 40rpx 0; */
overflow: hidden;
display: flex;
align-content: center;
flex-direction: row;
flex-direction:column;
justify-content: center;
font-size: 28rpx;
}
.handWriting {
background: #fff;
width: 100%;
height: 95vh;
width: 95vw;
height: 90vh;
margin: 0 auto;
}
.handRight {
@ -583,7 +620,9 @@
border: 4rpx dashed #e9e9e9;
flex: 5;
overflow: hidden;
width: 95vw;
box-sizing: border-box;
margin: 10px auto 0px auto;
}
.handTitle {
@ -597,19 +636,21 @@
}
.handBtn {
height: 95vh;
display: inline-flex;
flex-direction: column;
height: 10vh;
display: flex;
/* flex-direction: column; */
justify-content: space-between;
align-content: space-between;
flex: 1;
align-content:center;
align-items: center;
/* flex: 1; */
}
.delBtn {
position: absolute;
/* position: absolute;
top: 250rpx;
left: 0rpx;
transform: rotate(90deg);
transform: rotate(90deg); */
height: 35px;
color: #666;
}
@ -620,16 +661,17 @@
}
.subBtn {
position: absolute;
/* position: absolute;
bottom: 52rpx;
left: -3rpx;
display: inline-flex;
transform: rotate(90deg);
transform: rotate(90deg); */
background: #008ef6;
color: #fff;
margin-bottom: 30rpx;
/* margin-bottom: 30rpx; */
text-align: center;
justify-content: center;
height: 35px;
/* justify-content: center; */
}
/*Peach - 新增 - 保存*/
@ -651,10 +693,11 @@
}
.undoBtn {
position: absolute;
/* position: absolute;
top: 625rpx;
left: 0rpx;
transform: rotate(90deg);
transform: rotate(90deg); */
height: 35px;
color: #666;
}

BIN
static/imgs/word.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

92
utils/download.js Normal file
View File

@ -0,0 +1,92 @@
/**
* 下载API返回的PDF文件
* @param {Object} apiResponse - 接口返回的数据
* @param {boolean} [showLoading=true] - 是否显示加载提示
*/
import {IMAGE_BASE_URL,BASE_URL} from '@/utils/config';
export const downloadPdfFiles = (file, showLoading = true) => {
return new Promise((resolve, reject) => {
const filesToDownload = [{url:file.url,name:file.name}];
// 2. 收集需要下载的文件
// if (applyPdf) filesToDownload.push({ url: BASE_URL+applyPdf, name: '申请表.docx' });
// if (covenantPdf) filesToDownload.push({ url: BASE_URL+covenantPdf, name: '协议书.docx' });
if (filesToDownload.length === 0) {
return reject(new Error('未找到可下载的文件'));
}
// 3. 显示加载提示
if (showLoading) {
wx.showLoading({
title: `正在下载文件(0/${filesToDownload.length})`,
mask: true
});
}
// 4. 逐个下载文件
const downloadedFiles = [];
let completedCount = 0;
const updateProgress = () => {
if (showLoading) {
wx.showLoading({
title: `正在下载文件(${completedCount}/${filesToDownload.length})`,
mask: true
});
}
};
filesToDownload.forEach((file, index) => {
wx.downloadFile({
url: file.url,
success: (res) => {
if (res.statusCode === 200) {
downloadedFiles.push({
tempPath: res.tempFilePath,
name: file.name,
});
// 下载完成后自动打开
wx.openDocument({
filePath: res.tempFilePath,
fileType: 'docx',
showMenu: true,// 显示Android分享菜单
success: () => {
console.log(`${file.name} 打开成功`);
},
fail: (err) => {
console.error(`${file.name} 打开失败:`, err);
}
});
} else {
console.error(`${file.name} 下载失败,状态码: ${res.statusCode}`);
}
},
fail: (err) => {
console.error(`${file.name} 下载失败:`, err);
},
complete: () => {
completedCount++;
updateProgress();
// 全部下载完成
if (completedCount === filesToDownload.length) {
if (showLoading) wx.hideLoading();
if (downloadedFiles.length > 0) {
resolve({
success: true,
files: downloadedFiles,
message: `成功下载 ${downloadedFiles.length} 个文件`
});
} else {
reject(new Error('所有文件下载失败'));
}
}
}
});
});
});
};

27
utils/router.js Normal file
View File

@ -0,0 +1,27 @@
// utils/router.js
export const navigateTo = (options,isNavigate=true) => {
const publicPages = ['/pages/index/index', '/pages/chat/index','/pages/mine/index']; // 不需要登录的页面
if (publicPages.includes(options.url)) {
uni.navigateTo(options);
return;
}
const app = getApp();
app.checkLogin().then((isLogin) => {
if (isLogin) {
uni.navigateTo(options);
} else {
if(isNavigate){
uni.redirectTo({
url: `/pages/mine/index?redirect=${encodeURIComponent(options.url)}`
});
}else{
uni.showToast({
title: '请先登录',
icon:"none"
})
}
}
});
};