Yi 1 year ago
parent
commit
e658b38421

+ 7 - 0
README.md

@@ -164,3 +164,10 @@ docker run --name soybean -p 80:80 -d soybeanjs/soybean-admin:v0.9.6
 ## License
 
 [MIT © Soybean-2021](./LICENSE)
+
+
+## TODOLIST
+
+- **指标管理更值无法修改**
+- **所有列表页编辑和新增后没有刷新**
+

+ 17 - 0
src/constants/business.ts

@@ -143,3 +143,20 @@ export const EditSelectBoxDataSource: Common.OptionWithKey<number>[] = [
   { label: '录入', value: 1 },
   { label: '自动生成', value: 2 }
 ];
+
+export const EditSelectBoxTriggerOperation: Common.OptionWithKey<number>[] = [
+  { label: '新增', value: 1 },
+  { label: '删除', value: 2 }
+];
+
+export const EditSelectBoxStartTime: Common.OptionWithKey<number>[] = [
+  { label: '等于当天', value: 1 },
+  { label: '大于当天', value: 2 },
+  { label: '大于等于当天', value: 3 }
+];
+
+export const WorkflowIsShowLabels: Record<BackgroundWorkflow.IsShowKey, string> = {
+  0: '无效',
+  1: '是',
+  2: '否'
+};

+ 10 - 0
src/router/modules/background.ts

@@ -32,6 +32,16 @@ const dashboard: AuthRoute.Route = {
         requiresAuth: true,
         icon: 'icon-park-outline:workbench'
       }
+    },
+    {
+      name: 'background_workflow',
+      path: '/background/workflow',
+      component: 'self',
+      meta: {
+        title: '流程设置',
+        requiresAuth: true,
+        icon: 'icon-park-outline:workbench'
+      }
     }
   ],
   meta: {

+ 14 - 0
src/service/api/event.adapter.ts

@@ -41,3 +41,17 @@ export function adapterOfFetchIndicatorsList(
     return indicators;
   });
 }
+
+export function adapterOfFetchWorkflowList(data: ApiBackground.Workflow[] | null): BackgroundWorkflow.Workflow[] {
+  if (!data) return [];
+
+  return data.map(item => {
+    const workflow: BackgroundWorkflow.Workflow = {
+      index: item.id,
+      key: item.id,
+      ...item
+    };
+
+    return workflow;
+  });
+}

+ 29 - 3
src/service/api/event.ts

@@ -2,7 +2,8 @@ import { adapter } from '@/utils';
 import {
   adapterOfFetchEventList,
   adapterOfFetchFieldList,
-  adapterOfFetchIndicatorsList
+  adapterOfFetchIndicatorsList,
+  adapterOfFetchWorkflowList
 } from '@/service/api/event.adapter';
 import { backgroundRequest } from '../request';
 
@@ -57,7 +58,7 @@ export const fetchIndicatorsList = async (page: number, page_size: number, name:
   return adapter(adapterOfFetchIndicatorsList, data);
 };
 
