浏览代码

feat: 工程师端保养记录模块

Tong 2 年之前
父节点
当前提交
43afe69289

+ 46 - 0
src/api/biz/engineer/upkeepApi.ts

@@ -0,0 +1,46 @@
+import { defHttp } from '/@/utils/http/axios';
+import { setParams } from '/@/utils/index';
+
+enum Api {
+  upkeepQueryPage = '/biz/device/dialysisMaintain/query/page',
+  upkeepDetail = '/biz/device/dialysisMaintain/detail',
+  upkeepAdd = '/biz/device/dialysisMaintain/add',
+  upkeepEdit = '/biz/device/dialysisMaintain/edit',
+  upkeepRemove = '/biz/device/dialysisMaintain/removeByIds/',
+  upkeepCompanyCount = '/biz/device/dialysisMaintain/maintainCompany',
+  getDeviceList = '/biz/device/dialysisMaintain/allMaintainDevice',
+  getDeviceListRecently = '/biz/device/dialysisMaintain/needMaintainDevice',
+}
+
+// 获取Tab各方数量
+export function upkeepCompanyCount() {
+  return defHttp.get({ url: Api.upkeepCompanyCount });
+}
+
+export const upkeepQueryPage = (params?: object) => {
+  return defHttp.post({ url: Api.upkeepQueryPage, params: setParams(params) });
+};
+
+export const upkeepRemove = (params: Array<string | number>) => {
+  return defHttp.post({ url: Api.upkeepRemove, params: params });
+};
+
+export const upkeepAdd = (params?: object) => {
+  return defHttp.post({ url: Api.upkeepAdd, params: params });
+};
+
+export const upkeepEdit = (params?: object) => {
+  return defHttp.post({ url: Api.upkeepEdit, params: params });
+};
+
+export const upkeepDetail = (id: string) => {
+  return defHttp.get({ url: Api.upkeepDetail + '/' + id });
+};
+
+export const getDeviceList = () => {
+  return defHttp.get({ url: Api.getDeviceList });
+};
+
+export const getDeviceListRecently = () => {
+  return defHttp.get({ url: Api.getDeviceListRecently });
+};

+ 120 - 0
src/views/biz/engineer/upkeep/data.ts

@@ -0,0 +1,120 @@
+import { BasicColumn, FormSchema } from '/@/components/Table';
+import { listDictModel, uploadApi } from '/@/api/common';
+
+export const columns: BasicColumn[] = [
+  {
+    title: '设备编号',
+    dataIndex: 'deviceUniqueCode',
+  },
+  {
+    title: '设备厂家',
+    dataIndex: 'deviceManufacturer',
+  },
+  {
+    title: '设备型号',
+    dataIndex: 'deviceModel',
+  },
+  {
+    title: '保养时间',
+    dataIndex: 'maintainTime',
+  },
+  {
+    title: '保养方',
+    dataIndex: 'maintainCompany',
+  },
+  {
+    title: '保养内容',
+    dataIndex: 'content',
+  },
+  {
+    title: '保养费用(元)',
+    dataIndex: 'costYuan',
+  },
+  {
+    title: '保养照片',
+    dataIndex: 'picture',
+  },
+];
+// 表单新增编辑
+export const dataFormSchema: FormSchema[] = [
+  {
+    label: '保养设备',
+    field: 'devices',
+    component: 'PlainTitle',
+    defaultValue: '保养设备',
+  },
+  {
+    field: 'deviceInfos',
+    component: 'Input',
+    slot: 'deviceInfos',
+  },
+  {
+    label: '保养记录',
+    field: 'recording',
+    component: 'PlainTitle',
+    defaultValue: '保养记录',
+  },
+  {
+    label: '保养时间',
+    field: 'maintainTime',
+    component: 'DatePicker',
+    componentProps: {
+      placeholder: '请输入上传日期',
+      getPopupContainer: () => document.body,
+      valueFormat: 'YYYY-MM-DD HH:mm:ss',
+      format: 'YYYY-MM-DD HH:mm:ss',
+      showTime: true,
+    },
+    colProps: {
+      span: 12,
+    },
+  },
+  {
+    label: '保养方',
+    field: 'maintainCompany',
+    component: 'ApiSelect',
+    componentProps: {
+      api: listDictModel,
+      params: {
+        dictCode: 'dmc',
+      },
+    },
+    colProps: {
+      span: 12,
+    },
+  },
+  {
+    label: '保养内容',
+    field: 'content',
+    component: 'InputTextArea',
+    componentProps: {
+      placeholder: '请输入保养内容',
+    },
+  },
+  {
+    label: '保养费用(元)',
+    field: 'costYuan',
+    component: 'InputNumber',
+    componentProps: {
+      placeholder: '请输入保养费用',
+    },
+  },
+  {
+    label: '保养图片',
+    field: 'files',
+    component: 'XTUpload',
+    componentProps: ({ formModel, schema }) => {
+      return {
+        api: uploadApi,
+        maxSize: 2,
+        maxNumber: 1,
+        helpText: '仅支持上传jpg/png/pdf文件,文件大小不超过2M',
+        accept: ['image/*', '.pdf', '.doc', 'docx', 'xls'],
+        onChange: data => {
+          console.log('🚀 ~ file: data.ts:57 ~ data:', data);
+          formModel[schema.field] = data;
+        },
+      };
+    },
+  },
+];

