From c627685b89bc8aedf71e8d02411bc66d8f5bb6e3 Mon Sep 17 00:00:00 2001
From: Jay <csj123456>
Date: 星期二, 24 九月 2024 08:42:53 +0800
Subject: [PATCH] 指标定义

---
 src/views/data/ind/item/selectItemType.vue    |   96 ++++++
 src/views/data/ind/item/DerIndDefineForm.vue  |  329 +++++++++++++++++++++
 src/views/data/ind/item/index.vue             |  195 +++++++++++++
 src/views/data/ind/item/AtomIndDefineForm.vue |  263 +++++++++++++++++
 4 files changed, 883 insertions(+), 0 deletions(-)

diff --git a/src/views/data/ind/item/AtomIndDefineForm.vue b/src/views/data/ind/item/AtomIndDefineForm.vue
new file mode 100644
index 0000000..f9eaa74
--- /dev/null
+++ b/src/views/data/ind/item/AtomIndDefineForm.vue
@@ -0,0 +1,263 @@
+<template>
+  <Dialog v-model="dialogVisible" :title="dialogTitle" width="55%">
+    <el-form
+      ref="formRef"
+      v-loading="formLoading"
+      :model="formData"
+      :rules="formRules" label-width="100px">
+      <el-row>
+        <el-col :span="12">
+          <el-form-item label="指标编码" prop="itemNo">
+            <el-input v-model="formData.itemNo" disabled/>
+          </el-form-item>
+        </el-col>
+        <el-col :span="12">
+          <el-form-item label="指标名称" prop="itemName">
+            <el-input v-model="formData.itemName" placeholder="请输入指标名称"/>
+          </el-form-item>
+        </el-col>
+      </el-row>
+      <el-row>
+        <el-col :span="12">
+          <el-form-item label="指标分类" prop="itemCategory">
+            <el-select v-model="formData.itemCategory" clearable placeholder="请选择指标分类">
+              <el-option
+                v-for="item in dataCategoryList"
+                :key="item.id"
+                :label="item.label"
+                :value="item.id + ''"
+              />
+            </el-select>
+          </el-form-item>
+        </el-col>
+        <el-col :span="12">
+          <el-form-item label="时间粒度" prop="timeGranularity">
+            <el-select v-model="formData.timeGranularity" placeholder="请选择">
+              <el-option
+                v-for="dict in getStrDictOptions(DICT_TYPE.TIME_GRANULARITY)"
+                :key="dict.value"
+                :label="dict.label"
+                :value="dict.value"
+              />
+            </el-select>
+          </el-form-item>
+        </el-col>
+      </el-row>
+      <el-row>
+        <el-col :span="8">
+          <el-form-item label="指标精度" prop="precision">
+            <el-input v-model="formData.precision"/>
+          </el-form-item>
+        </el-col>
+        <el-col :span="8">
+          <el-form-item label="转换系数" prop="coefficient">
+            <el-input v-model="formData.coefficient"/>
+          </el-form-item>
+        </el-col>
+        <el-col :span="8">
+          <el-form-item label="数量单位" prop="unit">
+            <el-input v-model="formData.unit"/>
+          </el-form-item>
+        </el-col>
+      </el-row>
+      <el-row>
+        <el-col :span="24">
+          <el-form-item label="备注" prop="remark">
+            <el-input v-model="formData.remark" type="textarea" maxlength="100"/>
+          </el-form-item>
+        </el-col>
+      </el-row>
+      <el-row>
+        <el-col :span="12">
+          <el-form-item label="数据集" prop="atomItem.dataSet">
+            <el-select v-model="formData.atomItem.dataSet" clearable placeholder="请选择数据集" @change="handleDataSetChange($event)">
+              <el-option
+                v-for="item in dataSetList"
+                :key="item.id"
+                :label="item.name"
+                :value="item.id + ''"
+              />
+            </el-select>
+          </el-form-item>
+        </el-col>
+        <el-col :span="12">
+          <el-form-item label="使用字段" prop="atomItem.usingField">
+            <el-select v-model="formData.atomItem.usingField" clearable placeholder="请选择字段">
+              <el-option
+                v-for="item in dataSetFieldList"
+                :key="item.id"
+                :label="item.fieldCode"
+                :value="item.id + ''"
+              />
+            </el-select>
+          </el-form-item>
+        </el-col>
+        <el-col :span="12">
+          <el-form-item label="统计方式" prop="statFunc">
+            <el-select v-model="formData.atomItem.statFunc" placeholder="请选择">
+              <el-option
+                v-for="dict in getStrDictOptions(DICT_TYPE.STAT_FUNC)"
+                :key="dict.value"
+                :label="dict.label"
+                :value="dict.value"
+              />
+            </el-select>
+          </el-form-item>
+        </el-col>
+      </el-row>
+    </el-form>
+    <template #footer>
+      <el-button :disabled="formLoading" type="primary" @click="submitForm">确 定</el-button>
+      <el-button @click="dialogVisible = false">取 消</el-button>
+    </template>
+  </Dialog>
+</template>
+<script lang="ts" setup>
+  import {DICT_TYPE, getStrDictOptions} from '@/utils/dict'
+  import * as ItemApi from '@/api/data/ind/item/item'
+  import * as DataSetApi from '@/api/data/ind/data/data.set'
+  import * as DataSetFieldApi from '@/api/data/ind/data/data.field'
+  import * as CategoryApi from '@/api/data/ind/category/index'
+
+
+  defineOptions({name: 'IndDataSetForm'})
+
+  const {t} = useI18n() // 国际化
+  const message = useMessage() // 消息弹窗
+
+  const dialogVisible = ref(false) // 弹窗的是否展示
+  const dialogTitle = ref('') // 弹窗的标题
+  const formLoading = ref(false) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用
+  const formType = ref('') // 表单的类型:create - 新增;update - 修改
+  let formData = ref({
+    id: undefined,
+    itemNo: '',
+    itemName: '',
+    itemType: '',
+    itemCategory: '',
+    coefficient: '',
+    precision: '',
+    businessType: '',
+    timeRange: '',
+    timeGranularity: '',
+    remark: '',
+    atomItem:{
+      dataSource:'',
+      dataSet: '',
+      usingField: '',
+      statFunc: ''
+    }
+  })
+  const validateAsNumber = (rule, value, callback) => {
+    const regex = /^(\-|\+)?\d+(\.\d+)?$/;
+    if (!regex.test(value)) {
+      callback(new Error('请输入数字!'));
+    }
+  }
+  const formRules = reactive({
+    itemName: [{required: true, message: '指标名称不能为空', trigger: 'blur'}],
+    itemCategory: [{required: true, message: '指标分类不能为空', trigger: 'blur'}],
+    precision: [{validator: validateAsNumber, trigger: 'blur' }],
+    coefficient: [{validator: validateAsNumber, trigger: 'blur' }],
+    "atomItem.dataSet": [{required: true, message: '数据集不能为空', trigger: 'blur'}],
+    "atomItem.usingField":[{required: true, message: '使用字段不能为空', trigger: 'blur'}]
+  })
+  const formRef = ref() // 表单 Ref
+  const dataSetList = ref([] as DataSetApi.DataSetVO[])
+  const dataSetFieldList = ref([] as DataSetFieldApi.DataSetFieldVO[])
+  const dataCategoryList = ref([])
+  /** 打开弹窗 */
+  const open = async (type: string, id?: string) => {
+    dialogVisible.value = true
+    dialogTitle.value = '原子指标'
+    formType.value = type
+    resetForm()
+    // 加载数据源列表
+    dataSetList.value = await DataSetApi.getDataSetList()
+    dataCategoryList.value = await CategoryApi.getCategoryListAllSimple()
+    // 修改时,设置数据
+    if (id) {
+      formLoading.value = true
+      try {
+        formData.value = await ItemApi.getItem(id)
+        if(formData.value.atomItem.dataSet !== null){
+          const queryParams = reactive({
+            dataSetId: formData.value.atomItem.dataSet,
+          })
+          dataSetFieldList.value = (await DataSetFieldApi.getDataSetFieldPage(queryParams)).list
+        }
+      } finally {
+        formLoading.value = false
+      }
+    }
+
+  }
+  defineExpose({open}) // 提供 open 方法,用于打开弹窗
+
+  /** 提交表单 */
+  const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调
+  const submitForm = async () => {
+    // 校验表单
+    if (!formRef) return
+    const valid = await formRef.value.validate()
+    if (!valid) return
+    // 提交请求
+    formLoading.value = true
+    try {
+      formData.value.itemType = 'ATOM'
+      for (let index in dataSetList.value){
+        if(formData.value.atomItem.dataSet === dataSetList.value[index].id){
+          formData.value.atomItem.dataSource = dataSetList.value[index].dataSource
+        }
+      }
+      const data = formData.value as ItemApi.ItemVO
+      if (formType.value === 'create') {
+        await ItemApi.createItem(data)
+        message.success(t('common.createSuccess'))
+      } else {
+        await ItemApi.updateItem(data)
+        message.success(t('common.updateSuccess'))
+      }
+      dialogVisible.value = false
+      // 发送操作成功的事件
+      emit('success')
+    } finally {
+      formLoading.value = false
+    }
+  }
+
+  /** 重置表单 */
+  const resetForm = () => {
+    formData.value = {
+      id: '',
+      itemNo: '',
+      itemName: '',
+      itemType: '',
+      itemCategory: '',
+      coefficient: '',
+      precision: '',
+      businessType: '',
+      timeRange: '',
+      timeGranularity: '',
+      remark: '',
+      atomItem:{
+        dataSource:'',
+        dataSet: '',
+        usingField: '',
+        statFunc: ''
+      }
+    }
+    dataSetFieldList.value = []
+    formRef.value?.resetFields()
+  }
+
+  async function handleDataSetChange(event) {
+    if (event !== null && event !== undefined) {
+      const queryParams = reactive({
+        dataSetId: event,
+      })
+      dataSetFieldList.value = (await DataSetFieldApi.getDataSetFieldPage(queryParams)).list
+    }
+  }
+
+</script>
diff --git a/src/views/data/ind/item/DerIndDefineForm.vue b/src/views/data/ind/item/DerIndDefineForm.vue
new file mode 100644
index 0000000..2d7d1d9
--- /dev/null
+++ b/src/views/data/ind/item/DerIndDefineForm.vue
@@ -0,0 +1,329 @@
+<template>
+  <Dialog v-model="dialogVisible" :title="dialogTitle" width="55%">
+    <el-form
+      ref="formRef"
+      v-loading="formLoading"
+      :model="formData"
+      :rules="formRules" label-width="100px">
+      <el-row>
+        <el-col :span="12">
+          <el-form-item label="原子指标" prop="atomItem.id">
+            <el-select v-model="selected" clearable placeholder="请选择原子指标"
+                       @change="handleChange($event)">
+              <el-option
+                v-for="item in atomItemList"
+                :key="item.id"
+                :label="item.itemNo"
+                :value="item.id"
+              />
+            </el-select>
+          </el-form-item>
+        </el-col>
+        <el-col :span="12">
+          <el-form-item label="原子指标名称" prop="atomItem.itemName">
+            <el-input v-model="formData.atomItem.itemName" disabled/>
+          </el-form-item>
+        </el-col>
+      </el-row>
+      <el-row>
+        <el-col :span="12">
+          <el-form-item label="指标编码" prop="itemNo">
+            <el-input v-model="formData.itemNo" disabled/>
+          </el-form-item>
+        </el-col>
+        <el-col :span="12">
+          <el-form-item label="指标名称" prop="itemName">
+            <el-input v-model="formData.itemName"/>
+          </el-form-item>
+        </el-col>
+      </el-row>
+      <el-row>
+        <el-col :span="12">
+          <el-form-item label="指标分类" prop="itemCategory">
+            <el-select v-model="formData.itemCategory" clearable placeholder="请选择指标分类">
+              <el-option
+                v-for="item in dataCategoryList"
+                :key="item.id"
+                :label="item.label"
+                :value="item.id + ''"
+              />
+            </el-select>
+          </el-form-item>
+        </el-col>
+        <el-col :span="12">
+          <el-form-item label="时间粒度" prop="timeGranularity">
+            <el-select v-model="formData.timeGranularity" placeholder="请选择">
+              <el-option
+                v-for="dict in getStrDictOptions(DICT_TYPE.TIME_GRANULARITY)"
+                :key="dict.value"
+                :label="dict.label"
+                :value="dict.value"
+              />
+            </el-select>
+          </el-form-item>
+        </el-col>
+      </el-row>
+      <el-row>
+        <el-col :span="8">
+          <el-form-item label="指标精度" prop="precision">
+            <el-input v-model="formData.precision"/>
+          </el-form-item>
+        </el-col>
+        <el-col :span="8">
+          <el-form-item label="转换系数" prop="coefficient">
+            <el-input v-model="formData.coefficient"/>
+          </el-form-item>
+        </el-col>
+        <el-col :span="6">
+          <el-form-item label="数量单位" prop="unit">
+            <el-input v-model="formData.unit"/>
+          </el-form-item>
+        </el-col>
+      </el-row>
+      <el-row>
+        <el-col :span="20">
+          <el-form-item label="备注" prop="remark">
+            <el-input v-model="formData.remark" type="textarea" maxlength="100"/>
+          </el-form-item>
+        </el-col>
+      </el-row>
+      <el-row>
+        <el-col :span="12">
+          <el-form-item label="时间标识" prop="timeLabel">
+            <el-select v-model="formData.derItem.timeLabel" clearable placeholder="请选择时间标识">
+              <el-option
+                v-for="item in dataSetFieldList"
+                :key="item.id"
+                :label="item.fieldCode"
+                :value="item.id + ''"
+              />
+            </el-select>
+          </el-form-item>
+        </el-col>
+        <el-col :span="12">
+          <el-form-item label="时间限定" prop="timeLimit">
+            <el-select v-model="formData.timeLimit" placeholder="请选择"
+                       @change="handleTimeLimitChange($event)">
+              <el-option
+                v-for="dict in getStrDictOptions(DICT_TYPE.TIME_LIMIT)"
+                :key="dict.value"
+                :label="dict.label"
+                :value="dict.value"
+              />
+            </el-select>
+          </el-form-item>
+        </el-col>
+      </el-row>
+      <el-row v-if="showTimeChange">
+        <el-col :span="12">
+          <el-form-item label="开始时间" prop="timeStart">
+            <el-date-picker
+              v-model="formData.derItem.timeStart"
+              type="datetime"
+              placeholder="请选择开始时间"
+            />
+          </el-form-item>
+        </el-col>
+        <el-col :span="8">
+          <el-form-item label="结束时间" prop="timeEnd">
+            <el-date-picker
+              v-model="formData.derItem.timeEnd"
+              type="datetime"
+              placeholder="请选择结束时间"
+            />
+          </el-form-item>
+        </el-col>
+      </el-row>
+      <el-row>
+        <el-col :span="12">
+          <el-form-item label="分析维度" prop="dimension">
+            <el-select v-model="formData.derItem.dimension" clearable placeholder="请选择分析维度" multiple>
+              <el-option
+                v-for="item in dataSetFieldList"
+                :key="item.id"
+                :label="item.fieldCode"
+                :value="item.id + ''"
+              />
+            </el-select>
+          </el-form-item>
+        </el-col>
+      </el-row>
+    </el-form>
+    <template #footer>
+      <el-button :="formLoading" type="primary" @click="submitForm">确 定</el-button>
+      <el-button @click="dialogVisible = false">取 消</el-button>
+    </template>
+  </Dialog>
+</template>
+<script lang="ts" setup>
+  import {DICT_TYPE, getStrDictOptions} from '@/utils/dict'
+  import * as DataSetApi from '@/api/data/ind/data/data.set'
+  import * as ItemApi from '@/api/data/ind/item/item'
+  import {CommonStatusEnum} from '@/utils/constants'
+  import * as DataSourceConfigApi from "@/api/infra/dataSourceConfig";
+  import {PageParam} from "@/api/data/ind/item/item";
+  import * as CategoryApi from "@/api/data/ind/category";
+  import * as DataSetFieldApi from "@/api/data/ind/data/data.field";
+
+  defineOptions({name: 'IndDataSetForm'})
+
+  const {t} = useI18n() // 国际化
+  const message = useMessage() // 消息弹窗
+
+  const dialogVisible = ref(false) // 弹窗的是否展示
+  const dialogTitle = ref('') // 弹窗的标题
+  const formLoading = ref(false) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用
+  const formType = ref('') // 表单的类型:create - 新增;update - 修改
+  let formData = ref({
+    id: undefined,
+    itemNo: '',
+    itemName: '',
+    itemType: '',
+    itemCategory: '',
+    coefficient: '',
+    precision: '',
+    businessType: '',
+    timeRange: '',
+    timeGranularity: '',
+    atomItem: {
+      id: '',
+      itemNo: '',
+      itemName: '',
+    },
+    derItem: {
+      atomItemId: '',
+      timeLabel: '',
+      timeLimit: '',
+      timeStart: '',
+      timeEnd: '',
+      dimension: ''
+    }
+  })
+  const queryParams = ref({
+    itemType: 'ATOM'
+  })
+
+  const validateAsNumber = (rule, value, callback) => {
+    const regex = /^(\-|\+)?\d+(\.\d+)?$/;
+    if (!regex.test(value)) {
+      callback(new Error('请输入数字!'));
+    }
+  }
+
+  const formRules = reactive({
+    itemName: [{required: true, message: '指标名称不能为空', trigger: 'blur'}],
+    itemCategory: [{required: true, message: '指标类型不能为空', trigger: 'blur'}],
+    precision: [{validator: validateAsNumber, trigger: 'blur' }],
+    coefficient: [{validator: validateAsNumber, trigger: 'blur' }],
+    "atomItem.id": [{required: true, message: '原子指标不能为空', trigger: 'blur'}]
+  })
+  const formRef = ref() // 表单 Ref
+  const dataSourceList = ref([] as DataSourceConfigApi.DataSourceConfigVO[])
+  const atomItemList = ref([] as ItemApi.ItemVO[])
+  const selected = ref(null)
+  const showTimeChange = ref(false)
+  const dataCategoryList = ref([] as CategoryApi.IndItemCategoryVO[])
+  const dataSetFieldList = ref([] as DataSetFieldApi.DataSetFieldVO[])
+
+  /** 打开弹窗 */
+  const open = async (type: string, id?: string) => {
+    dialogVisible.value = true
+    dialogTitle.value = '派生指标'
+    formType.value = type
+    resetForm()
+    // 加载数据源列表
+    dataCategoryList.value = await CategoryApi.getCategoryListAllSimple()
+    atomItemList.value = await ItemApi.getItemList(queryParams)
+    selected.value = null
+    // 修改时,设置数据
+    if (id) {
+      formLoading.value = true
+      try {
+        formData.value = await ItemApi.getItem(id)
+      } finally {
+        formLoading.value = false
+      }
+    }
+  }
+  defineExpose({open}) // 提供 open 方法,用于打开弹窗
+
+  /** 提交表单 */
+  const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调
+  const submitForm = async () => {
+    // 校验表单
+    if (!formRef) return
+    const valid = await formRef.value.validate()
+    if (!valid) return
+    // 提交请求
+    formLoading.value = true
+    try {
+      formData.value.itemType = 'DER'
+      formData.value.derItem.atomItemId = formData.value.atomItem.id
+      if(formData.value.derItem.dimension.length > 0){
+        let dimension = ''
+        for (let index in formData.value.derItem.dimension){
+          dimension = dimension + formData.value.derItem.dimension[index] + ','
+        }
+        formData.value.derItem.dimension = dimension.substring(0, dimension.length - 1)
+      }
+      const data = formData.value as ItemApi.ItemVO
+      if (formType.value === 'create') {
+        await ItemApi.createItem(data)
+        message.success(t('common.createSuccess'))
+      } else {
+        await ItemApi.updateItem(data)
+        message.success(t('common.updateSuccess'))
+      }
+      dialogVisible.value = false
+      // 发送操作成功的事件
+      emit('success')
+    } finally {
+      formLoading.value = false
+    }
+  }
+  /** 重置表单 */
+  const resetForm = () => {
+    formData.value = {
+      id: undefined,
+      itemNo: '',
+      itemName: '',
+      itemType: '',
+      itemCategory: '',
+      coefficient: '',
+      precision: '',
+      businessType: '',
+      timeRange: '',
+      timeGranularity: '',
+      remark: '',
+      atomItem: {
+        id: '',
+        itemNo: '',
+        itemName: '',
+      },
+      derItem: {
+        atomItemId: '',
+        timeLabel: '',
+        timeLimit: '',
+        timeStart: '',
+        timeEnd: '',
+        dimension: ''
+      }
+    }
+  }
+
+  async function handleChange(event) {
+    if (event !== null && event !== undefined) {
+      const itemData = await ItemApi.getItem(event)
+      formData.value.atomItem.itemName = itemData.itemName
+      formData.value.atomItem.id = itemData.atomItem.id
+      const queryParams = reactive({
+        dataSetId: itemData.atomItem.dataSet,
+      })
+      dataSetFieldList.value = (await DataSetFieldApi.getDataSetFieldPage(queryParams)).list
+    }
+  }
+
+  function handleTimeLimitChange(event) {
+    showTimeChange.value = event === 'CUSTOM';
+  }
+</script>
diff --git a/src/views/data/ind/item/index.vue b/src/views/data/ind/item/index.vue
new file mode 100644
index 0000000..281115e
--- /dev/null
+++ b/src/views/data/ind/item/index.vue
@@ -0,0 +1,195 @@
+<template>
+  <!-- 搜索工作栏 -->
+  <ContentWrap>
+    <el-form ref="queryFormRef" :inline="true" :model="queryParams" class="-mb-15px"
+             label-width="68px">
+      <el-form-item label="指标编码" prop="name">
+        <el-input v-model="queryParams.itemNo" class="!w-240px" clearable placeholder="请输入指标编码"
+                  @keyup.enter="handleQuery"/>
+      </el-form-item>
+      <el-form-item label="指标名称" prop="name">
+        <el-input v-model="queryParams.itemName" class="!w-240px" clearable placeholder="请输入指标名称"
+                  @keyup.enter="handleQuery"/>
+      </el-form-item>
+      <el-form-item>
+        <el-button @click="handleQuery">
+          <Icon class="mr-5px" icon="ep:search"/>
+          搜索
+        </el-button>
+        <el-button @click="resetQuery">
+          <Icon class="mr-5px" icon="ep:refresh"/>
+          重置
+        </el-button>
+        <el-button
+          v-hasPermi="['data:ind-item:create']"
+          plain
+          type="primary"
+          @click="openForm('create')"
+        >
+          <Icon class="mr-5px" icon="ep:plus"/>
+          新增
+        </el-button>
+      </el-form-item>
+    </el-form>
+  </ContentWrap>
+
+  <!-- 列表 -->
+  <ContentWrap>
+    <el-table v-loading="loading" :data="list">
+      <el-table-column prop="itemNo" label="指标编码" header-align="center" align="center" min-width="80"/>
+      <el-table-column prop="itemName" label="指标名称" header-align="center" align="center" min-width="120"/>
+      <el-table-column prop="itemCategoryName" label="指标分类" header-align="center" align="center" min-width="100"/>
+      <el-table-column prop="itemType" label="指标类型" header-align="center" align="center" min-width="60">
+        <template #default="scope">
+          <dict-tag :type="DICT_TYPE.ITEM_TYPE" :value="scope.row.itemType" />
+        </template>
+      </el-table-column>
+      <el-table-column prop="coefficient" label="系数" header-align="center" align="center" min-width="60"/>
+      <el-table-column prop="precision" label="指标精度" header-align="center" align="center" min-width="60"/>
+      <el-table-column prop="timeGranularity" label="时间粒度" header-align="center" align="center" min-width="40">
+        <template #default="scope">
+          <dict-tag :type="DICT_TYPE.TIME_GRANULARITY" :value="scope.row.timeGranularity" />
+        </template>
+      </el-table-column>
+      <el-table-column
+        :formatter="dateFormatter"
+        align="center"
+        label="创建时间"
+        prop="createTime"
+        width="180"/>
+      <el-table-column align="center" label="操作">
+        <template #default="scope">
+          <el-button
+            v-hasPermi="['data:ind-item:update']"
+            link
+            type="primary"
+            @click="openForm('update', scope.row)">
+            修改
+          </el-button>
+          <el-button
+            v-hasPermi="['data:ind-item:delete']"
+            link
+            type="danger"
+            @click="handleDelete(scope.row.id)">
+            删除
+          </el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+    <!-- 分页 -->
+    <Pagination
+      v-model:limit="queryParams.pageSize"
+      v-model:page="queryParams.pageNo"
+      :total="total"
+      @pagination="getList"
+    />
+  </ContentWrap>
+
+  <!-- 表单弹窗:添加/修改 -->
+  <AtomIndDefineForm ref="atomFormRef" @success="getList" />
+  <DerIndDefineForm ref="derFormRef" @success="getList" />
+  <CalIndDefineForm ref="calFormRef" @success="getList" />
+  <SelectItemType ref="itemTypeSel"/>
+</template>
+
+<script lang="ts" setup>
+  import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
+  import { dateFormatter } from '@/utils/formatTime'
+  import * as DataSetApi from '@/api/data/ind/data/data.set'
+  import AtomIndDefineForm from './AtomIndDefineForm.vue'
+  import DerIndDefineForm from './DerIndDefineForm.vue'
+  import CalIndDefineForm from './CalIndDefineForm.vue'
+  import SelectItemType from './selectItemType.vue'
+  import download from '@/utils/download'
+  import * as ItemApi from '@/api/data/ind/item/item'
+  import * as CategoryApi from "@/api/data/ind/category";
+
+  defineOptions({ name: 'IndDataSet' })
+
+  const message = useMessage() // 消息弹窗
+  const { t } = useI18n() // 国际化
+  const dataCategoryList = ref([] as CategoryApi.IndItemCategoryVO[])
+  const loading = ref(true) // 列表的加载中
+  const total = ref(0) // 列表的总页数
+  const list = ref([]) // 字典表格数据
+  const queryParams = reactive({
+    pageNo: 1,
+    pageSize: 10,
+    itemNo: '',
+    itemName: '',
+    itemType: '',
+    itemCategory: ''
+  })
+  const queryFormRef = ref() // 搜索的表单
+  const exportLoading = ref(false) // 导出的加载中
+
+  /** 查询字典类型列表 */
+  const getList = async () => {
+    loading.value = true
+    try {
+      const data = await ItemApi.getItemPage(queryParams)
+      list.value = data.list
+      total.value = data.total
+      dataCategoryList.value = await CategoryApi.getCategoryListAllSimple()
+    } finally {
+      loading.value = false
+    }
+  }
+
+  /** 搜索按钮操作 */
+  const handleQuery = () => {
+    queryParams.pageNo = 1
+    getList()
+  }
+
+  /** 重置按钮操作 */
+  const resetQuery = () => {
+    queryFormRef.value.resetFields()
+    handleQuery()
+  }
+
+  /** 添加/修改操作 */
+  const atomFormRef = ref()
+  const derFormRef = ref()
+  const calFormRef = ref()
+  const itemTypeSel = ref()
+
+  const openForm = (type: string, row) => {
+    if(row !== null && row !==undefined){
+      if(row.itemType === 'ATOM'){
+        if (row.id){
+          atomFormRef.value.open(type,row.id)
+        }
+      }else if(row.itemType === 'CAL'){
+        if (row.id){
+          calFormRef.value.open(type,row.id)
+        }
+      }else if(row.itemType === 'DER'){
+        if (row.id){
+          derFormRef.value.open(type,row.id)
+        }
+      }
+    }else {
+      itemTypeSel.value.open(type)
+    }
+
+  }
+
+  /** 删除按钮操作 */
+  const handleDelete = async (id: number) => {
+    try {
+      // 删除的二次确认
+      await message.delConfirm()
+      // 发起删除
+      await ItemApi.deleteItem(id)
+      message.success(t('common.delSuccess'))
+      // 刷新列表
+      await getList()
+    } catch {}
+  }
+
+  /** 初始化 **/
+  onMounted(() => {
+    getList()
+  })
+</script>
diff --git a/src/views/data/ind/item/selectItemType.vue b/src/views/data/ind/item/selectItemType.vue
new file mode 100644
index 0000000..2b09ee2
--- /dev/null
+++ b/src/views/data/ind/item/selectItemType.vue
@@ -0,0 +1,96 @@
+<template>
+  <Dialog v-model="dialogVisible" :title="dialogTitle" width="47%">
+    <div class="card" @click="openForm('ATOM')">
+      <img src="../img/ATOM.png" alt="Card Image" class="card-img"/>
+      <div class="card-body">
+        <p class="card-title-text">{{ "原子指标" }}</p>
+        <p class="card-text">{{ "从0开始创建一个新指标" }}</p>
+      </div>
+    </div>
+    <div class="card" @click="openForm('DER')">
+      <img src="../img/DER.png" alt="Card Image" class="card-img"/>
+      <div class="card-body">
+        <p class="card-title-text">{{ "派生指标" }}</p>
+        <p class="card-text">{{ "基于单个原子指标通过条件过滤派生出的新指标" }}</p>
+      </div>
+    </div>
+    <div class="card" @click="openForm('CAL')">
+      <img src="../img/CAL.png" alt="Card Image" class="card-img"/>
+      <div class="card-body">
+        <p class="card-title-text">{{ "复合指标" }}</p>
+        <p class="card-text">{{ "基于一组原子指标通过条件过滤派生出的新指标" }}</p>
+      </div>
+    </div>
+  </Dialog>
+  <AtomIndDefineForm ref="atomFormRef" @success="getList" />
+  <DerIndDefineForm ref="derFormRef" @success="getList" />
+  <CalIndDefineForm ref="calFormRef" @success="getList" />
+</template>
+<script lang="ts" setup>
+  import * as DataSetApi from '@/api/data/ind/data/data.set'
+  import AtomIndDefineForm from './AtomIndDefineForm.vue'
+  import DerIndDefineForm from './DerIndDefineForm.vue'
+  import CalIndDefineForm from './CalIndDefineForm.vue'
+
+  defineOptions({ name: 'IndDataSetForm' })
+
+  const { t } = useI18n() // 国际化
+  const message = useMessage() // 消息弹窗
+
+  const dialogVisible = ref(false) // 弹窗的是否展示
+  const dialogTitle = ref('') // 弹窗的标题
+  const formLoading = ref(false) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用
+  const formType = ref('') // 表单的类型:create - 新增;update - 修改
+
+  /** 打开弹窗 */
+  const open = async (type: string) => {
+    dialogVisible.value = true
+    dialogTitle.value = t('action.' + type)
+    formType.value = type
+  }
+  defineExpose({ open }) // 提供 open 方法,用于打开弹窗
+
+  const atomFormRef = ref()
+  const derFormRef = ref()
+  const calFormRef = ref()
+  const openForm = (category: string) => {
+    if(category === 'ATOM'){
+      atomFormRef.value.open("create",null)
+    }else if(category === 'DER'){
+      derFormRef.value.open("create",null)
+    }else if(category === 'CAL'){
+      calFormRef.value.open("create",null)
+    }
+  }
+</script>
+
+<style scoped>
+  .card {
+    width: 25vh;
+    margin: 10px 16px;
+    display: inline-block;
+    vertical-align: top;
+    border: 1px solid #ddd;
+    border-radius: 4px;
+    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
+    height: 30vh;
+    cursor: pointer;
+  }
+  .card-img {
+    width: 100%;
+    height: 150px;
+    object-fit: cover;
+  }
+
+  .card-body {
+    padding: 10px;
+    text-align: center;
+  }
+  .card-title-text{
+    font-size: larger;
+  }
+  .card-text {
+    font-size: smaller;
+    margin: 0;
+  }
+</style>

--
Gitblit v1.9.3