user-form.vue 7.65 KB
<script setup lang="ts">
  import { fetchEventSource, EventSourceMessage } from '@microsoft/fetch-event-source';

  import {
    Form,
    FormItem,
    Upload,
    Input,
    Select,
    RangePicker,
    DatePicker,
    Timeline,
    TimelineItem,
    Link,
    RequestOption,
  } from '@arco-design/web-vue';
  import { ref, computed, onMounted, createVNode } from 'vue';
  import { getToken } from '@/utils/auth';
  import { createModalVNode } from '@/utils/createVNode';
  import UserTableItem from '@/views/operation/broker/components/user-table-item.vue';
  import useConfigApi from '@/http/config';
  // import { downloadFile } from '@/http/auth';
  import { first, last, range } from 'lodash';
  import { isEqual } from '@arco-design/web-vue/es/_utils/is-equal';
  import dayjs, { OpUnitType } from 'dayjs';
  import { BrokerUserConfig } from '@/http/broker';

  const pushOption = [
    { value: 0, label: '不通知' },
    { value: 1, label: '系统通知' },
    { value: 2, label: '系统通知+面板提醒' },
  ];

  const props = defineProps<{
    initValue?: BrokerUserConfig;
    disabled?: boolean;
    disabledUpload?: boolean;
    disabledType?: boolean;
    submit?: (value: unknown) => Promise<any>;
  }>();

  const templateUrl = ref('');

  onMounted(async () => {
    templateUrl.value = (await useConfigApi.getOne({ identifier: 't8iH6OBLP_WkzP-ILhF48', parent_id: 0 }))?.content || '';
  });

  const formRef = ref();
  const formValue = ref<Omit<BrokerUserConfig, 'id' | 'user_id'>>({
    title: '',
    begin_at: '',
    end_at: '',
    push_type: 0,
    push_at: '',
    items: [],
    ...props.initValue,
  });
  const formRule = computed(() => {
    return {
      title: [{ required: true, message: '请输入名称' }],
      begin_at: [{ required: true, message: '请选择生效时间' }],
      push_type: [{ required: true, message: '请选择推送方式' }],
      push_at: [{ required: !isEqual(formValue.value.push_type, 0), message: '请选择推送时间' }],
    };
  });

  const showTable = ref(!!props.initValue?.items);
  const timePending = ref<string | false>(false);

  const matchTotal = computed(() => formValue.value?.items?.filter((item) => item?.status === 1)?.length || 0);

  const isFullMatch = computed(() => matchTotal.value !== 0 && formValue.value.items?.length === matchTotal.value);

  const activationTime = computed({
    get: () => [formValue.value.begin_at, formValue.value.end_at],
    set: (val) => {
      formValue.value.begin_at = first(val) || '';
      formValue.value.end_at = last(val) || '';
    },
  });

  const onSubmit = async () => {
    const error = await formRef.value?.validate();
    // eslint-disable-next-line no-use-before-define
    if (timePending.value) {
      // eslint-disable-next-line prefer-promise-reject-errors
      return Promise.reject(false);
    }
    return error ? Promise.reject(error) : props.submit?.(formValue.value);
  };

  defineExpose({ onSubmit });

  const isSameTime = (date: dayjs.ConfigType, unit: OpUnitType) => dayjs().isSame(dayjs(date), unit);

  const disabledDate = (current?: Date) => dayjs(current).isBefore(dayjs().subtract(1, 'day'));
  const disabledTime = (current?: Date) => {
    return {
      disabledHours: () => range(0, 23).filter((item) => isSameTime(current, 'day') && item < dayjs().hour()),
      disabledMinutes: () =>
        range(0, 59).filter(
          (item) => isSameTime(current, 'day') && isSameTime(current, 'hour') && item < dayjs().add(5, 'minute').minute()
        ),
    };
  };
  // const onDownTemplate = () => downloadFile(templateUrl.value, '运营经纪人-经纪人配置');

  const onViewItem = () =>
    createModalVNode(() => createVNode(UserTableItem, { source: formValue.value.items }), {
      width: '760px',
      bodyStyle: { padding: '16px' },
      footer: false,
      maskClosable: true,
      escToClose: true,
    });

  const finishParse = () => {
    timePending.value = false;
    showTable.value = true;
  };

  const onUpload = async ({ fileItem, onSuccess }: RequestOption) => {
    const formData = new FormData();
    formData.append('file', fileItem.file as File);
    showTable.value = false;
    timePending.value = '检查表格中的数据...';

    await fetchEventSource(`${import.meta.env.VITE_API_HOST}/admin/system/broker/user-configs/upload`, {
      method: 'POST',
      openWhenHidden: true,
      headers: { Authorization: `Bearer ${getToken()}` },
      body: formData,
      onopen() {
        formValue.value.items = [];
        onSuccess();
        return Promise.resolve();
      },
      onclose() {
        throw new Error();
      },
      onmessage(ev: EventSourceMessage) {
        if (ev.event === 'finish') {
          finishParse();
          throw new Error('finish');
        }
        if (ev.event === 'item') {
          formValue.value.items?.push({ user_id: ev.id, ...JSON.parse(ev.data) });
        }
      },
      onerror() {
        finishParse();
        throw new Error('close');
      },
    });
  };