+ 178 - 0
src/views/biz/engineer/upkeep/formDrawer.vue

@@ -0,0 +1,178 @@
+<template>
+  <BasicDrawer
+    v-bind="$attrs"
+    destroyOnClose
+    @register="registerDrawer"
+    :title="getTitle"
+    :width="width"
+    @ok="handleSubmit"
+    :showFooter="true"
+  >
+    <BasicForm @register="registerForm" layout="vertical">
+      <template #deviceInfos>
+        <div class="device-info" v-if="isUpdate">
+          <div :class="['device-card', 'card-disable']">
+            {{
+              deviceDetail.uniqueCode +
+              ' ' +
+              deviceDetail.manufacturer +
+              ' ' +
+              deviceDetail.deviceType
+            }}
+          </div>
+        </div>
+        <div class="device-info" v-else>
+          <div
+            v-for="(item, index) in deviceList"
+            :key="index"
+            :class="['device-card', item.isSel ? 'card-select' : '']"
+            @click="handleSelDevice(item)"
+            >{{ item.uniqueCode + ' ' + item.manufacturer + ' ' + item.adviceModel }}</div
+          >
+        </div>
+      </template>
+    </BasicForm>
+  </BasicDrawer>
+</template>
+<script lang="ts" setup>
+  import { ref, computed, unref } from 'vue';
+  import { BasicDrawer, useDrawerInner } from '/@/components/Drawer';
+  import { BasicForm, useForm } from '/@/components/Form';
+  import { useMessage } from '/@/hooks/web/useMessage';
+  import { dataFormSchema } from './data';
+
+  import {
+    getDeviceList,
+    upkeepAdd,
+    upkeepEdit,
+    upkeepDetail,
+    getDeviceListRecently,
+  } from '/@/api/biz/engineer/upkeepApi';
+  import { engineerDialysisDeviceDetail } from '/@/api/biz/engineer/dialysisDeviceApi';
+  const emit = defineEmits(['success', 'register']);
+  const getTitle = computed(() => (!unref(isUpdate) ? '新增保养记录' : '编辑保养记录'));
+  const width = '35%';
+  const isUpdate = ref(false);
+  const deviceDetail = ref({
+    uniqueCode: null,
+    manufacturer: null,
+    deviceType: null,
+  });
+  const detailData = ref();
+  const rowId = ref();
+  const deviceList = ref([]);
+  const deviceSelIds = ref([]);
+  const { createMessage } = useMessage();
+  const [registerForm, { setFieldsValue, resetFields, validate }] = useForm({
+    labelWidth: 100,
+    schemas: dataFormSchema,
+    showActionButtonGroup: false,
+    actionColOptions: {
+      span: 23,
+    },
+  });
+  const [registerDrawer, { setDrawerProps, closeDrawer }] = useDrawerInner(async data => {
+    await resetFields();
+    setDrawerProps({ confirmLoading: false });
+    isUpdate.value = !!data?.isUpdate;
+    if (unref(isUpdate)) {
+      const resData = await upkeepDetail(data.record.id);
+      rowId.value = resData.id;
+      detailData.value = resData;
+      deviceDetail.value = await engineerDialysisDeviceDetail(resData.deviceId);
+      await setFieldsValue({
+        ...resData,
+      });
+    } else {
+      if (data.isRecently) {
+        deviceList.value = await getDeviceListRecently();
+      } else {
+        deviceList.value = await getDeviceList();
+      }
+    }
+  });
+
+  // 提交按钮事件
+  async function handleSubmit() {
+    try {
+      const values = await validate();
+      let updateVal = {};
+      setDrawerProps({ confirmLoading: true });
+      values.picture = values.files && values.files.map(ele => ele.id);
+      if (!isUpdate.value) {
+        if (deviceSelIds.value && deviceSelIds.value.length > 0) {
+          values.deviceIds = deviceSelIds.value;
+        } else {
+          createMessage.error('请选择需要保养的设备');
+          return false;
+        }
+      } else {
+        updateVal = { ...detailData.value, ...values };
+      }
+      debugger;
+      !unref(isUpdate)
+        ? await upkeepAdd({ ...values })
+        : await upkeepEdit({ ...updateVal, id: rowId.value });
+      !unref(isUpdate) ? createMessage.success('新增成功!') : createMessage.success('编辑成功!');
+      closeDrawer();
+      emit('success', {
+        isUpdate: unref(isUpdate),
+        values: { ...values, id: rowId.value },
+      });
+    } finally {
+      setDrawerProps({ confirmLoading: false });
+    }
+  }
+
+  // 选中需要保养的设备
+  function handleSelDevice(item) {
+    if (item.isSel) {
+      deviceSelIds.value = deviceSelIds.value.filter(val => val != item.id);
+    } else {
+      deviceSelIds.value.push(item.id);
+    }
+    deviceList.value.forEach(val => {
+      if (item.id === val.id) {
+        item.isSel = item.isSel ? !item.isSel : true;
+      }
+    });
+  }
+</script>
+<style lang="less" scoped>
+  .device-info {
+    width: 100%;
+    max-height: 520px;
+    margin-top: -30px;
+    overflow: auto;
+
+    .device-card {
+      display: inline-block;
+      width: 270px;
+      height: 40px;
+      margin: 10px 20px;
+      background: #f4f6f9;
+      border-radius: 4px;
+      font-size: 14px;
+      font-weight: 500;
+      color: #000a18;
+      text-align: center;
+      line-height: 40px;
+      cursor: pointer;
+    }
+
+    .card-select {
+      background: #fff;
+      border-radius: 4px;
+      border: 1px solid #006dff;
+      color: #006dff;
+    }
+
+    .card-disable {
+      background: #fff;
+      border-radius: 4px;
+      border: 1px solid #a5a5a5;
+      color: #a5a5a5;
+      cursor: default;
+    }
+  }
+</style>

