chenkainan 8 months ago
parent
commit
234ba8efa8
  1. 18
      pages.json
  2. 6
      pages/user/user.vue
  3. 52
      static/js/CommonFunction.js
  4. 223
      subPackages/clockIn/apply.vue
  5. 186
      subPackages/clockIn/index.vue
  6. 116
      subPackages/clockIn/record.vue

18
pages.json

@ -97,6 +97,24 @@
"style": {
"navigationBarTitleText": ""
}
},
{
"path": "clockIn/index",
"style": {
"navigationBarTitleText": "审批打卡"
}
},
{
"path": "clockIn/apply",
"style": {
"navigationBarTitleText": "审批打卡"
}
},
{
"path": "clockIn/record",
"style": {
"navigationBarTitleText": "我的打卡记录"
}
}
]
}],

6
pages/user/user.vue

@ -39,7 +39,11 @@
// {
// title: '',
// path: '/subPackages/user/accountPassword'
// }
// },
{
title: '我的打卡记录',
path: '/subPackages/clockIn/record'
}
],
userInfo: {group_data: {}}
}

52
static/js/CommonFunction.js

@ -185,4 +185,56 @@ Vue.prototype.calculateDistance = (lat1, lon1, lat2, lon2) => {
const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
return R * c;
}
/**
* @description 格式化时间
* @param {String|Number} dateTime 需要格式化的时间戳
* @param {String} fmt 格式化规则 yyyy:mm:dd|yyyy:mm|yyyy年mm月dd日|yyyy年mm月dd日 hh时MM分等,可自定义组合 默认yyyy-mm-dd
* @returns {string} 返回格式化后的字符串
*/
Vue.prototype.timeFormat = (dateTime = null, formatStr = 'yyyy-mm-dd')=> {
let date
// 若传入时间为假值,则取当前时间
if (!dateTime) {
date = new Date()
}
// 若为unix秒时间戳,则转为毫秒时间戳(逻辑有点奇怪,但不敢改,以保证历史兼容)
else if (/^\d{10}$/.test(dateTime?.toString().trim())) {
date = new Date(dateTime * 1000)
}
// 若用户传入字符串格式时间戳,new Date无法解析,需做兼容
else if (typeof dateTime === 'string' && /^\d+$/.test(dateTime.trim())) {
date = new Date(Number(dateTime))
}
// 处理平台性差异,在Safari/Webkit中,new Date仅支持/作为分割符的字符串时间
// 处理 '2022-07-10 01:02:03',跳过 '2022-07-10T01:02:03'
else if (typeof dateTime === 'string' && dateTime.includes('-') && !dateTime.includes('T')) {
date = new Date(dateTime.replace(/-/g, '/'))
}
// 其他都认为符合 RFC 2822 规范
else {
date = new Date(dateTime)
}
const timeSource = {
'y': date.getFullYear().toString(), // 年
'm': (date.getMonth() + 1).toString().padStart(2, '0'), // 月
'd': date.getDate().toString().padStart(2, '0'), // 日
'h': date.getHours().toString().padStart(2, '0'), // 时
'M': date.getMinutes().toString().padStart(2, '0'), // 分
's': date.getSeconds().toString().padStart(2, '0') // 秒
// 有其他格式化字符需求可以继续添加,必须转化成字符串
}
for (const key in timeSource) {
const [ret] = new RegExp(`${key}+`).exec(formatStr) || []
if (ret) {
// 年可能只需展示两位
const beginIndex = key === 'y' && ret.length === 2 ? 2 : 0
formatStr = formatStr.replace(ret, timeSource[key].slice(beginIndex))
}
}
return formatStr
}

223
subPackages/clockIn/apply.vue

