| | |
| | | <script lang="ts" setup> |
| | | import { onMounted, ref } from 'vue'; |
| | | |
| | | import { Page } from '@vben/common-ui'; |
| | | import { Page, useVbenModal } from '@vben/common-ui'; |
| | | |
| | | import { DatePicker, Select, Spin } from 'ant-design-vue'; |
| | | import { DatePicker, message, Select, Spin } from 'ant-design-vue'; |
| | | import dayjs from 'dayjs'; |
| | | |
| | | import { getForecastList } from '#/api/bi/decision/forecast'; |
| | | import { useVbenForm } from '#/adapter/form'; |
| | | import { |
| | | generateForecastWorkOrder, |
| | | getForecastList, |
| | | } from '#/api/bi/decision/forecast'; |
| | | |
| | | defineOptions({ name: 'DecisionForecastAnalysis' }); |
| | | |
| | |
| | | { label: '日负荷预测', value: 'load_forecast_daily' }, |
| | | { label: '周负荷预测', value: 'load_forecast_weekly' }, |
| | | { label: '月负荷预测', value: 'load_forecast_monthly' }, |
| | | ]; |
| | | |
| | | const WORK_ORDER_TYPE_OPTIONS = [ |
| | | { label: '电力运维', value: 4 }, |
| | | { label: '发电', value: 5 }, |
| | | { label: '检修', value: 6 }, |
| | | ]; |
| | | |
| | | async function loadData() { |
| | |
| | | } |
| | | |
| | | onMounted(loadData); |
| | | |
| | | /** ========== 生成工单 ========== */ |
| | | const [Form, formApi] = useVbenForm({ |
| | | commonConfig: { |
| | | componentProps: { |
| | | class: 'w-full', |
| | | }, |
| | | labelWidth: 100, |
| | | }, |
| | | wrapperClass: 'grid-cols-1', |
| | | layout: 'vertical', |
| | | schema: [ |
| | | { |
| | | fieldName: 'forecastId', |
| | | component: 'Input', |
| | | dependencies: { |
| | | triggerFields: [''], |
| | | show: () => false, |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'workOrderName', |
| | | label: '工单名称', |
| | | component: 'Input', |
| | | componentProps: { |
| | | placeholder: '请输入工单名称', |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'workOrderType', |
| | | label: '工单类型', |
| | | component: 'Select', |
| | | componentProps: { |
| | | options: WORK_ORDER_TYPE_OPTIONS, |
| | | placeholder: '请选择工单类型', |
| | | }, |
| | | rules: 'selectRequired', |
| | | }, |
| | | { |
| | | fieldName: 'requestDate', |
| | | label: '需求日期', |
| | | component: 'DatePicker', |
| | | componentProps: { |
| | | placeholder: '请选择需求日期', |
| | | valueFormat: 'YYYY-MM-DD HH:mm:ss', |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'quantity', |
| | | label: '生产数量', |
| | | component: 'InputNumber', |
| | | componentProps: { |
| | | class: '!w-full', |
| | | min: 0, |
| | | precision: 2, |
| | | placeholder: '请输入生产数量', |
| | | }, |
| | | rules: 'required', |
| | | }, |
| | | { |
| | | fieldName: 'remark', |
| | | label: '备注', |
| | | component: 'Textarea', |
| | | componentProps: { |
| | | placeholder: '请输入备注', |
| | | rows: 3, |
| | | }, |
| | | }, |
| | | ], |
| | | showDefaultActions: false, |
| | | }); |
| | | |
| | | const [Modal, modalApi] = useVbenModal({ |
| | | async onConfirm() { |
| | | const { valid } = await formApi.validate(); |
| | | if (!valid) { |
| | | return; |
| | | } |
| | | modalApi.lock(); |
| | | try { |
| | | const values = await formApi.getValues<{ |
| | | forecastId: number; |
| | | workOrderName?: string; |
| | | workOrderType: number; |
| | | requestDate?: string; |
| | | quantity: number; |
| | | remark?: string; |
| | | }>(); |
| | | await generateForecastWorkOrder({ |
| | | forecastId: Number(values.forecastId), |
| | | workOrderName: values.workOrderName, |
| | | workOrderType: Number(values.workOrderType), |
| | | requestDate: values.requestDate, |
| | | quantity: Number(values.quantity ?? 1), |
| | | remark: values.remark, |
| | | }); |
| | | await modalApi.close(); |
| | | message.success('工单生成成功'); |
| | | } finally { |
| | | modalApi.unlock(); |
| | | } |
| | | }, |
| | | async onOpenChange(isOpen: boolean) { |
| | | if (!isOpen) { |
| | | return; |
| | | } |
| | | const data = modalApi.getData<{ item: any }>(); |
| | | const item = data?.item; |
| | | await formApi.resetForm(); |
| | | await formApi.setValues({ |
| | | forecastId: item?.id, |
| | | workOrderType: 4, |
| | | requestDate: item?.pointTime ?? dayjs().format('YYYY-MM-DD HH:mm:ss'), |
| | | quantity: item?.forecastValue ?? 1, |
| | | remark: `由负荷预测(${item?.forecastName ?? forecastCode.value})自动生成`, |
| | | }); |
| | | }, |
| | | }); |
| | | |
| | | function handleGenerate(item: any) { |
| | | modalApi.setData({ item }).open(); |
| | | } |
| | | </script> |
| | | |
| | | <template> |
| | | <Page :auto-content-height="true"> |
| | | <Modal title="负荷预测生成生产工单" class="w-1/2"> |
| | | <Form class="mx-3" /> |
| | | </Modal> |
| | | <div class="p-4"> |
| | | <div class="mb-4 flex items-center gap-4"> |
| | | <h2 class="text-lg font-bold">负荷预测</h2> |
| | |
| | | 暂无预测数据,请先配置 KPI 指标和预警规则后查看 |
| | | </div> |
| | | <div v-else class="grid grid-cols-1 gap-4 lg:grid-cols-2"> |
| | | <div v-for="item in forecastData" :key="item.id" class="rounded-lg border p-4"> |
| | | <div |
| | | v-for="item in forecastData" |
| | | :key="item.id" |
| | | class="rounded-lg border p-4" |
| | | > |
| | | <div class="mb-2 flex items-center justify-between"> |
| | | <span class="font-medium">{{ item.forecastName }}</span> |
| | | <span class="text-xs text-gray-400">{{ item.pointTime }}</span> |
| | |
| | | <div v-if="item.dimension" class="mt-1 text-xs text-gray-400"> |
| | | {{ item.dimension }}: {{ item.dimensionValue }} |
| | | </div> |
| | | <div class="mt-3"> |
| | | <a-button |
| | | type="primary" |
| | | ghost |
| | | size="small" |
| | | @click="handleGenerate(item)" |
| | | > |
| | | 生成工单 |
| | | </a-button> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </Spin> |
| | | </div> |
| | | </Page> |
| | | </template> |
| | | </template> |