main
ihzero 2024-05-01 15:44:30 +08:00
parent 5855dd35d4
commit 30251f5035
7 changed files with 269 additions and 155 deletions

View File

@ -60,7 +60,7 @@
<view class="h-40vh flex-center flex-col">
<view
:disabled="noCheck && maxDistance != 0"
:disabled="noCheck"
@click="clockIn"
class="w-220rpx h-220rpx rounded-full overflow-hidden card-shadow1 flex-center btn"
>
@ -128,7 +128,7 @@ const form = reactive({
const rules = ref({})
const noCheck = computed(() => {
return !isGPS.value || !detail.value.enable
return !detail.value.enable
})
const maxDistance = computed(() => {
return detail.value.maxDistance

View File

@ -1,97 +1,46 @@
<template>
<view>
<CuNavbar title="培训考试">
<template v-if="!readonly" #right>
<template v-if="!readonly && !notfound" #right>
<view class="text-white" @click="submit"></view>
</template>
</CuNavbar>
<uv-sticky bgColor="#fff">
<view class="flex items-center justify-between h-90rpx px-base">
<view class="w-140rpx">
<view class="btn" :disabled="index == 0" @click="prev"></view>
</view>
<view>{{ index + 1 }}/{{ total }}</view>
<view class="w-140rpx text-right">
<view class="btn" :disabled="index == total - 1" @click="next">
下一题</view
>
</view>
<template v-if="notfound">
<view class="h-60vh flex-center">
<uv-empty text="试卷不存在" :icon="NotFoundImg"> </uv-empty>
</view>
</uv-sticky>
<view class="p-base">
<view class="card-shadow bg-white rounded-19rpx p-base min-h-30vh">
<template v-for="(item, key) in list" :key="key">
<view v-show="key == index" class="item">
<view class="title text-30rpx"
>({{ item.cate_name }}){{ item.title }}
<text v-if="readonly" class="text-primary"
>(得分{{ item.user_score }})</text
>
</view>
<view
class="pt-base"
:class="[readonly ? 'pointer-events-none' : '']"
</template>
<template v-else>
<uv-sticky bgColor="#fff">
<view class="flex items-center justify-between h-90rpx px-base">
<view class="w-140rpx">
<view class="btn" :disabled="index == 0" @click="prev"></view>
</view>
<view>{{ index + 1 }}/{{ total }}</view>
<view class="w-140rpx text-right">
<view class="btn" :disabled="index == total - 1" @click="next">
下一题</view
>
<template v-if="item.cate == 2">
<uv-checkbox-group
activeColor="#ee2c37"
v-model="item.answer"
placement="column"
</view>
</view>
</uv-sticky>
<view class="p-base">
<view class="card-shadow bg-white rounded-19rpx p-base min-h-30vh">
<template v-for="(item, key) in list" :key="key">
<view v-show="key == index" class="item">
<view class="title text-30rpx"
>({{ item.cate_name }}){{ item.title }}
<text v-if="readonly" class="text-primary"
>(得分{{ item.user_score }})</text
>
<uv-checkbox
:customStyle="{ margin: '8px' }"
v-for="(op, i) in item.options"
:activeColor="
op.selected != op.is_true && op.selected
? '#e3e3e3'
: '#3678f7'
"
:key="i"
:label="op.text"
:name="i"
>
<view class="flex items-center">
<view>{{ op.text }}</view>
<uv-icon
v-if="(op.selected || op.is_true)&& readonly"
:color="
op.is_true && op.selected ? '#4caf50' : '#ee2c37'
"
:name="
op.is_true && op.selected ? 'checkbox-mark' : 'close'
"
></uv-icon>
</view>
</uv-checkbox>
</uv-checkbox-group>
</template>
<template v-if="item.cate == 1">
<uv-radio-group
v-if="!readonly"
activeColor="#ee2c37"
v-model="item.answer"
placement="column"
>
<uv-radio
:customStyle="{ margin: '8px' }"
v-for="(op, i) in item.options"
:key="i"
:label="op.text"
:name="i"
>
<view class="flex items-center">
<view>{{ op.text }}</view>
<uv-icon
v-if="op.selected && readonly"
:color="op.is_true ? '#ee2c37' : '#5ac725'"
:name="op.is_true ? 'checkbox-mark' : 'close'"
></uv-icon>
</view>
</uv-radio>
</uv-radio-group>
<template v-else>
</view>
<view
class="pt-base"
:class="[readonly ? 'pointer-events-none' : '']"
>
<template v-if="item.cate == 2">
<uv-checkbox-group
activeColor="#ee2c37"
v-model="item.answer"
@ -126,12 +75,72 @@
</uv-checkbox>
</uv-checkbox-group>
</template>
</template>
<template v-if="item.cate == 1">
<uv-radio-group
v-if="!readonly"
activeColor="#ee2c37"
v-model="item.answer"
placement="column"
>
<uv-radio
:customStyle="{ margin: '8px' }"
v-for="(op, i) in item.options"
:key="i"
:label="op.text"
:name="i"
>
<view class="flex items-center">
<view>{{ op.text }}</view>
<uv-icon
v-if="op.selected && readonly"
:color="op.is_true ? '#ee2c37' : '#5ac725'"
:name="op.is_true ? 'checkbox-mark' : 'close'"
></uv-icon>
</view>
</uv-radio>
</uv-radio-group>
<template v-else>
<uv-checkbox-group
activeColor="#ee2c37"
v-model="item.answer"
placement="column"
>
<uv-checkbox
:customStyle="{ margin: '8px' }"
v-for="(op, i) in item.options"
:activeColor="
op.selected != op.is_true && op.selected
? '#e3e3e3'
: '#3678f7'
"
:key="i"
:label="op.text"
:name="i"
>
<view class="flex items-center">
<view>{{ op.text }}</view>
<uv-icon
v-if="(op.selected || op.is_true) && readonly"
:color="
op.is_true && op.selected ? '#4caf50' : '#ee2c37'
"
:name="
op.is_true && op.selected
? 'checkbox-mark'
: 'close'
"
></uv-icon>
</view>
</uv-checkbox>
</uv-checkbox-group>
</template>
</template>
</view>
</view>
</view>
</template>
</template>
</view>
</view>
</view>
</template>
<uv-modal
ref="modalRef"
@ -143,10 +152,12 @@
</view>
</template>
<script setup>
import NotFoundImg from '@/static/images/404.svg'
import CuNavbar from '@/components/cu-navbar/index'
import { http } from '@/utils/request'
import { onLoad } from '@dcloudio/uni-app'
import { onLoad, onShow } from '@dcloudio/uni-app'
import { computed, ref } from 'vue'
const notfound = ref(false)
const modalRef = ref(null)
const info = ref({})
const id = ref(0)
@ -184,7 +195,6 @@ const total = computed(() => list.value.length)
const readonly = computed(() => (info.value.finished_at ? true : false))
function findAllIndices(arr, predicate) {
console.log(arr)
return arr.filter(predicate).keys()
}
@ -199,11 +209,25 @@ const answer = computed(() => {
onLoad((options) => {
id.value = options.id
http.get(`/train/examinations/${options.id}`).then((resData) => {
const res = resData
info.value = res
})
})
onShow(() => {
getDetail()
})
const getDetail = async () => {
try {
await http.get(`/train/examinations/${id.value}`).then((resData) => {
const res = resData
info.value = res
})
notfound.value = false
} catch (error) {
const { statusCode } = error
if (statusCode == 404) {
notfound.value = true
}
}
}
const next = () => {
if (index.value < total.value - 1) {

View File

@ -6,8 +6,15 @@
</template>
</CuNavbar>
<view class="card-shadow px-base">
<uv-form labelPosition="left" :model="form" :rules="rules" ref="formRef" errorType="toast" labelWidth="250rpx">
<uv-form-item required label="日期" prop="date">
<uv-form
labelPosition="left"
:model="form"
:rules="rules"
ref="formRef"
errorType="toast"
labelWidth="250rpx"
>
<!-- <uv-form-item required label="日期" prop="date">
<uv-input
placeholder="请选择日期"
readonly
@ -18,7 +25,7 @@
>
</uv-input>
</uv-form-item>
<uv-line color="#f5f5f5"></uv-line>
<uv-line color="#f5f5f5"></uv-line> -->
<uv-form-item required label="加班开始时间" prop="start_at">
<uv-input
placeholder="请选择加班开始时间"
@ -30,7 +37,16 @@
>
</uv-input>
</uv-form-item>
<uv-form-item required label="加班结束时间" prop="end_at">
<uv-form-item required label="加班时长" prop="duration">
<uv-input
placeholder="请输入加班时长"
type="number"
inputAlign="right"
border="`none`"
v-model="form.duration"
></uv-input>
</uv-form-item>
<!-- <uv-form-item required label="加班结束时间" prop="end_at">
<uv-input
placeholder="请选择加班结束时间"
readonly
@ -40,10 +56,22 @@
v-model="form.end_at"
>
</uv-input>
</uv-form-item>
</uv-form-item> -->
<uv-line color="#f5f5f5"></uv-line>
<uv-form-item required label="请输入加班事由" prop="reason" labelPosition="top">
<uv-textarea :customStyle="{ padding: '0' }" v-model="form.reason" count placeholder="请输入加班事由" :border="`none`" :maxlength="200"></uv-textarea>
<uv-form-item
required
label="请输入加班事由"
prop="reason"
labelPosition="top"
>
<uv-textarea
:customStyle="{ padding: '0' }"
v-model="form.reason"
count
placeholder="请输入加班事由"
:border="`none`"
:maxlength="200"
></uv-textarea>
</uv-form-item>
</uv-form>
</view>
@ -72,15 +100,21 @@
@confirm="confirmEndDatePicker"
>
</uv-datetime-picker>
<uv-modal ref="modalRef" title="提示" content="确定提交吗?" @confirm="onSubmit" :showCancelButton="true"></uv-modal>
<uv-modal
ref="modalRef"
title="提示"
content="确定提交吗?"
@confirm="onSubmit"
:showCancelButton="true"
></uv-modal>
</view>
</template>
<script setup>
import CuNavbar from "@/components/cu-navbar/index"
import { ref, reactive, computed } from "vue"
import { onLoad } from "@dcloudio/uni-app"
import { http } from "@/utils/request"
import { timeFormat } from "@climblee/uv-ui/libs/function/index"
import CuNavbar from '@/components/cu-navbar/index'
import { ref, reactive, computed } from 'vue'
import { onLoad } from '@dcloudio/uni-app'
import { http } from '@/utils/request'
import { timeFormat } from '@climblee/uv-ui/libs/function/index'
const columns = ref([])
const pickerData = ref([])
const formRef = ref(null)
@ -94,15 +128,15 @@ const endValue = ref(Number(new Date()))
const id = ref(0)
const loading = ref(false)
const form = reactive({
start_at: "",
end_at: "",
reason: "",
date: ""
start_at: '',
end_at: '',
reason: '',
date: '',
})
const endTime = computed(()=>{
const endTime = computed(() => {
return {
min:form.start_at? new Date(form.start_at).getTime():null,
max:new Date().getTime()
min: form.start_at ? new Date(form.start_at).getTime() : null,
max: new Date().getTime(),
}
})
const openDate = () => {
@ -114,60 +148,78 @@ const openStartDatePicker = () => {
const openEndDatePicker = () => {
dateEndPicker.value.open()
}
const confirmDatePicker = e => {
form.date = timeFormat(e.value, "yyyy-mm-dd")
const confirmDatePicker = (e) => {
form.date = timeFormat(e.value, 'yyyy-mm-dd')
}
const confirmStartDatePicker = e => {
const confirmStartDatePicker = (e) => {
form.end_at = null
form.start_at = timeFormat(e.value, "yyyy-mm-dd hh:MM")
form.start_at = timeFormat(e.value, 'yyyy-mm-dd hh:MM')
}
const confirmEndDatePicker = e => {
form.end_at = timeFormat(e.value, "yyyy-mm-dd hh:MM")
const confirmEndDatePicker = (e) => {
form.end_at = timeFormat(e.value, 'yyyy-mm-dd hh:MM')
}
const rules = reactive({
start_at: [{ required: true, message: "请选择加班开始时间" }],
start_at: [{ required: true, message: '请选择加班开始时间' }],
duration: [
{
required: true,
message: '请输入加班时长',
},
{
type: 'integer',
message: '加班时长必须为整数',
},
{
type: 'integer',
min: 1,
message: '加班时长不能小于1小时',
},
],
end_at: [
{ required: true, message: "请选择加班结束时间" },
{ required: true, message: '请选择加班结束时间' },
{
validator: (rule, value, callback) => {
const startTime = new Date(form.start_at).getTime()
const endTime = new Date(value).getTime()
if (endTime < startTime) {
callback(new Error("结束时间不能小于开始时间"))
callback(new Error('结束时间不能小于开始时间'))
}
}
},{
},
},
{
validator: (rule, value, callback) => {
const endTime = new Date(value).getTime()
const startTime = new Date(form.start_at).getTime()
const diff = endTime-startTime
if(diff< 1000*60*60){
callback(new Error("加班时间不能小于1小时"))
const diff = endTime - startTime
if (diff < 1000 * 60 * 60) {
callback(new Error('加班时间不能小于1小时'))
}
}
}
},
},
],
reason: [{ required: true, message: "请输入加班事由" }],
date: [{ required: true, message: "请选择日期" }]
reason: [{ required: true, message: '请输入加班事由' }],
date: [{ required: true, message: '请选择日期' }],
})
onLoad(options => {
onLoad((options) => {
id.value = options.id
if (id.value) {
http
.request({
url: `/hr/overtimes/${options.id}`,
method: "GET",
method: 'GET',
header: {
Accept: "application/json"
}
Accept: 'application/json',
},
})
.then(res => {
.then((res) => {
startValue.value = res.start_at * 1000
endValue.value = res.end_at * 1000
dateValue.value = res.date * 1000
form.start_at = timeFormat(res.start_at, "yyyy-mm-dd hh:MM:ss")
form.end_at = timeFormat(res.end_at, "yyyy-mm-dd hh:MM:ss")
form.date = timeFormat(res.date, "yyyy-mm-dd")
form.start_at = timeFormat(res.start_at, 'yyyy-mm-dd hh:MM:ss')
form.end_at = timeFormat(res.end_at, 'yyyy-mm-dd hh:MM:ss')
form.date = timeFormat(res.date, 'yyyy-mm-dd')
// form.duration = res.duration
form.duration = res.hours
form.reason = res.reason
form.address = res.address
})
@ -175,8 +227,7 @@ onLoad(options => {
})
const submit = () => {
formRef.value.validate().then(res => {
formRef.value.validate().then((res) => {
//1
modalRef.value.open()
})
@ -186,24 +237,25 @@ const onSubmit = async () => {
if (loading.value) return
loading.value = true
try {
let url = id.value ? `/hr/overtimes/${id.value}` : "/hr/overtimes"
let method = id.value ? "PUT" : "POST"
let url = id.value ? `/hr/overtimes/${id.value}` : '/hr/overtimes'
let method = id.value ? 'PUT' : 'POST'
await http.request({
url: url,
method: method,
header: {
Accept: "application/json"
Accept: 'application/json',
},
data: {
start_at: form.start_at,
date: form.date,
// date: form.date,
duration: form.duration,
reason: form.reason,
end_at: form.end_at
}
// end_at: form.end_at,
},
})
uni.showToast({
title: "提交成功",
icon: "none"
title: '提交成功',
icon: 'none',
})
formRef.value.resetFields()
uni.$emit('refresh')

View File

@ -23,6 +23,7 @@
>
</uv-textarea>
</uv-form-item>
<uv-line color="#f5f5f5"></uv-line>
<uv-form-item label="" prop="photos">
<view class="w-full">
@ -44,6 +45,12 @@
</view>
</view>
</uv-form-item>
<uv-line color="#f5f5f5"></uv-line>
<uv-form-item labelPosition="left" label="匿名" prop="anonymous">
<view class="flex justify-end w-full">
<uv-switch v-model="form.anonymous"></uv-switch>
</view>
</uv-form-item>
</uv-form>
</view>
</view>
@ -70,6 +77,7 @@ const formRef = ref(null)
const form = reactive({
content: '',
photos: [],
anonymous: false,
})
const rules = reactive({
content: [
@ -147,7 +155,7 @@ const onSubmit = () => {
.post('/complaints', {
content: form.content,
photos: form.photos.map((item) => item.url),
anonymous: true,
anonymous: form.anonymous,
})
.then((ress) => {
uni.showToast({

View File

@ -21,6 +21,7 @@
border="none"
input-align="right"
type="password"
maxlength="15"
v-model="form.password"
placeholder="请输入密码"
></uv-input>
@ -30,6 +31,7 @@
<uv-input
border="none"
v-model="form.password2"
maxlength="15"
input-align="right"
type="password"
placeholder="请输入密码"
@ -62,7 +64,20 @@ const form = reactive({
password2: '',
})
const rules = reactive({
password: [{ required: true, message: '请输入新登录密码' }],
password: [
{ required: true, message: '请输入新登录密码' },
{
min: 6,
max: 15,
message: '密码长度在 6 到 15 个字符',
},
{
validator: (rule, value) => {
return /^[^\u4e00-\u9fa5]{0,}$/.test(value)
},
message: '密码不能包含中文',
},
],
password2: [
{ required: true, message: '请再次输入新登录密码' },
{

View File

@ -66,6 +66,7 @@
<uv-input
placeholder="请输入登录密码"
inputAlign="right"
maxlength="15"
type="password"
v-model="form.password"
:border="`none`"
@ -130,7 +131,20 @@ const rules = computed(() => {
},
],
username: [{ required: true, message: '请输入登录用户名' }],
password: [{ required: !isEdit.value, message: '请输入登录密码' }],
password: [
{ required: !isEdit.value, message: '请输入登录密码' },
{
min: 6,
max: 15,
message: '密码长度在 6 到 15 个字符',
},
{
validator: (rule, value) => {
return /^[^\u4e00-\u9fa5]{0,}$/.test(value)
},
message: '密码不能包含中文',
}
],
confirm_password: [
{ required: !isEdit.value, message: '请输入登录密码' },
{

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 9.4 KiB