@ -0,0 +1,223 @@
<template>
<view class="bg">
<view class="user-other-info">
<view class="userinfo-item edit" >
<span>打卡日期</span>
<view>
<!-- <picker mode="date" :value="info.date" :start="startDate" :end="endDate" @change="bindDateChange">
<view class="text-overflow" v-if="info.date">{{info.date}}</view>
<view v-else class="empty-value" >请选择</view>
</picker> -->
<view class="text-overflow" >{{timeFormat(new Date())}}</view>
</view>
</view>
<!-- <view class="userinfo-item edit" >
<span>打卡时段</span>
<view>
<picker @change="bindPickerChange" :value="info.time" :range="timeArr">
<view class="text-overflow" v-if="info.time || info.time===0">{{timeArr[info.time]}}</view>
<view v-else class="empty-value" >请选择</view>
</picker>
</view>
</view> -->
<view class="userinfo-item" style="border: none;">
<span>审批事由</span>
</view>
<textarea class="reason" auto-height v-model="info.reason" placeholder="请填写您审批的事由"/>
<view class="btn-tao" @click="submit">提交</view>
</view>
</view>
</template>
<script>
function getDate(type) {
const date = new Date();
let year = date.getFullYear();
let month = date.getMonth() + 1;
let day = date.getDate();
if (type === 'start') {
year = year - 10;
} else if (type === 'end') {
year = year + 10;
}
month = month > 9 ? month : '0' + month;;
day = day > 9 ? day : '0' + day;
return `${year}-${month}-${day}`;
}
export default {
data() {
return {
info: {
date: '',
time: '',timeStr: '',
reason: ''
},
startDate:getDate('start'),
endDate:getDate('end'),
timeArr: [
"09:00-10:00",
]
}
},
onLoad () {
},
methods: {
bindDateChange: function(e) {
this.info.date = e.detail.value
},
bindPickerChange: function(e) {
console.log(e.detail.value)
this.info.time = e.detail.value
},
submit() {
if (!this.info.reason.trim()) {
this.showToast({title: "请输入审批事由",icon:'none'})
return;
}
this.Post({reason: this.info.reason},'/api/Merchants/guideClockExamine').then(res=>{
uni.showToast({
title:'提交成功',icon:"none"
})
setTimeout(()=>{
uni.navigateTo({
url:'/subPackages/clockIn/record'
})
},1000)
})
},
}
}
</script>
<style scoped lang="scss">
view {
box-sizing: content-box;
}
.bg{
min-height: calc(100vh - 44px - env(safe-area-inset-top)) ;
overflow-x: hidden;
background: white;
padding-bottom: 50rpx;
}
.empty-value{
font-weight: 500;
font-size: 28rpx;
color: #999999;
}
.user-other-info {
margin:0 30rpx;
.info-title{
font-weight: bold;
font-size: 32rpx;
color: #000000;
}
}
.userinfo-item {
display: flex;
justify-content: space-between;
align-items: center;
font-size: 28rpx;
border-bottom: 1rpx solid #D8D8D8;
padding: 40rpx 30rpx 40rpx 0;
height: 48rpx;
color: #333;
position: relative;
}
.info-avatar-top span {
font-weight: 500;
font-size: 31rpx;
flex-shrink: 0;
}
.userinfo-item>span {
font-weight: 500;
font-size: 31rpx;
flex-shrink: 0;
color: #000;
width: 200rpx;
&::before{
content: "*";
color: #96684F;
}
}
.userinfo-item>i {
font-weight: 500;
font-size: 24rpx;
color: #999999;
}
.userinfo-item.edit {
&>view::after {
content: "";
width: 20rpx;
height: 20rpx;
margin-left: 6rpx;
background-image: url('https://static.ticket.sz-trip.com/tongli/images/user/rightIcon-gray.png');
background-size: 100% 100%;
position: absolute;
right: 0;
margin: auto;
top: 0;
bottom: 0;
}
}
.birthday-box {
text-align: right;
}
.dialog-footer .change-avatar-btn {
position: fixed;
text-align: center;
bottom: 80rpx;
left: 50%;
margin-left: -110rpx;
}
.btn-tao {
text-align: center;
font-size: 30rpx;
width: 697rpx;
height: 80rpx;
background: #96684F;
border-radius: 40rpx;
line-height: 80rpx;
color: #FFFFFF;
position: absolute;
bottom: 50rpx;
}
.reason{
background: #F5F5F5;
border-radius: 13rpx;
min-height: 265rpx;
width: 100%;
padding: 20rpx 12rpx;
box-sizing: border-box;
font-size: 28rpx;
}
</style>

186
subPackages/clockIn/index.vue