+ 305 - 3
src/views/biz/engineer/upkeep/index.vue

@@ -1,7 +1,309 @@
 <template>
-  <div> 占位符 </div>
+  <div class="m-4 modals">
+    <div>
+      <XTTitle title="保养记录" :right-data="titleData" @click="callTitleClick" />
+      <div class="flex items-center justify-between my-4">
+        <XTTab
+          type="illness"
+          :width="180"
+          :selected="tabSelected"
+          :data="typeOptions"
+          @item-click="callTab"
+        />
+        <XTForm :form-data="formData" @change="callForm" />
+      </div>
+    </div>
+    <BasicTable @register="registerTable">
+      <template #bodyCell="{ column, record }">
+        <template v-if="column.key === 'picture'">
+          <Image :width="80" :src="record.files ? record.files[0].absolutePath : null" />
+        </template>
+        <template v-if="column.key === 'maintainCompany'">
+          <span> {{ formatDictValue(typeCategoryOptions, record.maintainCompany) }}</span>
+        </template>
+        <template v-if="column.key === 'action'">
+          <TableAction
+            :actions="[
+              {
+                auth: 'biz:consumable:edit',
+                icon: 'icon-xt-details_edit_default|iconfont',
+                tooltip: '编辑',
+                onClick: handleEdit.bind(null, record),
+              },
+              {
+                auth: 'biz:dialysisMaintain:remove',
+                icon: 'icon-xt-details_delete_default|iconfont',
+                tooltip: '删除',
+                popConfirm: {
+                  title: '是否确认删除',
+                  placement: 'left',
+                  confirm: handleDelete.bind(null, record),
+                },
+              },
+            ]"
+          />
+        </template>
+      </template>
+    </BasicTable>
+    <FormDrawer @register="registerDrawer" @success="callSuccess" @cancel="handleCancel" />
+  </div>
 </template>
