From 611dd8268e40caa4d97e8954b85b5adaaef99afa Mon Sep 17 00:00:00 2001
From: liu <2021943741@qq.com>
Date: 星期一, 26 十月 2026 17:45:58 +0800
Subject: [PATCH] feat(hrm): 考勤规则支持地图定位打卡
---
src/views/hrm/attendance/rule/modules/form.vue | 81 +++++++++++++++++++++++++++++++++++++++-
1 files changed, 78 insertions(+), 3 deletions(-)
diff --git a/src/views/hrm/attendance/rule/modules/form.vue b/src/views/hrm/attendance/rule/modules/form.vue
index 60bff96..a0a6eb8 100644
--- a/src/views/hrm/attendance/rule/modules/form.vue
+++ b/src/views/hrm/attendance/rule/modules/form.vue
@@ -13,11 +13,21 @@
import { $t } from '#/locales';
import { useFormSchema } from '../data';
+import LocationMapPicker from './location-map-picker.vue';
const emit = defineEmits(['success']);
const formType = ref<FormType>('create');
+/** 鍦板浘閫夋嫨鍣ㄦ墍闇�鐨勫畾浣嶇姸鎬侊紝闅忚〃鍗曞�煎彉鍖栧悓姝� */
+const locationRequired = ref(false);
+const longitude = ref<number>();
+const latitude = ref<number>();
+const radiusMeters = ref(10);
+
const isDetail = computed(() => formType.value === 'detail');
+const modalWidth = computed(() =>
+ locationRequired.value ? 'w-[1000px]' : 'w-[800px]',
+);
const getTitle = computed(() => {
if (formType.value === 'detail') {
return '鏌ョ湅鑰冨嫟瑙勫垯';
@@ -27,6 +37,43 @@
}
return '鏂板鑰冨嫟瑙勫垯';
});
+
+function toNumber(value: unknown): number | undefined {
+ return value === null || value === undefined || value === ''
+ ? undefined
+ : Number(value);
+}
+
+/** 琛ㄥ崟鍊煎彉鍖栨椂鍚屾瀹氫綅鐘舵�侊紝鐢ㄤ簬鎺у埗鍦板浘鍖哄煙涓庡脊绐楀搴� */
+function syncLocationState(
+ values: Partial<HrmAttendanceRuleApi.AttendanceRule>,
+) {
+ locationRequired.value = Boolean(values.locationRequired);
+ longitude.value = toNumber(values.longitude);
+ latitude.value = toNumber(values.latitude);
+ radiusMeters.value = toNumber(values.radiusMeters) ?? 10;
+}
+
+/** 鍦板浘閫夌偣鍚庡洖濉粡绾害锛屽苟灏介噺琛ュ叏鍦扮偣鍚嶇О涓庡湴鍧� */
+async function handleMapSelect(location: {
+ address?: string;
+ latitude: number;
+ locationName?: string;
+ longitude: number;
+}) {
+ const currentValues = await formApi.getValues();
+ longitude.value = location.longitude;
+ latitude.value = location.latitude;
+ await formApi.setFieldValue('longitude', location.longitude);
+ await formApi.setFieldValue('latitude', location.latitude);
+ await formApi.setFieldValue('coordinateSystem', 'WGS84');
+ if (location.address) {
+ await formApi.setFieldValue('locationAddress', location.address);
+ }
+ if (!currentValues.locationName && location.locationName) {
+ await formApi.setFieldValue('locationName', location.locationName);
+ }
+}
const [Form, formApi] = useVbenForm({
commonConfig: {
@@ -40,6 +87,9 @@
layout: 'horizontal',
schema: [],
showDefaultActions: false,
+ handleValuesChange: (values) => {
+ syncLocationState(values);
+ },
});
const [Modal, modalApi] = useVbenModal({
@@ -54,6 +104,10 @@
}
modalApi.lock();
const data = (await formApi.getValues()) as HrmAttendanceRuleApi.AttendanceRule;
+ // 鍚庣浠呮帴鍙� WGS84锛屼笖鍚敤瀹氫綅鏃惰姹傚潗鏍囩郴蹇呭~
+ if (data.locationRequired) {
+ data.coordinateSystem = 'WGS84';
+ }
try {
if (formType.value === 'update') {
await updateAttendanceRule(data);
@@ -73,15 +127,26 @@
}
const data = modalApi.getData<{ formType: FormType; id?: number }>();
formType.value = data.formType;
+ locationRequired.value = false;
+ longitude.value = undefined;
+ latitude.value = undefined;
+ radiusMeters.value = 10;
formApi.setState({ schema: useFormSchema(data.formType) });
formApi.setDisabled(data.formType === 'detail');
modalApi.setState({ showConfirmButton: data.formType !== 'detail' });
if (!data?.id) {
+ await formApi.setValues({
+ coordinateSystem: 'WGS84',
+ locationRequired: false,
+ radiusMeters: 10,
+ });
return;
}
modalApi.lock();
try {
- await formApi.setValues(await getAttendanceRule(data.id));
+ const rule = await getAttendanceRule(data.id);
+ await formApi.setValues(rule);
+ syncLocationState(rule);
} finally {
modalApi.unlock();
}
@@ -90,7 +155,17 @@
</script>
<template>
- <Modal :title="getTitle" class="w-[800px]">
+ <Modal :title="getTitle" :class="modalWidth">
<Form class="mx-4" />
+ <section v-if="locationRequired" class="mx-4 mt-2">
+ <div class="mb-2 text-sm font-medium">鍦板浘閫夋嫨鎵撳崱鑼冨洿</div>
+ <LocationMapPicker
+ :disabled="isDetail"
+ :latitude="latitude"
+ :longitude="longitude"
+ :radius-meters="radiusMeters"
+ @select="handleMapSelect"
+ />
+ </section>
</Modal>
-</template>
\ No newline at end of file
+</template>
--
Gitblit v1.9.3