| | |
| | | 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 '查看考勤规则'; |
| | |
| | | } |
| | | 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: { |
| | |
| | | layout: 'horizontal', |
| | | schema: [], |
| | | showDefaultActions: false, |
| | | handleValuesChange: (values) => { |
| | | syncLocationState(values); |
| | | }, |
| | | }); |
| | | |
| | | const [Modal, modalApi] = useVbenModal({ |
| | |
| | | } |
| | | 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); |
| | |
| | | } |
| | | 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(); |
| | | } |
| | |
| | | </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> |
| | | </template> |