+<script lang="ts" setup>
+  import { onBeforeMount, ref } from 'vue';
+  import { message } from 'ant-design-vue';
+  import { BasicTable, useTable, TableAction } from '/@/components/TableCard';
+  import { useMessage } from '/@/hooks/web/useMessage';
+  import FormDrawer from './formDrawer.vue';
+  import { formatDictValue } from '/@/utils';
+  import { columns } from './data';
+  import { Image } from 'ant-design-vue';
+  import {
+    upkeepQueryPage,
+    upkeepRemove,
+    upkeepCompanyCount,
+    getDeviceListRecently,
+  } from '/@/api/biz/engineer/upkeepApi';
+  import { listDictModel } from '/@/api/common';
+  import { useDrawer } from '/@/components/Drawer';
+  import { XTTitle } from '/@/components/XTTitle/index';
+  import { XTTab } from '/@/components/XTTab/index';
+  import { XTForm } from '/@/components/XTForm/index';
 
-<script setup lang="ts"></script>
+  // 标题数据
+  const titleData = [
+    {
+      type: 'add',
+      btnIcon: 'icon-xt-add_default',
+      auth: ['biz:consumable:add'],
+      btnText: '新增保养',
+    },
+  ];
+  // formdata
+  const formData = [
+    {
+      name: 'shiftDate',
+      componentType: 'RangePicker',
+      format: 'YYYY-MM-DD',
+      valueFormat: 'YYYY-MM-DD',
+      placeholder: '请选择日期',
+      width: 280,
+    },
+    {
+      name: 'searchNames',
+      componentType: 'Input',
+      prefix: 'icon-xt-search',
+      placeholder: '请输入设备编号',
+      width: 240,
+    },
+  ];
+  // tab 切换选中
+  const tabSelected = ref();
+  // 操作名称
+  const searchNames = ref('');
+  const shiftDate = ref([]);
 