</script>

<template>
  <Form
    ref="formRef"
    :model="formValue"
    :rules="formRule"
    :disabled="disabled as boolean"
    layout="horizontal"
    size="small"
    auto-label-width
  >
    <FormItem label="名称" field="title" show-colon>
      <Input v-model="formValue.title" placeholder="请输入" :max-length="100" show-word-limit />
    </FormItem>
    <FormItem label="生效时间" show-colon field="begin_at">
      <RangePicker
        v-model="activationTime"
        style="width: 100%"
        :time-picker-props="{ defaultValue: ['00:00:00', '23:59:59'] }"
        :day-start-of-week="1"
        value-format="YYYY-MM-DD HH:mm:ss"
        format="YYYY-MM-DD"
      />
    </FormItem>
    <FormItem v-if="!disabledType" label="系统通知" field="push_type" show-colon>
      <Select v-model="formValue.push_type" :options="pushOption" placeholder="请选择" :disabled="disabledType as boolean" />
    </FormItem>
    <FormItem v-if="!disabledType && formValue.push_type" label="推送时间" field="push_at" show-colon>
      <DatePicker
        v-model="formValue.push_at"
        show-time
        :day-start-of-week="1"
        :show-now-btn="false"
        :disabled="disabledType as boolean"
        :disabled-input="true"
        :disabled-date="disabledDate"
        :disabled-time="disabledTime"
        style="width: 100%"
        value-format="YYYY-MM-DD HH:mm:ss"
        format="YYYY-MM-DD HH:mm"
      />
    </FormItem>
    <FormItem row-class="mb-0">
      <Timeline :pending="timePending">
        <TimelineItem>
          下载模版
          <template #label>
            <Link :href="templateUrl" :hoverable="false">点击此处下载模板</Link>
          </template>
        </TimelineItem>
        <TimelineItem>
          在模板中添加要推送的经纪人,并将表格上传
          <template #label>
            <Upload accept=".xls,.xlsx" :show-file-list="false" :custom-request="onUpload" :disabled="disabledUpload || !!timePending">
              <template #upload-button>
                <Link h :hoverable="false" :disabled="disabledUpload || !!timePending">点击此处上传表格</Link>
              </template>
            </Upload>
          </template>
        </TimelineItem>
        <TimelineItem v-if="showTable">
          <template v-if="isFullMatch">数据检查:全部识别,共 {{ matchTotal }} 名经纪人</template>
          <template v-else>数据检查:已匹配 {{ matchTotal }} 人,未匹配 {{ formValue.items?.length - matchTotal }} 人!</template>
          <template #label>
            <Link :hoverable="false" @click="onViewItem">查看匹配信息</Link>
          </template>
        </TimelineItem>
      </Timeline>
    </FormItem>
  </Form>
</template>

<style scoped lang="less"></style>