-export const fetchIndicatorsAdd = (params: ApiBackground.Indicators[]) => {
+export const fetchIndicatorsAdd = (params: ApiBackground.Indicators) => {
   return backgroundRequest.post<ApiBoolean.OK | null>('/kpt/indicators/add', params);
 };
 
@@ -69,6 +70,31 @@ export const fetchIndicatorsDelete = (fieldId: number) => {
   return backgroundRequest.post<ApiBoolean.OK | null>('/kpt/indicators/delete', { id: fieldId });
 };
 
-export const basicEvent = (eventName: string) => {
+export const basicEventColumnName = (eventName: string) => {
   return backgroundRequest.get<ApiBackground.BasicCowField[] | null>(`/basic/table/${eventName}`);
 };
+
+export const basicEventList = () => {
+  return backgroundRequest.get<ApiBackground.BasicCowField[] | null>(`/basic/event/list`);
+};
+
+export const fetchWorkflowList = async (page: number, page_size: number, name: string) => {
+  const data = await backgroundRequest.post<ApiBackground.Workflow[] | null>('/kpt/workflow/search', {
+    page,
+    page_size,
+    name
+  });
+  return adapter(adapterOfFetchWorkflowList, data);
+};
+
+export const fetchWorkflowDelete = (workflowId: number) => {
+  return backgroundRequest.post<ApiBoolean.OK | null>('/kpt/workflow/delete', { id: workflowId });
+};
+
+export const fetchWorkflowAdd = (params: ApiBackground.Workflow[]) => {
+  return backgroundRequest.post<ApiBoolean.OK | null>('/kpt/workflow/add', params);
+};
+
+export const fetchWorkflowEdit = (param: ApiBackground.Workflow) => {
+  return backgroundRequest.post<ApiBoolean.OK | null>('/kpt/field/edit', param);
+};

+ 26 - 1
src/typings/basic.d.ts

@@ -25,7 +25,7 @@ declare namespace RowField {
   }
 }
 
-declare namespace EditSelectBox {
+declare namespace EventSelectBox {
   interface Data {
     cowFieldData: ApiBackground.BasicCowField[] | null;
     isRequired: ApiBackground.BasicSelectValue[] | null;
@@ -35,3 +35,28 @@ declare namespace EditSelectBox {
     showLine: ApiBackground.BasicSelectValue[] | null;
   }
 }
+
+declare namespace RowIndicators {
+  interface Data {
+    event_id: number;
+    event_name: string;
+    trigger_operation: number;
+    is_cumulative: number;
+    impact_mode: number;
+    impact_value: string;
+    start_time: number;
+  }
+}
+
+declare namespace IndicatorsSelectBox {
+  interface Data {
+    cowEventData: ApiBackground.BasicCowField[] | null;
+    eventId: number;
+    eventName: string;
+    triggerOperation: ApiBackground.BasicSelectValue[] | null;
+    isCumulative: ApiBackground.BasicSelectValue[] | null;
+    impactMode: ApiBackground.BasicSelectValue[] | null;
+    impactValue: number;
+    startTime: ApiBackground.BasicSelectValue[] | null;
+  }
+}

+ 17 - 0
src/typings/business.d.ts

@@ -111,3 +111,20 @@ declare namespace BackgroundIndicators {
    */
   type IsShowKey = NonNullable<Indicators['is_show']>;
 }
+
+declare namespace BackgroundWorkflow {
+  interface Workflow extends ApiBackground.Workflow {
+    /** 序号 */
+    index: number;
+    /** 表格的key(id) */
+    key: number;
+  }
+
+  /**
+   * 是否启动
+   * 0 无效
+   * 1:是
+   * 2: 否
+   */
+  type IsShowKey = NonNullable<Workflow['is_show']>;
+}

+ 1 - 0
src/typings/indicators.d.ts

@@ -26,6 +26,7 @@ declare namespace ApiBackground {
      * 字段描述
      */
     description: string | null;
+    event_indicators: RowIndicators.Data[] | null;
   }
 }
 

+ 2 - 0
src/typings/page-route.d.ts

@@ -30,6 +30,7 @@ declare namespace PageRoute {
     | 'background_event'
     | 'background_field'
     | 'background_indicators'
+    | 'background_workflow'
     | 'component'
     | 'component_button'
     | 'component_card'
@@ -93,6 +94,7 @@ declare namespace PageRoute {
     | 'background_event'
     | 'background_field'
     | 'background_indicators'
+    | 'background_workflow'
     | 'component_button'
     | 'component_card'
     | 'component_table'

+ 11 - 0
src/typings/workflow.d.ts

@@ -0,0 +1,11 @@
+declare namespace ApiBackground {
+  interface Workflow {
+    /** id */
+    id: number;
+    /** 字段名 */
+    name: string | null;
+    remarks: string | null;
+    is_show: number | null;
+    end_condition: string | null;
+  }
+}

+ 7 - 2
src/views/background/event/components/select-box.vue

@@ -9,10 +9,15 @@
 </template>
 
 <script lang="ts">
-import { defineComponent, computed, onMounted, ref } from 'vue';
+import { defineComponent, computed, onMounted } from 'vue';
 export default defineComponent({
   props: {
     fieldOptions: {
+      type: Array,
+      default: null,
+      required: true
+    },
+    value: {
       type: null,
       default: null,
       required: true
@@ -28,7 +33,7 @@ export default defineComponent({
     // const emit = defineEmits(["updateTableValue"]);
     return {
       getOptions,
-      selectValue: ref(null),
+      selectValue: props.value,
       handleUpdateValue(value: string) {
         emit('updateTableValue', value);
       }

+ 19 - 15
src/views/background/event/components/table-action-modal.vue

@@ -32,7 +32,7 @@ import type { FormInst, FormItemRule, DataTableColumns, PaginationProps } from '
 import { NButton, NTag, NInput } from 'naive-ui';
 import { EditSelectBoxDataSource, EditSelectBoxIsShow, EditSelectBoxShowLine, EventIsShowOptions } from '@/constants';
 import { createRequiredFormRule } from '@/utils';
-import { basicEvent, fetchEventAdd, fetchEventEdit } from '@/service/api/event';
+import { basicEventColumnName, fetchEventAdd, fetchEventEdit } from '@/service/api/event';
 import SelectBox from './select-box.vue';
 export interface Props {
   /** 弹窗可见性 */
@@ -59,7 +59,7 @@ const props = withDefaults(defineProps<Props>(), {
 interface Emits {
   (e: 'update:visible', visible: boolean): void;
 }
-
+/*  */
 const emit = defineEmits<Emits>();
 
 const modalVisible = computed({
@@ -70,15 +70,10 @@ const modalVisible = computed({
     emit('update:visible', visible);
   }
 });
-const closeModal = () => {
-  // eslint-disable-next-line @typescript-eslint/no-use-before-define
-  tableData.value = [];
-  modalVisible.value = false;
-};
 
 const titles: Record<ModalType, string> = {
-  add: '添加字段',
-  edit: '编辑字段'
+  add: '添加事件',
+  edit: '编辑事件'
 };
 
 const title = computed(() => {
@@ -100,7 +95,7 @@ const rules: Record<keyof FormModel, FormItemRule | FormItemRule[]> = {
   id: createRequiredFormRule('请输入事件id')
 };
 
-const selectBoxData: EditSelectBox.Data = {
+const selectBoxData: EventSelectBox.Data = {
   cowFieldData: [],
   isDetails: EditSelectBoxIsShow,
   isList: EditSelectBoxIsShow,
@@ -114,7 +109,7 @@ function setCowFieldData(data: ApiBackground.BasicCowField[] | null) {
 }
 
 function getCowFieldData() {
-  const data = basicEvent('animals_cow');
+  const data = basicEventColumnName('animals_cow');
   data.then(res => {
     setCowFieldData(res.data);
   });
@@ -145,10 +140,8 @@ function handleUpdateFormModelByModalType() {
       if (props.editData) {
         handleUpdateFormModel(props.editData);
         if (props.editData.event_field) {
-          props.editData.event_field.forEach((value, index) => {
-            console.log(value);
-            console.log(index);
-          });
+          // eslint-disable-next-line @typescript-eslint/no-use-before-define
+          tableData.value = props.editData.event_field;
         }
       }
     }
@@ -214,6 +207,7 @@ const createColumns = (): DataTableColumns<RowField.Data> => [
     render(row, index) {
       return h(SelectBox, {
         fieldOptions: selectBoxData.cowFieldData,
+        value: tableData.value[index].column_name,
         onUpdateTableValue(value: string) {
           tableData.value[index].column_name = value;
         }
@@ -228,6 +222,7 @@ const createColumns = (): DataTableColumns<RowField.Data> => [
     render(row, index) {
       return h(SelectBox, {
         fieldOptions: selectBoxData.isRequired,
+        value: tableData.value[index].is_required,
         onUpdateTableValue(value: number) {
           tableData.value[index].is_required = value;
         }
@@ -242,6 +237,7 @@ const createColumns = (): DataTableColumns<RowField.Data> => [
     render(row, index) {
       return h(SelectBox, {
         fieldOptions: selectBoxData.dataSource,
+        value: tableData.value[index].data_source,
         onUpdateTableValue(value: number) {
           tableData.value[index].data_source = value;
         }
@@ -256,6 +252,7 @@ const createColumns = (): DataTableColumns<RowField.Data> => [
     render(row, index) {
       return h(SelectBox, {
         fieldOptions: selectBoxData.isList,
+        value: tableData.value[index].is_list,
         onUpdateTableValue(value: number) {
           tableData.value[index].is_list = value;
         }
@@ -270,6 +267,7 @@ const createColumns = (): DataTableColumns<RowField.Data> => [
     render(row, index) {
       return h(SelectBox, {
         fieldOptions: selectBoxData.isDetails,
+        value: tableData.value[index].is_details,
         onUpdateTableValue(value: number) {
           tableData.value[index].is_details = value;
         }
@@ -284,6 +282,7 @@ const createColumns = (): DataTableColumns<RowField.Data> => [
     render(row, index) {
       return h(SelectBox, {
         fieldOptions: selectBoxData.showLine,
+        value: tableData.value[index].show_line,
         onUpdateValue(value: number) {
           tableData.value[index].show_line = value;
         }
@@ -322,6 +321,11 @@ function deleteData(indexKey: number) {
   tableData.value.splice(indexKey, 1);
 }
 
+const closeModal = () => {
+  tableData.value = [];
+  modalVisible.value = false;
+};
+
 getCowFieldData();
 
 async function handleSubmit() {

+ 119 - 0
src/views/background/event/components/table-setting-model.vue

@@ -0,0 +1,119 @@
+<template>
+  <n-modal v-model:show="modalVisible" preset="card" :title="title" style="width: 70%">
+    <n-form ref="formRef" label-placement="left" :label-width="80" :model="formModel" :rules="rules">
+      <n-space style="display: flex; flex-direction: column">
+        <n-button type="primary" @click="addEventSetting">添加事件字段</n-button>
+        <n-data-table :columns="columns" :data="tableData" :pagination="pagination" />
+      </n-space>
+    </n-form>
+  </n-modal>
+</template>
+
+<script setup lang="ts">
+import { computed, reactive, ref, watch } from 'vue';
+import type { FormInst } from 'naive-ui';
+export interface Props {
+  /** 弹窗可见性 */
+  settingVisible: boolean;
+  /**
+   * 弹窗类型
+   * add: 新增
+   * edit: 编辑
+   */
+  type?: 'add' | 'edit';
+  /** 编辑的表格行数据 */
+  editData?: BackgroundEvent.Event | null;
+}
+
+export type ModalSettingType = NonNullable<Props['type']>;
+
+defineOptions({ name: 'TableSettingModal' });
+
+interface Emits {
+  (e: 'update:settingVisible', visible: boolean): void;
+}
+
+const emit = defineEmits<Emits>();
+
+const props = withDefaults(defineProps<Props>(), {
+  type: 'add',
+  editData: null
+});
+
+const modalVisible = computed({
+  get() {
+    return props.settingVisible;
+  },
+  set(visible) {
+    emit('update:settingVisible', visible);
+  }
+});
+const titles: Record<ModalSettingType, string> = {
+  add: '添加事件',
+  edit: '编辑事件'
+};
+
+const title = computed(() => {
+  return titles[props.type];
+});
+
+const settingVisible = computed({
+  get() {
+    return props.settingVisible;
+  },
+  set(visible) {
+    emit('update:settingVisible', visible);
+  }
+});
+
+const closeModal = () => {
+  settingVisible.value = false;
+};
+
+const formRef = ref<HTMLElement & FormInst>();
+type FormModel = Pick<BackgroundEvent.Event, 'name'>;
+
+const formModel = reactive<FormModel>(createDefaultFormModel());
+function handleUpdateFormModel(model: Partial<FormModel>) {
+  Object.assign(formModel, model);
+}
+
+function createDefaultFormModel(): FormModel {
+  return {
+    name: ''
+  };
+}
+
+function handleUpdateFormModelByModalType() {
+  const handlers: Record<ModalSettingType, () => void> = {
+    add: () => {
+      const defaultFormModel = createDefaultFormModel();
+      handleUpdateFormModel(defaultFormModel);
+    },
+    edit: () => {
+      if (props.editData) {
+        handleUpdateFormModel(props.editData);
+      }
+    }
+  };
+
+  handlers[props.type]();
+}
+
+// 添加条件
+async function addEventSetting() {
+  await formRef.value?.validate();
+  window.$message?.success('添加成功!');
+  closeModal();
+}
+
+watch(
+  () => props.settingVisible,
+  newValue => {
+    if (newValue) {
+      handleUpdateFormModelByModalType();
+    }
+  }
+);
+</script>
+<style scoped></style>

+ 17 - 4
src/views/background/event/index.vue

@@ -30,6 +30,7 @@
         :type="modalConditionType"
         :edit-data="editData"
       />
+      <table-setting-modal v-model:settingVisible="settingVisible" :type="ModalSettingType" :edit-data="editData" />
     </n-card>
   </div>
 </template>
@@ -42,14 +43,16 @@ import type { DataTableColumns, PaginationProps } from 'naive-ui';
 import { EventIsShowLabels } from '@/constants';
 import { useBoolean, useLoading } from '@/hooks';
 import { fetchEventDelete, fetchEventList } from '@/service/api/event';
-import TableActionModal from './components/table-action-modal.vue';
 import type { ModalType } from './components/table-action-modal.vue';
 import type { ModalConditionType } from './components/table-condition-modal.vue';
+import TableSettingModal, { ModalSettingType } from './components/table-setting-model.vue';
+import TableActionModal from './components/table-action-modal.vue';
 import TableConditionModal from './components/table-condition-modal.vue';
 
 const { loading, startLoading, endLoading } = useLoading(false);
 const { bool: visible, setTrue: openModal } = useBoolean();
 const { bool: conditionVisible, setTrue: openEventModal } = useBoolean();
+const { bool: settingVisible, setTrue: openSettingModal } = useBoolean();
 
 const eventName = ref('');
 const tableData = ref<BackgroundEvent.Event[]>([]);
@@ -152,15 +155,20 @@ const columns: Ref<DataTableColumns<BackgroundEvent.Event>> = ref([
 
 const modalType = ref<ModalType>('add');
 const modalConditionType = ref<ModalConditionType>('add');
+const modalSettingType = ref<ModalSettingType>('add');
 
 function setModalType(type: ModalType) {
   modalType.value = type;
 }
 
-function setModalConditionType(type: ModalType) {
+function setModalConditionType(type: ModalConditionType) {
   modalConditionType.value = type;
 }
 
+function setModalSettingType(type: ModalSettingType) {
+  modalSettingType.value = type;
+}
+
 const editData = ref<BackgroundEvent.Event | null>(null);
 
 function setEditData(data: BackgroundEvent.Event | null) {
@@ -185,7 +193,12 @@ function handleEditTable(rowId: number) {
  * 影响设置
  */
 function handleSetting(rowId: number) {
-  window.$message?.warning(`${rowId}`);
+  const findItem = tableData.value.find(item => item.id === rowId);
+  if (findItem) {
+    setEditData(findItem);
+  }
+  setModalSettingType('edit');
+  openSettingModal();
 }
 
 /*
@@ -207,7 +220,7 @@ function handleDeleteTable(rowId: number) {
       window.$message?.success('删除成功!');
     }
   });
-  getTableData();
+  init();
 }
 
 const pagination: PaginationProps = reactive({

+ 214 - 16
src/views/background/indicators/components/table-action-modal.vue

@@ -1,5 +1,5 @@
 <template>
-  <n-modal v-model:show="modalVisible" preset="card" :title="title" class="w-700px">
+  <n-modal v-model:show="modalVisible" preset="card" :title="title" style="width: 70%">
     <n-form ref="formRef" label-placement="left" :label-width="80" :model="formModel" :rules="rules">
       <n-grid :cols="48" :x-gap="18">
         <n-form-item-grid-item :span="25" label="指标名称" path="name">
@@ -15,6 +15,10 @@
           <n-input v-model:value="formModel.description" type="textarea" placeholder="请输入指标描述" />
         </n-form-item-grid-item>
       </n-grid>
+      <n-space style="display: flex; flex-direction: column">
+        <n-button type="primary" @click="addEventIndicators">添加指标事件</n-button>
+        <n-data-table :columns="columns" :data="tableData" />
+      </n-space>
       <n-space class="w-full pt-16px" :size="24" justify="end">
         <n-button class="w-72px" @click="closeModal">取消</n-button>
         <n-button class="w-72px" type="primary" @click="handleSubmit">确定</n-button>
@@ -24,11 +28,19 @@
 </template>
 
 <script setup lang="ts">
-import { ref, computed, reactive, watch } from 'vue';
-import type { FormInst, FormItemRule } from 'naive-ui';
-import { IndicatorsOptions } from '@/constants';
+import { ref, computed, reactive, watch, h } from 'vue';
+import type { FormInst, FormItemRule, DataTableColumns } from 'naive-ui';
+import { NButton, NTag, NInput, NInputNumber } from 'naive-ui';
+import {
+  EditSelectBoxDataSource,
+  EditSelectBoxIsShow,
+  EditSelectBoxTriggerOperation,
+  IndicatorsOptions,
+  EditSelectBoxStartTime
+} from '@/constants';
 import { createRequiredFormRule } from '@/utils';
-import { fetchIndicatorsAdd, fetchIndicatorsEdit } from '@/service/api/event';
+import { basicEventList, fetchIndicatorsAdd, fetchIndicatorsEdit } from '@/service/api/event';
+import SelectBox from '@/views/background/event/components/select-box.vue';
 
 export interface Props {
   /** 弹窗可见性 */
@@ -66,12 +78,10 @@ const modalVisible = computed({
     emit('update:visible', visible);
   }
 });
-const closeModal = () => {
-  modalVisible.value = false;
-};
+
 const titles: Record<ModalType, string> = {
-  add: '添加字段',
-  edit: '编辑字段'
+  add: '添加指标',
+  edit: '编辑指标'
 };
 
 const title = computed(() => {
@@ -82,7 +92,7 @@ const formRef = ref<HTMLElement & FormInst>();
 
 type FormModel = Pick<
   ApiBackground.Indicators,
-  'id' | 'name' | 'category_id' | 'particle_size' | 'is_show' | 'description'
+  'id' | 'name' | 'category_id' | 'particle_size' | 'is_show' | 'description' | 'event_indicators'
 >;
 
 const formModel = reactive<FormModel>(createDefaultFormModel());
@@ -93,9 +103,187 @@ const rules: Record<keyof FormModel, FormItemRule | FormItemRule[]> = {
   category_id: createRequiredFormRule('请选择分类id'),
   description: createRequiredFormRule('请输入字段描述'),
   is_show: createRequiredFormRule(),
-  id: createRequiredFormRule()
+  id: createRequiredFormRule(),
+  event_indicators: createRequiredFormRule()
 };
 
+const createData = (): RowIndicators.Data[] => [
+  {
+    event_id: 0,
+    event_name: '',
+    trigger_operation: 1,
+    is_cumulative: 1,
+    impact_mode: 1,
+    impact_value: '0',
+    start_time: 1
+  }
+];
+const tableData = ref(createData());
+
+const selectBoxData: IndicatorsSelectBox.Data = {
+  cowEventData: [],
+  triggerOperation: EditSelectBoxTriggerOperation,
+  isCumulative: EditSelectBoxIsShow,
+  impactMode: EditSelectBoxDataSource,
+  impactValue: 0,
+  eventId: 0,
+  eventName: '',
+  startTime: EditSelectBoxStartTime
+};
+
+function setIndicatorsEventData(data: ApiBackground.BasicCowField[] | null) {
+  selectBoxData.cowEventData = data;
+}
+
+function getIndicatorsEventData() {
+  const data = basicEventList();
+  data.then(res => {
+    setIndicatorsEventData(res.data);
+  });
+}
+
+const createColumns = (): DataTableColumns<RowIndicators.Data> => [
+  {
+    title: '序号',
+    key: 'orderNum',
+    // eslint-disable-next-line @typescript-eslint/no-unused-vars
+    render(row, index) {
+      return h(
+        NTag,
+        {
+          style: {
+            marginRight: '6px',
+            background: 'none',
+            color: 'rgb(31, 34, 37)'
+          },
+          type: 'info',
+          bordered: false
+        },
+        {
+          default: () => index + 1
+        }
+      );
+    }
+  },
+  {
+    title: '事件名称',
+    key: 'EventName',
+    maxWidth: 300,
+    // eslint-disable-next-line @typescript-eslint/no-unused-vars
+    render(row, index) {
+      return h(SelectBox, {
+        fieldOptions: selectBoxData.cowEventData,
+        value: tableData.value[index].event_name,
+        onUpdateTableValue(value: string) {
+          tableData.value[index].event_name = value;
+        }
+      });
+    }
+  },
+  {
+    title: '触发操作',
+    key: 'triggerOperation',
+    maxWidth: 100,
+    // eslint-disable-next-line @typescript-eslint/no-unused-vars
+    render(row, index) {
+      return h(SelectBox, {
+        fieldOptions: selectBoxData.triggerOperation,
+        value: tableData.value[index].trigger_operation,
+        onUpdateTableValue(value: number) {
+          tableData.value[index].trigger_operation = value;
+        }
+      });
+    }
+  },
+  {
+    title: '累加上期',
+    key: 'cumulative',
+    maxWidth: 200,
+    // eslint-disable-next-line @typescript-eslint/no-unused-vars
+    render(row, index) {
+      return h(SelectBox, {
+        fieldOptions: selectBoxData.isCumulative,
+        value: tableData.value[index].is_cumulative,
+        onUpdateTableValue(value: number) {
+          tableData.value[index].is_cumulative = value;
+        }
+      });
+    }
+  },
+  {
+    title: '变更方法',
+    key: 'impactMode',
+    maxWidth: 200,
+    // eslint-disable-next-line @typescript-eslint/no-unused-vars
+    render(row, index) {
+      return h(SelectBox, {
+        fieldOptions: selectBoxData.impactMode,
+        value: tableData.value[index].impact_mode,
+        onUpdateTableValue(value: number) {
+          tableData.value[index].impact_mode = value;
+        }
+      });
+    }
+  },
+  {
+    title: '变更值',
+    key: 'impactValue',
+    maxWidth: 100,
+    // eslint-disable-next-line @typescript-eslint/no-unused-vars
+    render(row, index) {
+      return h(NInput, {
+        value: tableData.value[index].impact_value,
+        onUpdateTableValue(value: string) {
+          tableData.value[index].impact_value = value;
+        }
+      });
+    }
+  },
+  {
+    title: '开始时间',
+    key: 'startTime',
+    maxWidth: 200,
+    // eslint-disable-next-line @typescript-eslint/no-unused-vars
+    render(row, index) {
+      return h(SelectBox, {
+        fieldOptions: selectBoxData.startTime,
+        value: tableData.value[index].start_time,
+        onUpdateValue(value: number) {
+          tableData.value[index].start_time = value;
+        }
+      });
+    }
+  },
+  {
+    title: '操作',
+    key: 'actions',
+    // eslint-disable-next-line @typescript-eslint/no-unused-vars
+    render(row, index) {
+      return [
+        h(
+          NButton,
+          {
+            // 可在里面写按钮样式
+            text: true,
+            style: { marginRight: '10px', color: 'red' },
+            onClick: () => deleteData(index) // 点击按钮后的回调
+          },
+          { default: () => '删除' } // 按钮显示名称
+        )
+      ];
+    }
+  }
+];
+
+const columns = ref(createColumns());
+
+function addEventIndicators() {
+  tableData.value.push(createData()[0]);
+}
+function deleteData(indexKey: number) {
+  tableData.value.splice(indexKey, 1);
+}
+
 function createDefaultFormModel(): FormModel {
   return {
     id: 0,
@@ -103,7 +291,8 @@ function createDefaultFormModel(): FormModel {
     particle_size: null,
     category_id: null,
     is_show: null,
-    description: ''
+    description: '',
+    event_indicators: null
   };
 }
 
@@ -120,6 +309,9 @@ function handleUpdateFormModelByModalType() {
     edit: () => {
       if (props.editData) {
         handleUpdateFormModel(props.editData);
+        if (props.editData.event_indicators) {
+          tableData.value = props.editData.event_indicators;
+        }
       }
     }
   };
@@ -127,12 +319,18 @@ function handleUpdateFormModelByModalType() {
   handlers[props.type]();
 }
 
+const closeModal = () => {
+  tableData.value = [];
+  modalVisible.value = false;
+};
+
+getIndicatorsEventData();
+
 async function handleSubmit() {
   formRef.value?.validate();
-  const params: Array<ApiBackground.Indicators> = [formModel];
-
+  formModel.event_indicators = tableData.value;
   if (props.type === 'add') {
-    const data = fetchIndicatorsAdd(params);
+    const data = fetchIndicatorsAdd(formModel);
     data.then(res => {
       if (res.data) {
         window.$message?.success(`${titles[props.type]}成功!`);

+ 2 - 0
src/views/background/indicators/index.vue

@@ -129,6 +129,7 @@ function setEditData(data: BackgroundIndicators.Indicators | null) {
 function handleAddTable() {
   openModal();
   setModalType('add');
+  init();
 }
 
 function handleEditTable(rowId: number) {
@@ -138,6 +139,7 @@ function handleEditTable(rowId: number) {
   }
   setModalType('edit');
   openModal();
+  init();
 }
 
 function handleDeleteTable(rowId: number) {

+ 155 - 0
src/views/background/workflow/components/table-action-modal.vue

@@ -0,0 +1,155 @@
+<template>
+  <n-modal v-model:show="modalVisible" preset="card" :title="title" class="w-700px">
+    <n-form ref="formRef" label-placement="left" :label-width="80" :model="formModel" :rules="rules">
+      <n-grid :cols="48" :x-gap="18">
+        <n-form-item-grid-item :span="25" label="流程名称" path="name">
+          <n-input v-model:value="formModel.name" />
+        </n-form-item-grid-item>
+        <n-form-item-grid-item :span="25" label="是否显示" path="is_show">
+          <n-select v-model:value="formModel.is_show" :options="EventIsShowOptions" />
+        </n-form-item-grid-item>
+        <n-form-item-grid-item :span="25" label="流程描述" path="remarks">
+          <n-input v-model:value="formModel.remarks" type="textarea" placeholder="请输入流程描述" />
+        </n-form-item-grid-item>
+      </n-grid>
+      <super-flow></super-flow>
+      <n-space class="w-full pt-16px" :size="24" justify="end">
+        <n-button class="w-72px" @click="closeModal">取消</n-button>
+        <n-button class="w-72px" type="primary" @click="handleSubmit">确定</n-button>
+      </n-space>
+    </n-form>
+  </n-modal>
+</template>
+
+<script setup lang="ts">
+import type { FormInst, FormItemRule } from 'naive-ui';
+import { EventIsShowOptions } from '@/constants';
+import { createRequiredFormRule } from '@/utils';
+import { fetchWorkflowAdd, fetchWorkflowEdit } from '@/service/api/event';
+export interface Props {
+  /** 弹窗可见性 */
+  visible: boolean;
+  /**
+   * 弹窗类型
+   * add: 新增
+   * edit: 编辑
+   */
+  type?: 'add' | 'edit';
+  /** 编辑的表格行数据 */
+  editData?: BackgroundWorkflow.Workflow | null;
+}
+
+export type ModalType = NonNullable<Props['type']>;
+
+defineOptions({ name: 'TableActionModal' });
+
+const props = withDefaults(defineProps<Props>(), {
+  type: 'add',
+  editData: null
+});
+
+interface Emits {
+  (e: 'update:visible', visible: boolean): void;
+}
+
+const emit = defineEmits<Emits>();
+
+const modalVisible = computed({
+  get() {
+    return props.visible;
+  },
+  set(visible) {
+    emit('update:visible', visible);
+  }
+});
+const closeModal = () => {
+  modalVisible.value = false;
+};
+const titles: Record<ModalType, string> = {
+  add: '添加流程',
+  edit: '编辑流程'
+};
+
+const title = computed(() => {
+  return titles[props.type];
+});
+
+const formRef = ref<HTMLElement & FormInst>();
+
+type FormModel = Pick<ApiBackground.Workflow, 'id' | 'name' | 'remarks' | 'is_show' | 'end_condition'>;
+
+const formModel = reactive<FormModel>(createDefaultFormModel());
+
+const rules: Record<keyof FormModel, FormItemRule | FormItemRule[]> = {
+  name: createRequiredFormRule('请输入流程名称'),
+  is_show: createRequiredFormRule(),
+  end_condition: createRequiredFormRule('请选择组件类型'),
+  remarks: createRequiredFormRule('请输入流程描述'),
+  id: createRequiredFormRule()
+};
+
+function createDefaultFormModel(): FormModel {
+  return {
+    id: 0,
+    name: '',
+    remarks: '',
+    end_condition: null,
+    is_show: 1
+  };
+}
+
+function handleUpdateFormModel(model: Partial<FormModel>) {
+  Object.assign(formModel, model);
+}
+
+function handleUpdateFormModelByModalType() {
+  const handlers: Record<ModalType, () => void> = {
+    add: () => {
+      const defaultFormModel = createDefaultFormModel();
+      handleUpdateFormModel(defaultFormModel);
+    },
+    edit: () => {
+      if (props.editData) {
+        handleUpdateFormModel(props.editData);
+      }
+    }
+  };
+
+  handlers[props.type]();
+}
+
+async function handleSubmit() {
+  formRef.value?.validate();
+  const params: Array<ApiBackground.Workflow> = [formModel];
+
+  if (props.type === 'add') {
+    const data = fetchWorkflowAdd(params);
+    data.then(res => {
+      if (res.data) {
+        window.$message?.success(`${titles[props.type]}成功!`);
+      }
+    });
+  }
+
+  if (props.type === 'edit') {
+    const data = fetchWorkflowEdit(formModel);
+    data.then(res => {
+      if (res.data) {
+        window.$message?.success(`${titles[props.type]}成功!`);
+      }
+    });
+  }
+  closeModal();
+}
+
+watch(
+  () => props.visible,
+  newValue => {
+    if (newValue) {
+      handleUpdateFormModelByModalType();
+    }
+  }
+);
+</script>
+
+<style scoped></style>

+ 192 - 0
src/views/background/workflow/index.vue

@@ -0,0 +1,192 @@
+<template>
+  <div class="h-full overflow-hidden">
+    <n-card title="流程管理" :bordered="false" class="rounded-16px shadow-sm">
+      <n-space class="pb-12px" justify="space-between">
+        <n-space>
+          <n-button type="primary" @click="handleAddTable">
+            <icon-ic-round-plus class="mr-4px text-20px" />
+            新增
+          </n-button>
+          <n-button type="success">
+            <icon-uil:export class="mr-4px text-20px" />
+            导出Excel
+          </n-button>
+        </n-space>
+        <n-space align="center" :size="18">
+          <n-input-group>
+            <n-input v-model:value="workflowName" />
+            <n-button type="primary" @click="handleSearch">搜索</n-button>
+          </n-input-group>
+          <n-button size="small" type="primary" @click="getTableData">
+            <icon-mdi-refresh class="mr-4px text-16px" :class="{ 'animate-spin': loading }" />
+            刷新表格
+          </n-button>
+        </n-space>
+      </n-space>
+      <n-data-table :columns="columns" :data="tableData" :loading="loading" :pagination="pagination" />
+      <table-action-modal v-model:visible="visible" :type="modalType" :edit-data="editData" />
+    </n-card>
+  </div>
+</template>
+
+<script setup lang="tsx">
+import { reactive, ref } from 'vue';
+import type { Ref } from 'vue';
+import { NButton, NPopconfirm, NSpace, NTag } from 'naive-ui';
+import type { DataTableColumns, PaginationProps } from 'naive-ui';
+import { WorkflowIsShowLabels } from '@/constants';
+import { useBoolean, useLoading } from '@/hooks';
+import { fetchWorkflowDelete, fetchWorkflowList } from '@/service/api/event';
+import TableActionModal from '../workflow/components/table-action-modal.vue';
+import type { ModalType } from '../workflow/components/table-action-modal.vue';
+
+const { loading, startLoading, endLoading } = useLoading(false);
+const { bool: visible, setTrue: openModal } = useBoolean();
+const workflowName = ref('');
+const tableData = ref<BackgroundWorkflow.Workflow[]>([]);
+function setTableData(data: BackgroundWorkflow.Workflow[]) {
+  tableData.value = data;
+}
+
+async function getTableData() {
+  startLoading();
+  const { data } = await fetchWorkflowList(1, 100, workflowName.value);
+  if (data) {
+    setTimeout(() => {
+      setTableData(data);
+      endLoading();
+    }, 1000);
+  }
+}
+
+const columns: Ref<DataTableColumns<BackgroundWorkflow.Workflow>> = ref([
+  {
+    type: 'selection',
+    align: 'center'
+  },
+  {
+    key: 'index',
+    title: '序号',
+    align: 'center'
+  },
+  {
+    key: 'name',
+    title: '名称',
+    align: 'center'
+  },
+  {
+    key: 'is_show',
+    title: '是否展示',
+    align: 'center',
+    render: row => {
+      if (row.is_show) {
+        const tagTypes: Record<BackgroundWorkflow.IsShowKey, NaiveUI.ThemeColor> = {
+          '0': 'error',
+          '1': 'success',
+          '2': 'warning'
+        };
+
+        return <NTag type={tagTypes[row.is_show]}>{WorkflowIsShowLabels[row.is_show]}</NTag>;
+      }
+
+      return <span></span>;
+    }
+  },
+  {
+    key: 'remarks',
+    title: '描述',
+    align: 'center'
+  },
+  {
+    key: 'actions',
+    title: '操作',
+    align: 'center',
+    render: row => {
+      return (
+        <NSpace justify={'center'}>
+          <NButton type="info" size={'small'} onClick={() => handleEditTable(row.id)}>
+            编辑
+          </NButton>
+          <NPopconfirm onPositiveClick={() => handleDeleteTable(row.id)}>
+            {{
+              default: () => '确认删除',
+              trigger: () => (
+                <NButton type="error" size={'small'}>
+                  删除
+                </NButton>
+              )
+            }}
+          </NPopconfirm>
+        </NSpace>
+      );
+    }
+  }
+]) as Ref<DataTableColumns<BackgroundWorkflow.Workflow>>;
+
+const modalType = ref<ModalType>('add');
+
+function setModalType(type: ModalType) {
+  modalType.value = type;
+}
+
+const editData = ref<BackgroundWorkflow.Workflow | null>(null);
+
+function setEditData(data: BackgroundWorkflow.Workflow | null) {
+  editData.value = data;
+}
+
+function handleAddTable() {
+  openModal();
+  setModalType('add');
+}
+
+function handleEditTable(rowId: number) {
+  const findItem = tableData.value.find(item => item.id === rowId);
+  if (findItem) {
+    setEditData(findItem);
+  }
+  setModalType('edit');
+  openModal();
+}
+
+function handleDeleteTable(rowId: number) {
+  const data = fetchWorkflowDelete(rowId);
+  data.then(res => {
+    if (res.data) {
+      window.$message?.success('删除成功!');
+    }
+  });
+  init();
+}
+
+const pagination: PaginationProps = reactive({
+  page: 1,
+  pageSize: 10,
+  showSizePicker: true,
+  pageSizes: [10, 15, 20, 25, 30],
+  onChange: (page: number) => {
+    pagination.page = page;
+  },
+  onUpdatePageSize: (pageSize: number) => {
+    pagination.pageSize = pageSize;
+    pagination.page = 1;
+  }
+});
+
+function handleSearch() {
+  if (!workflowName.value) {
+    window.$message?.warning('请输入流程名称');
+  } else {
+    startLoading();
+  }
+}
+
+function init() {
+  getTableData();
+}
+
+// 初始化
+init();
+</script>
+
+<style scoped></style>

+ 1 - 0
src/views/index.ts

@@ -16,6 +16,7 @@ export const views: Record<
   background_event: () => import('./background/event/index.vue'),
   background_field: () => import('./background/field/index.vue'),
   background_indicators: () => import('./background/indicators/index.vue'),
+  background_workflow: () => import('./background/workflow/index.vue'),
   component_button: () => import('./component/button/index.vue'),
   component_card: () => import('./component/card/index.vue'),
   component_table: () => import('./component/table/index.vue'),