-<style lang="less" scoped></style>
+  const typeOptions = ref();
+  const typeCategoryOptions = ref();
+  onBeforeMount(async () => {
+    typeCategoryOptions.value = await listDictModel({ dictCode: 'dmc' });
+    handleDeviceListRecently();
+    getTab();
+  });
+
+  const { createMessage } = useMessage();
+  const [registerDrawer, { openDrawer }] = useDrawer();
+
+  const tableSort = ref([
+    {
+      field: 'create_time',
+      direction: 'DESC',
+    },
+  ]) as any;
+
+  const [registerTable, { reload, clearSelectedRowKeys }] = useTable({
+    api: upkeepQueryPage,
+    batchDelApi: upkeepRemove,
+    // batchExportApi: suppliesExport,
+    delAuthList: ['biz:dialysisMaintain:remove'],
+    rowKey: 'id',
+    columns,
+    showIndexColumn: true,
+    bordered: true,
+    actionColumn: {
+      width: 200,
+      title: '操作',
+      dataIndex: 'action',
+    },
+    beforeFetch: handleBeforeFetch,
+    sortFn: handleSortFn,
+  });
+  // 详情按钮事件
+  function handleEdit(record) {
+    openDrawer(true, {
+      record,
+      isUpdate: true,
+    });
+  }
+
+  // 新增按钮事件
+  function callTitleClick(data) {
+    if (data.type == 'add') {
+      openDrawer(true, {
+        isUpdate: false,
+        record: data,
+      });
+    } else if (data.type == 'print') {
+      console.log('打印中...');
+    }
+  }
+
+  // 删除按钮事件
+  async function handleDelete(record: Recordable) {
+    if (record) {
+      await upkeepRemove([record.id]);
+      createMessage.success('记录删除成功!');
+      clearSelectedRowKeys();
+      await reload();
+      await getTab();
+    }
+  }
+  // 表格点击字段排序
+  function handleSortFn(sortInfo) {
+    if (sortInfo?.order && sortInfo?.columnKey) {
+      // 默认单列排序
+      tableSort.value = [
+        {
+          field: sortInfo.columnKey,
+          direction: sortInfo.order.replace(/(\w+)(end)/g, '$1').toUpperCase(),
+        },
+      ];
+    }
+  }
+
+  // 表格请求之前,对参数进行处理, 添加默认 排序
+  async function handleBeforeFetch(params) {
+    console.log('searchNames:::', searchNames.value);
+    return {
+      ...params,
+      orders: tableSort.value,
+      uniqueCode: searchNames.value == '' ? undefined : searchNames.value,
+      maintainCompany: tabSelected.value == '' ? undefined : tabSelected.value,
+      maintainTime: shiftDate.value.length <= 0 ? undefined : shiftDate.value,
+    };
+  }
+
+  async function getTab() {
+    typeOptions.value = await listDictModel({ dictCode: 'dmc' });
+    const typeNums = await upkeepCompanyCount(); // 获取各类型数量
+    let typeList = [];
+    typeOptions.value.forEach(ele => {
+      // 变量各类型放置对应数量
+      let typeData = {};
+      Object.keys(typeNums).forEach(numKey => {
+        if (ele.value == numKey) {
+          typeData = {
+            key: ele.value,
+            label: ele.label,
+            value: typeNums[numKey],
+            hasValue: true,
+            prefixColor: ele.prefixColor,
+            hasBracket: true,
+          };
+          typeList.push(typeData);
+        }
+      });
+    });
+    typeList = typeList.reverse();
+    typeList.splice(0, 0, {
+      key: '',
+      label: '全部',
+      value: typeNums.total,
+      hasValue: true,
+      hasBracket: true,
+    });
+    typeOptions.value = typeList;
+    tabSelected.value = typeOptions.value[0].key;
+  }
+
+  //取消按钮事件
+  async function handleCancel() {
+    clearSelectedRowKeys();
+    await reload();
+    await getTab();
+  }
+
+  // 弹窗回调事件
+  async function callSuccess({ isUpdate, values }) {
+    console.log(isUpdate);
+    console.log(values);
+    await reload();
+    await getTab();
+  }
+  // 选项卡组件回调
+  async function callTab(data) {
+    tabSelected.value = data.value;
+    await reload();
+  }
+
+  // 查询组件回调
+  async function callForm(data) {
+    shiftDate.value = data.shiftDate ? data.shiftDate : '';
+    searchNames.value = data.searchNames ? data.searchNames : '';
+    console.log('callForm:::', searchNames.value);
+    await reload();
+  }
+
+  // 查询是否有近日需要保养的设备
+  async function handleDeviceListRecently() {
+    const res = await getDeviceListRecently();
+
+    if (res && res.length > 0) {
+      await message.warning({
+        key: '1',
+        content: '有需要保养的设备',
+        duration: 10,
+        style: {
+          color: '#1890ff',
+          cursor: 'pointer',
+        },
+        onClick: async () => {
+          openDrawer(true, {
+            isUpdate: false,
+            isRecently: true,
+          });
+          await message.destroy('1');
+        },
+      });
+    }
+  }
+</script>
+<style lang="less" scoped>
+  .table-dot {
+    display: inline-block;
+    width: 10px;
+    height: 10px;
+    margin-right: 6px;
+    border-radius: 50%;
+  }
+
+  ::v-deep(.ant-btn-link) {
+    color: #3d4155;
+  }
+
+  ::v-deep(.ant-input-prefix) {
+    color: #8a99ac;
+  }
+
+  .colUpdateAvatar {
+    display: flex;
+    justify-content: center;
+    text-align: center;
+    line-height: 28px;
+  }
+
+  .colImg {
+    width: 28px;
+    height: 28px;
+    margin-right: 5px;
+  }
+</style>