@ -0,0 +1,186 @@
<template>
<view class="bg">
<view>
<view class="detail-container">
<view class="box-title">
<text>{{item.guide_name}}的审批打卡</text>
<text :class="['status'+item.status]">{{status[item.status]}}</text>
</view>
<view class="item">
<view class="title">审批编号:</view>
<view class="subtitle">{{item.id}}</view>
</view>
<view class="item">
<view class="title">提交时间:</view>
<view class="subtitle">{{item.create_time}}</view>
</view>
<view class="item">
<view class="title">打卡日期:</view>
<view class="subtitle">{{item.date}}</view>
</view>
<!-- <view class="item">
<view class="title">打卡时段:</view>
<view class="subtitle">{{item.goods_title}}</view>
</view> -->
<view class="item">
<view class="title">打卡事由:</view>
<view class="subtitle">{{item.reason}}</view>
</view>
</view>
<view class="detail-container">
<view class="box-title">
<text>审批流程</text>
<text></text>
</view>
<view class="item">
<view class="title">审批人:</view>
<view class="subtitle">张大庄{{status[item.status]}}</view>
</view>
</view>
</view>
<view class="btn-tao" @click="submit" v-if="item.status===0">撤销</view>
</view>
</template>
<script>
export default {
data() {
return {
id: null,
item: {},
status:{
0:'审批中',
1:'打卡正常',
2:'审批拒绝',
3:'审批取消'
}
}
},
onLoad(option) {
if(option.id) {
this.id = option.id
this.getDetail(option.id)
} else {
uni.showToast({
title: '参数错误',
icon: 'none'
})
setTimeout(()=>{
uni.navigateBack()
},1000)
}
},
methods: {
getDetail(id) {
this.Post({clock_id: id},'/api/Merchants/getGuideClockDetails').then(res => {
this.item = res.data
if (uni.getStorageSync('userInfo') && JSON.parse(uni.getStorageSync('userInfo')).token) this.item.guide_name = JSON.parse(uni.getStorageSync('userInfo')).nickname
else if (store.state.user.userInfo.nickname) this.item.guide_name = store.state.user.userInfo.nickname
})
},
submit () {
//
this.Post({clock_id: this.id},'/api/Merchants/cancelGuideClockExamine').then(res => {
uni.showToast({
title:'撤销成功',
icon:'none'
})
setTimeout(()=>{
uni.navigateBack()
})
})
},
},
}
</script>
<style lang="scss" scoped>
.bg {
background: #F5F5F5;
min-height: calc(100vh - 44px - env(safe-area-inset-top)) ;
padding: 0rpx 26rpx 50rpx;
}
.detail-container {
padding: 33rpx 0rpx;
background: #FFFFFF;
border-radius: 13rpx;
margin-top: 30rpx;
.box-title {
font-weight: bold;
font-size: 35rpx;
color: #111111;
padding: 0 27rpx 33rpx;
display: flex;
justify-content: space-between;
border-bottom: 1px solid #ccc;
.status0{
font-weight: bold;
font-size: 28rpx;
color: #96684F;
}
.status1{
font-weight: bold;
font-size: 28rpx;
color: #47C24F;
}
.status2{
font-weight: bold;
font-size: 28rpx;
color: #F56C6C;
}
.status3{
font-weight: bold;
font-size: 28rpx;
color: #F56C6C;
}
}
.item {
margin-top: 20rpx;
padding: 0rpx 27rpx;
display: flex;
color: #111111;
.title {
min-width: 120rpx;
font-weight: 500;
font-size: 28rpx;
flex-shrink: 0;
padding-right: 20rpx;
}
.subtitle {
font-weight: 500;
font-size: 28rpx;
}
}
}
.empty-text {
font-weight: 500;
font-size: 25rpx;
color: #646464;
text-align: center;
margin: 50rpx 0;
}
.btn-tao {
text-align: center;
font-size: 30rpx;
width: 697rpx;
height: 80rpx;
border-radius: 40rpx;
line-height: 80rpx;
color: #96684F;
position: absolute;
bottom: 50rpx;
border: 1px solid #96684F;
}
</style>

116
subPackages/clockIn/record.vue

@ -0,0 +1,116 @@
<template>
<view class="bg">
<view class="row-container header-row" v-if="list.length>0">
<view>所属日期</view>
<view>打卡时间</view>
<view>打卡状态</view>
</view>
<view class="row-container item-row" v-for="(item, index) in list" :key="index" @click="goDetail(item)">
<view>{{ item.date }}</view>
<view v-if="item.status==1">
{{item.type==1?item.create_time.slice(11):item.update_time.slice(11) }}
</view>
<view v-else></view>
<view>
{{item.status==0?'审批中':item.status==1?'打卡正常':item.status==2?'审批拒绝':item.status==3?'审批取消':''}}
</view>
</view>
<view class="empty-text" v-if="list.length == 0">
暂无打卡记录
</view>
</view>
</template>
<script>
export default {
data() {
return {
list: [],
finished: false,
page: 1,
limit: 30,
}
},
onLoad() {
this.page = 1
this.finished = false
this.list = []
this.getList()
},
methods: {
getList() {
this.Post({
page: this.page,
limit: this.limit,
},'/api/Merchants/getGuideClockList').then(res => {
this.list = this.list.concat(res.data || [])
this.page++
if (res.data.length<this.limit) {
this.finished = true
}
})
},
goDetail (item) {
//
if (item.type == 2) {
uni.navigateTo({
url: '/subPackages/clockIn/index?id='+item.id
})
}
},
},
onReachBottom() {
setTimeout(() => {
if (!this.finished) this.getList()
},1000)
}
}
</script>
<style lang="scss" scoped>
.bg {
background: #F5F5F5;
min-height: calc(100vh - 44px - env(safe-area-inset-top)) ;
padding: 26rpx 26rpx 50rpx;
}
.row-container{
display: flex;
width: 100%;
flex-wrap: nowrap;
background: white;
&>view{
flex: 1;
flex-shrink: 0;
text-align: center;
padding: 22rpx 27rpx;
}
}
.header-row{
color: white;
background: #96684F;
border-radius: 13rpx 13rpx 0rpx 0rpx;
}
.item-row{
border-bottom: 1px solid #ccc;
&>view{
border-left: 1px solid #ccc;;
}
&>view:first-child{
border-left: none;
}
&:last-child{
border-bottom: none;
border-radius: 0rpx 0rpx 13rpx 13rpx;;
}
}
.empty-text {
font-weight: 500;
font-size: 25rpx;
color: #646464;
text-align: center;
margin: 50rpx 0;
}
</style>
Loading…
Cancel
Save