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

View File

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

View File

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

View File

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

View File

@ -21,6 +21,7 @@
border="none" border="none"
input-align="right" input-align="right"
type="password" type="password"
maxlength="15"
v-model="form.password" v-model="form.password"
placeholder="请输入密码" placeholder="请输入密码"
></uv-input> ></uv-input>
@ -30,6 +31,7 @@
<uv-input <uv-input
border="none" border="none"
v-model="form.password2" v-model="form.password2"
maxlength="15"
input-align="right" input-align="right"
type="password" type="password"
placeholder="请输入密码" placeholder="请输入密码"
@ -62,7 +64,20 @@ const form = reactive({
password2: '', password2: '',
}) })
const rules = reactive({ 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: [ password2: [
{ required: true, message: '请再次输入新登录密码' }, { required: true, message: '请再次输入新登录密码' },
{ {

View File

@ -66,6 +66,7 @@
<uv-input <uv-input
placeholder="请输入登录密码" placeholder="请输入登录密码"
inputAlign="right" inputAlign="right"
maxlength="15"
type="password" type="password"
v-model="form.password" v-model="form.password"
:border="`none`" :border="`none`"
@ -130,7 +131,20 @@ const rules = computed(() => {
}, },
], ],
username: [{ required: true, message: '请输入登录用户名' }], 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: [ confirm_password: [
{ required: !isEdit.value, message: '请输入登录密码' }, { required: !isEdit.value, message: '请输入登录密码' },
{ {

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 9.4 KiB