liu
8 小时以前 611dd8268e40caa4d97e8954b85b5adaaef99afa
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>