420 lines
7.7 KiB
Vue
420 lines
7.7 KiB
Vue
|
<template>
|
|||
|
<view class="page-container">
|
|||
|
|
|||
|
<!-- 表单区域 -->
|
|||
|
<view class="form-section">
|
|||
|
<view class="form-item">
|
|||
|
<text class="form-label">补卡时间</text>
|
|||
|
<picker mode="date" :value="form.date" @change="onDateChange">
|
|||
|
<view class="picker">{{ form.date }} {{ form.time }}</view>
|
|||
|
</picker>
|
|||
|
</view>
|
|||
|
|
|||
|
<view class="tip-text">
|
|||
|
<text>本月已补卡{{ usedTimes }}次,剩余{{ remainTimes }}次。</text>
|
|||
|
</view>
|
|||
|
|
|||
|
<view class="form-item">
|
|||
|
<text class="form-label">补卡说明</text>
|
|||
|
<textarea v-model="form.remark" placeholder="请输入" class="textarea" />
|
|||
|
</view>
|
|||
|
|
|||
|
<view class="form-item">
|
|||
|
<text class="form-label">附件</text>
|
|||
|
<!-- 如果没有图片,显示上传按钮 -->
|
|||
|
<view class="custom-upload-btn" @click="chooseImage" v-if="!selectedImage">
|
|||
|
<image class="image" src="/static/ic_camera.png"></image>
|
|||
|
<text class="text">上传图片</text>
|
|||
|
</view>
|
|||
|
|
|||
|
<!-- 已选图片预览 -->
|
|||
|
<view class="preview-item" v-else>
|
|||
|
<image class="preview-img" :src="selectedImage" mode="aspectFill" @click="previewImage"></image>
|
|||
|
<view class="delete-btn" @click.stop="deletePic">✕</view>
|
|||
|
</view>
|
|||
|
</view>
|
|||
|
</view>
|
|||
|
|
|||
|
<!-- 审批记录 -->
|
|||
|
<view class="record-section">
|
|||
|
<text class="section-title">审批记录</text>
|
|||
|
<view class="timeline">
|
|||
|
<view v-for="(item, index) in records" :key="index" class="timeline-item">
|
|||
|
<!-- 点 -->
|
|||
|
<view class="timeline-dot"></view>
|
|||
|
|
|||
|
<!-- 节点内容 -->
|
|||
|
<view class="timeline-content">
|
|||
|
<text class="end-text">{{ item.node }}</text>
|
|||
|
|
|||
|
<view class="record-row" v-if="item.status !== '结束'">
|
|||
|
<image class="avatar" :src="item.avatar" mode="aspectFill" />
|
|||
|
<view class="name-node-container">
|
|||
|
<text class="name">{{ item.name }}</text>
|
|||
|
<text class="status" :class="statusClass(item.status)">{{ item.status }}</text>
|
|||
|
</view>
|
|||
|
<text class="time2">{{ item.time }}</text>
|
|||
|
</view>
|
|||
|
<text v-else class="time">{{ item.time }}</text>
|
|||
|
</view>
|
|||
|
</view>
|
|||
|
</view>
|
|||
|
</view>
|
|||
|
|
|||
|
<!-- 提交按钮 -->
|
|||
|
<view class="footer">
|
|||
|
<button class="submit-btn" type="primary" @click="submit">提交</button>
|
|||
|
</view>
|
|||
|
</view>
|
|||
|
</template>
|
|||
|
|
|||
|
<script>
|
|||
|
export default {
|
|||
|
data() {
|
|||
|
return {
|
|||
|
usedTimes: 0,
|
|||
|
remainTimes: 5,
|
|||
|
selectedImage: '',
|
|||
|
form: {
|
|||
|
date: '2025-07-13',
|
|||
|
time: '09:00',
|
|||
|
remark: ''
|
|||
|
},
|
|||
|
records: [{
|
|||
|
node: '提交',
|
|||
|
name: '于永乐',
|
|||
|
status: '已提交',
|
|||
|
time: '07-12 18:28:22',
|
|||
|
avatar: '/static/avatar1.png'
|
|||
|
},
|
|||
|
{
|
|||
|
node: '审批',
|
|||
|
name: '张桂花',
|
|||
|
status: '已同意',
|
|||
|
time: '07-12 18:30:12',
|
|||
|
avatar: '/static/avatar2.png'
|
|||
|
},
|
|||
|
{
|
|||
|
node: '审批',
|
|||
|
name: '张桂花',
|
|||
|
status: '已拒绝',
|
|||
|
time: '07-12 19:12:45',
|
|||
|
avatar: '/static/avatar2.png'
|
|||
|
},
|
|||
|
{
|
|||
|
node: '结束',
|
|||
|
name: '',
|
|||
|
status: '结束',
|
|||
|
time: '07-12 20:00:00',
|
|||
|
avatar: ''
|
|||
|
}
|
|||
|
]
|
|||
|
}
|
|||
|
},
|
|||
|
methods: {
|
|||
|
onDateChange(e) {
|
|||
|
this.form.date = e.detail.value
|
|||
|
},
|
|||
|
chooseImage() {
|
|||
|
uni.chooseImage({
|
|||
|
count: 1,
|
|||
|
success: (res) => {
|
|||
|
this.selectedImage = res.tempFilePaths[0]
|
|||
|
}
|
|||
|
})
|
|||
|
},
|
|||
|
// 预览图片
|
|||
|
previewImage() {
|
|||
|
uni.previewImage({
|
|||
|
current: this.selectedImage,
|
|||
|
urls: [this.selectedImage]
|
|||
|
})
|
|||
|
},
|
|||
|
// 删除图片
|
|||
|
deletePic(event) {
|
|||
|
this.selectedImage = ''
|
|||
|
},
|
|||
|
|
|||
|
submit() {
|
|||
|
uni.showToast({
|
|||
|
title: '提交成功',
|
|||
|
icon: 'success'
|
|||
|
})
|
|||
|
},
|
|||
|
statusClass(status) {
|
|||
|
if (status === '已提交') return 'blue'
|
|||
|
if (status === '已同意') return 'green'
|
|||
|
if (status === '已拒绝') return 'orange'
|
|||
|
if (status === '结束') return 'gray'
|
|||
|
return ''
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
</script>
|
|||
|
|
|||
|
<style scoped>
|
|||
|
.page-container {
|
|||
|
background: #f5f5f5;
|
|||
|
min-height: 100vh;
|
|||
|
display: flex;
|
|||
|
flex-direction: column;
|
|||
|
}
|
|||
|
|
|||
|
.form-section {
|
|||
|
background: #fff;
|
|||
|
margin: 20rpx;
|
|||
|
padding: 20rpx;
|
|||
|
border-radius: 12rpx;
|
|||
|
}
|
|||
|
|
|||
|
.form-item {
|
|||
|
margin-bottom: 20rpx;
|
|||
|
}
|
|||
|
|
|||
|
.form-label {
|
|||
|
font-size: 24rpx;
|
|||
|
color: #737373;
|
|||
|
margin-bottom: 10rpx;
|
|||
|
display: block;
|
|||
|
}
|
|||
|
|
|||
|
.tip-text {
|
|||
|
height: 73rpx;
|
|||
|
line-height: 73rpx;
|
|||
|
background: #F7F7F7;
|
|||
|
color: #808080;
|
|||
|
font-size: 24rpx;
|
|||
|
border-radius: 10rpx;
|
|||
|
padding-left: 16rpx;
|
|||
|
}
|
|||
|
|
|||
|
.textarea {
|
|||
|
width: 100%;
|
|||
|
height: 160rpx;
|
|||
|
border: 2rpx solid #ddd;
|
|||
|
border-radius: 8rpx;
|
|||
|
padding: 12rpx;
|
|||
|
font-size: 24rpx;
|
|||
|
}
|
|||
|
|
|||
|
.upload-box {
|
|||
|
border: 2rpx dashed #aaa;
|
|||
|
border-radius: 12rpx;
|
|||
|
padding: 40rpx;
|
|||
|
text-align: center;
|
|||
|
color: #888;
|
|||
|
}
|
|||
|
|
|||
|
.upload-icon {
|
|||
|
width: 60rpx;
|
|||
|
height: 60rpx;
|
|||
|
margin-bottom: 12rpx;
|
|||
|
}
|
|||
|
|
|||
|
/* 审批记录 */
|
|||
|
.record-section {
|
|||
|
background: #fff;
|
|||
|
border-radius: 25rpx;
|
|||
|
margin-left: 32rpx;
|
|||
|
margin-right: 32rpx;
|
|||
|
padding: 35rpx 25rpx 35rpx 25rpx;
|
|||
|
}
|
|||
|
|
|||
|
.section-title {
|
|||
|
font-size: 30rpx;
|
|||
|
font-weight: bold;
|
|||
|
margin-bottom: 20rpx;
|
|||
|
color: #333;
|
|||
|
}
|
|||
|
|
|||
|
/* timeline 方法二:每个节点自己画线 */
|
|||
|
.timeline {
|
|||
|
position: relative;
|
|||
|
margin-left: 12rpx;
|
|||
|
margin-top: 45rpx;
|
|||
|
}
|
|||
|
|
|||
|
.timeline-item {
|
|||
|
position: relative;
|
|||
|
padding-left: 40rpx;
|
|||
|
padding-bottom: 50rpx;
|
|||
|
}
|
|||
|
|
|||
|
.timeline-item::before {
|
|||
|
content: "";
|
|||
|
position: absolute;
|
|||
|
top: 0;
|
|||
|
bottom: 0;
|
|||
|
left: -2rpx;
|
|||
|
width: 2rpx;
|
|||
|
background: #ddd;
|
|||
|
}
|
|||
|
|
|||
|
/* 第一个节点:去掉上半段 */
|
|||
|
.timeline-item:first-child::before {
|
|||
|
top: 20rpx;
|
|||
|
}
|
|||
|
|
|||
|
/* 最后一个节点:去掉下半段 */
|
|||
|
.timeline-item:last-child::before {
|
|||
|
bottom: auto;
|
|||
|
height: 20rpx;
|
|||
|
}
|
|||
|
|
|||
|
/* 状态点 */
|
|||
|
.timeline-dot {
|
|||
|
position: absolute;
|
|||
|
left: -12rpx;
|
|||
|
top: 10rpx;
|
|||
|
width: 20rpx;
|
|||
|
height: 20rpx;
|
|||
|
border: 1rpx solid #10AF7F;
|
|||
|
border-radius: 50%;
|
|||
|
background: #fff;
|
|||
|
}
|
|||
|
|
|||
|
.timeline-content {
|
|||
|
margin-left: -20rpx;
|
|||
|
}
|
|||
|
|
|||
|
.record-row {
|
|||
|
display: flex;
|
|||
|
align-items: center;
|
|||
|
margin-bottom: 8rpx;
|
|||
|
}
|
|||
|
|
|||
|
.avatar {
|
|||
|
width: 54rpx;
|
|||
|
height: 54rpx;
|
|||
|
border-radius: 50%;
|
|||
|
margin-right: 15rpx;
|
|||
|
background: #688CFF;
|
|||
|
}
|
|||
|
|
|||
|
.name-node-container {
|
|||
|
display: flex;
|
|||
|
flex-direction: column;
|
|||
|
align-items: flex-start;
|
|||
|
}
|
|||
|
|
|||
|
.name {
|
|||
|
font-size: 28rpx;
|
|||
|
color: #000;
|
|||
|
}
|
|||
|
|
|||
|
.status {
|
|||
|
font-size: 22rpx;
|
|||
|
font-weight: 500;
|
|||
|
}
|
|||
|
|
|||
|
.status.blue {
|
|||
|
color: #007aff;
|
|||
|
}
|
|||
|
|
|||
|
.status.green {
|
|||
|
color: #4caf50;
|
|||
|
}
|
|||
|
|
|||
|
.status.orange {
|
|||
|
color: #ff6b35;
|
|||
|
}
|
|||
|
|
|||
|
.status.gray {
|
|||
|
color: #999;
|
|||
|
}
|
|||
|
|
|||
|
.end-text {
|
|||
|
font-size: 24rpx;
|
|||
|
color: #000;
|
|||
|
font-weight: bold;
|
|||
|
}
|
|||
|
|
|||
|
.time {
|
|||
|
font-size: 24rpx;
|
|||
|
color: #626262;
|
|||
|
float: right;
|
|||
|
margin-right: 40rpx;
|
|||
|
}
|
|||
|
|
|||
|
.time2 {
|
|||
|
font-size: 24rpx;
|
|||
|
color: #626262;
|
|||
|
position: absolute;
|
|||
|
right: 40rpx;
|
|||
|
bottom: 70rpx;
|
|||
|
}
|
|||
|
|
|||
|
.footer {
|
|||
|
padding: 20rpx;
|
|||
|
}
|
|||
|
|
|||
|
.submit-btn {
|
|||
|
width: 100%;
|
|||
|
height: 90rpx;
|
|||
|
line-height: 90rpx;
|
|||
|
border-radius: 50rpx;
|
|||
|
background: #007aff;
|
|||
|
color: #fff;
|
|||
|
font-size: 32rpx;
|
|||
|
}
|
|||
|
|
|||
|
.text {
|
|||
|
color: #000000;
|
|||
|
font-size: 24rpx;
|
|||
|
margin-left: 10rpx;
|
|||
|
font-weight: 400;
|
|||
|
}
|
|||
|
|
|||
|
.image {
|
|||
|
width: 55rpx;
|
|||
|
height: 42rpx;
|
|||
|
}
|
|||
|
|
|||
|
.custom-upload-btn {
|
|||
|
width: auto;
|
|||
|
margin-left: 0rpx;
|
|||
|
margin-right: 0rpx;
|
|||
|
margin-top: 24rpx;
|
|||
|
height: 244rpx;
|
|||
|
background: #f6f6f6;
|
|||
|
display: flex;
|
|||
|
flex-direction: column;
|
|||
|
align-items: center;
|
|||
|
justify-content: center;
|
|||
|
border-radius: 16rpx;
|
|||
|
}
|
|||
|
|
|||
|
.preview-item {
|
|||
|
position: relative;
|
|||
|
width: auto;
|
|||
|
/* 宽度自动 */
|
|||
|
margin-left: 40rpx;
|
|||
|
margin-right: 40rpx;
|
|||
|
height: 244rpx;
|
|||
|
margin-top: 24rpx;
|
|||
|
/* 固定高度 */
|
|||
|
display: flex;
|
|||
|
justify-content: center;
|
|||
|
/* 水平居中 */
|
|||
|
align-items: center;
|
|||
|
/* 垂直居中 */
|
|||
|
overflow: hidden;
|
|||
|
/* 裁剪超出部分 */
|
|||
|
border-radius: 10rpx;
|
|||
|
/* 可选:圆角 */
|
|||
|
}
|
|||
|
|
|||
|
.delete-btn {
|
|||
|
position: absolute;
|
|||
|
top: 0;
|
|||
|
right: 0;
|
|||
|
width: 40rpx;
|
|||
|
height: 40rpx;
|
|||
|
line-height: 40rpx;
|
|||
|
text-align: center;
|
|||
|
border-radius: 50%;
|
|||
|
background: rgba(0, 0, 0, 0.6);
|
|||
|
color: #fff;
|
|||
|
font-size: 24rpx;
|
|||
|
}
|
|||
|
</style>
|