Bladeren bron

feat:灵活模板-数据源管理加入时间格式和时间范围限制,对应的过滤器加入规则

韩洋 5 maanden geleden
bovenliggende
commit
7d2f812b95

+ 46 - 2
src/modules/data-source-manage/add-source/components/ApiFieldConfig.vue

@@ -17,12 +17,15 @@
             <th>字段角色</th>
             <th>是否可聚合</th>
             <th>是否必填</th>
+            <th>是否支持接口参数</th>
             <th>通用配置类型</th>
             <th>是否需要展示字段</th>
             <th>接口参数是否支持多值</th>
             <th>接口参数是否支持模糊查询</th>
             <th>多值分隔符</th>
             <th>枚举类型ID</th>
+            <th>日期格式</th>
+            <th>时间限制</th>
             <th>操作</th>
           </tr>
         </thead>
@@ -58,6 +61,12 @@
                 <a-option :value="1">是</a-option>
               </a-select>
             </td>
+            <td>
+              <a-select v-model="field.is_support_api_query_condition" @change="handleFieldChange">
+                <a-option :value="0">否</a-option>
+                <a-option :value="1">是</a-option>
+              </a-select>
+            </td>
             <td>
               <a-input v-model="field.common_config_type" @input="handleFieldChange" placeholder="通用配置类型" />
             </td>
@@ -88,6 +97,26 @@
                 <a-option :value="1">有</a-option>
               </a-select>
             </td>
+            <td>
+              <a-select v-model="field.format_str" @change="handleFieldChange" :disabled="field.field_type !== 'date'">
+                <a-option value="date">精确到日期</a-option>
+                <a-option value="datetime">精确到时间</a-option>
+              </a-select>
+            </td>
+            <td>
+              <a-select
+                v-model="field.time_limit"
+                @change="handleFieldChange"
+                :disabled="field.field_type !== 'date'"
+                allow-clear
+                :style="{ width: '170px' }"
+              >
+                <a-option value="limit_to_yesterday_start">昨天的 00:00:00</a-option>
+                <a-option value="limit_to_yesterday_end">昨天的 23:59:59</a-option>
+                <a-option value="limit_to_day_start">今天的 00:00:00</a-option>
+                <a-option value="limit_to_day_end">今天的 23:59:59</a-option>
+              </a-select>
+            </td>
             <td>
               <a-button type="outline" status="danger" @click="deleteField(index)"><icon-delete /></a-button>
             </td>
@@ -120,8 +149,20 @@ watch(() => props.modelValue, (newValue) => {
 
 // 通知父组件数据变化
 const notifyParent = () => {
+  // 处理非date类型的字段,不保留日期格式和时间限制
+  const processedFields = metric_fields.value.map(field => {
+    if (field.field_type !== 'date') {
+      return {
+        ...field,
+        format_str: undefined,
+        time_limit: undefined
+      };
+    }
+    return field;
+  });
+
   emit('update:modelValue', {
-    metric_fields: metric_fields.value
+    metric_fields: processedFields
   });
 };
 
@@ -140,12 +181,15 @@ const addField = () => {
     column_role: 'dim',
     is_aggregatable: 0,
     is_required: 0,
+    is_support_api_query_condition: 0,
     common_config_type: null,
     is_api_support_multi_value: 0,
     is_api_support_fuzzy_query: 0,
     multi_value_delimiter: ',',
     is_needs_show_fields: 1,
-    enum_type_id: 0
+    enum_type_id: 0,
+    format_str: 'date', // 默认精确到日期
+    time_limit: 'limit_to_day_start' // 默认截止到昨天
   }];
   notifyParent();
 };

+ 42 - 2
src/modules/data-source-manage/add-source/components/DbFieldConfig.vue

@@ -17,9 +17,12 @@
             <th>字段角色</th>
             <th>是否可聚合</th>
             <th>是否必填</th>
+            <th>通用配置类型</th>
             <th>是否需要展示字段</th>
             <th>字段来源表</th>
             <th>枚举类型ID</th>
+            <th>日期格式</th>
+            <th>时间限制</th>
             <th>操作</th>
           </tr>
         </thead>
@@ -55,6 +58,9 @@
                 <a-option :value="1">是</a-option>
               </a-select>
             </td>
+            <td>
+              <a-input v-model="field.common_config_type" @input="handleFieldChange" placeholder="通用配置类型" />
+            </td>
             <td>
               <a-select v-model="field.is_needs_show_fields" @change="handleFieldChange">
                 <a-option :value="0">否</a-option>
@@ -71,6 +77,26 @@
               </a-select>
               <!-- <a-input v-model="field.enum_type_id" @input="handleFieldChange" placeholder="枚举类型ID" /> -->
             </td>
+            <td>
+              <a-select v-model="field.format_str" @change="handleFieldChange" :disabled="field.field_type !== 'date'">
+                <a-option value="date">精确到日期</a-option>
+                <a-option value="datetime">精确到时间</a-option>
+              </a-select>
+            </td>
+            <td>
+              <a-select
+                v-model="field.time_limit"
+                :style="{ width: '160px' }"
+                @change="handleFieldChange"
+                :disabled="field.field_type !== 'date'"
+                allow-clear
+              >
+                <a-option value="limit_to_yesterday_start">昨天的 00:00:00</a-option>
+                <a-option value="limit_to_yesterday_end">昨天的 23:59:59</a-option>
+                <a-option value="limit_to_day_start">今天的 00:00:00</a-option>
+                <a-option value="limit_to_day_end">今天的 23:59:59</a-option>
+              </a-select>
+            </td>
             <td>
               <a-button type="outline" status="danger" @click="deleteField(index)"><icon-delete /></a-button>
             </td>
@@ -103,8 +129,20 @@ watch(() => props.modelValue, (newValue) => {
 
 // 通知父组件数据变化
 const notifyParent = () => {
+  // 处理非date类型的字段,不保留日期格式和时间限制
+  const processedFields = metric_fields.value.map(field => {
+    if (field.field_type !== 'date') {
+      return {
+        ...field,
+        date_format: undefined,
+        time_limit: undefined
+      };
+    }
+    return field;
+  });
+
   emit('update:modelValue', {
-    metric_fields: metric_fields.value
+    metric_fields: processedFields
   });
 };
 
@@ -126,7 +164,9 @@ const addField = () => {
     common_config_type: null,
     field_from_table: '',
     is_needs_show_fields: 1,
-    enum_type_id: 0
+    enum_type_id: 0,
+    date_format: 'date', // 默认精确到日期
+    time_limit: 'limit_to_day_start' // 默认截止到昨天
   }];
   notifyParent();
 };

+ 1 - 0
src/modules/report-template/TemplateDetail.vue

@@ -184,6 +184,7 @@ const getMetricsFun = async () => {
       if (data_source_list.value.length > 0) {
         const flexible_template_metric_fields = data_source_list.value[0].flexible_template_metric_fields;
         if (flexible_template_metric_fields.length) {
+          console.log(data_source_list.value);
           setDataToMetricsAndDimension(flexible_template_metric_fields, data_source_list.value[0]);
           getTargetCommonConfigInfo(flexible_template_metric_fields);
         }

+ 0 - 1
src/modules/report-template/editor-model/EditorDetail.vue

@@ -888,7 +888,6 @@ function insertOption(opt) {
   sel.removeAllRanges();
   sel.addRange(newRange);
   // 保存到MentionData列表中
-
   mentionsData.value.push({
     uid,
     option: opt

+ 1 - 0
src/modules/report-template/editor-model/EditorTitleHeader.vue

@@ -265,6 +265,7 @@ const editTemplateFunc = async (id, type = 1) => {
       common_config: JSON.stringify(reportEditor.common_config),
       type: type
     });
+    console.log(212, reportEditor.metrics_list);
     if (res.code / 1 === 200) {
       return res;
     } else {

+ 1 - 1
src/modules/report-template/filter-model/MentionFilter.vue

@@ -578,7 +578,7 @@ defineExpose({
   flex-direction: column;
   gap: 10px;
   min-height: 36px;
-  max-height: 100%;
+  max-height: calc(100% - 20px);
   overflow-y: auto;
   margin: 10px 0px;
   padding: 5px 3px;

+ 173 - 3
src/modules/report-template/filter-model/model/DateModel.vue

@@ -37,15 +37,43 @@
 
       <!-- 日期选择 -->
       <a-form-item v-if="formModel.rangeType === 'start'" label="过滤条件">
-        <a-date-picker v-model="formModel.startDate" style="width: 100%" />
+        <a-date-picker
+          v-model="formModel.startDate"
+          :showTime="props.filter?.format_str === 'datetime'"
+          :type="props.filter?.format_str === 'datetime' ? 'datetime' : 'date'"
+          :disabledDate="disabledDate"
+          :disabledTime="props.filter?.format_str === 'datetime' ? disabledTime : undefined"
+          :show-now-btn="false"
+          class="date-picker-custom"
+          style="width: 100%"
+        />
       </a-form-item>
 
       <a-form-item v-if="formModel.rangeType === 'end'" label="过滤条件">
-        <a-date-picker v-model="formModel.endDate" style="width: 100%" />
+        <a-date-picker
+          v-model="formModel.endDate"
+          :showTime="props.filter?.format_str === 'datetime'"
+          :type="props.filter?.format_str === 'datetime' ? 'datetime' : 'date'"
+          :disabledDate="disabledDate"
+          :disabledTime="props.filter?.format_str === 'datetime' ? disabledTime : undefined"
+          :show-now-btn="false"
+          class="date-picker-custom"
+          style="width: 100%"
+        />
       </a-form-item>
 
       <a-form-item v-if="formModel.rangeType === 'between'" label="过滤条件">
-        <a-range-picker v-model="formModel.dateRange" style="width: 100%" />
+        <a-range-picker
+          v-model="formModel.dateRange"
+          :showTime="props.filter?.format_str === 'datetime'"
+          :type="props.filter?.format_str === 'datetime' ? 'datetime' : 'date'"
+          :disabledDate="disabledDate"
+          :disabledTime="props.filter?.format_str === 'datetime' ? disabledRangeTime : undefined"
+          :timePickerProps="{ hideDisabledOptions: true }"
+          :show-now-btn="false"
+          class="date-picker-custom"
+          style="width: 100%"
+        />
       </a-form-item>
     </a-form>
   </a-modal>
@@ -86,6 +114,141 @@ const formModel = ref({
   is_aggregatable: 1
 });
 
+// 禁用日期函数
+const disabledDate = (current) => {
+  const timeLimit = props.filter?.time_limit;
+  const now = new Date();
+  const yesterday = new Date(now);
+  yesterday.setDate(yesterday.getDate() - 1);
+
+  // 重置时间部分,只比较日期
+  const currentDate = new Date(current);
+  currentDate.setHours(0, 0, 0, 0);
+  const todayDate = new Date(now);
+  todayDate.setHours(0, 0, 0, 0);
+  const yesterdayDate = new Date(yesterday);
+  yesterdayDate.setHours(0, 0, 0, 0);
+
+  switch (timeLimit) {
+    case 'limit_to_day_start':
+    case 'limit_to_day_end':
+      // 最多选到今天
+      return currentDate > todayDate;
+    case 'limit_to_yesterday_start':
+    case 'limit_to_yesterday_end':
+      // 最多选到昨天
+      return currentDate > yesterdayDate;
+    default:
+      return false;
+  }
+};
+
+// 禁用时间函数(单个日期选择器)
+const disabledTime = (date) => {
+  const timeLimit = props.filter?.time_limit;
+  const now = new Date();
+
+  // 检查当前选择的日期是否是限制的最后一天
+  const selectedDate = new Date(date);
+  selectedDate.setHours(0, 0, 0, 0);
+
+  const todayDate = new Date(now);
+  todayDate.setHours(0, 0, 0, 0);
+
+  const yesterdayDate = new Date(now);
+  yesterdayDate.setDate(yesterdayDate.getDate() - 1);
+  yesterdayDate.setHours(0, 0, 0, 0);
+
+  // 检查是否是限制的最后一天
+  const isLastDay =
+    ((timeLimit === 'limit_to_day_start' || timeLimit === 'limit_to_day_end') &&
+      selectedDate.getTime() === todayDate.getTime()) ||
+    ((timeLimit === 'limit_to_yesterday_start' || timeLimit === 'limit_to_yesterday_end') &&
+      selectedDate.getTime() === yesterdayDate.getTime());
+
+  if (!isLastDay) {
+    return {};
+  }
+
+  switch (timeLimit) {
+    case 'limit_to_day_start':
+      // 最多选到今天的 00:00:00
+      return {
+        disabledHours: () => Array.from({ length: 24 }, (_, i) => i).filter((hour) => hour > 0),
+        disabledMinutes: () => Array.from({ length: 60 }, (_, i) => i).filter((minute) => minute > 0),
+        disabledSeconds: () => Array.from({ length: 60 }, (_, i) => i).filter((second) => second > 0)
+      };
+    case 'limit_to_yesterday_start':
+      // 最多选到昨天的 00:00:00
+      return {
+        disabledHours: () => Array.from({ length: 24 }, (_, i) => i).filter((hour) => hour > 0),
+        disabledMinutes: () => Array.from({ length: 60 }, (_, i) => i).filter((minute) => minute > 0),
+        disabledSeconds: () => Array.from({ length: 60 }, (_, i) => i).filter((second) => second > 0)
+      };
+    case 'limit_to_day_end':
+      // 最多选到今天的 23:59:59
+      return {};
+    case 'limit_to_yesterday_end':
+      // 最多选到昨天的 23:59:59
+      return {};
+    default:
+      return {};
+  }
+};
+
+// 禁用时间函数(范围选择器)
+const disabledRangeTime = (date, type) => {
+  const timeLimit = props.filter?.time_limit;
+  const now = new Date();
+
+  // 检查当前选择的日期是否是限制的最后一天
+  const selectedDate = new Date(date);
+  selectedDate.setHours(0, 0, 0, 0);
+
+  const todayDate = new Date(now);
+  todayDate.setHours(0, 0, 0, 0);
+
+  const yesterdayDate = new Date(now);
+  yesterdayDate.setDate(yesterdayDate.getDate() - 1);
+  yesterdayDate.setHours(0, 0, 0, 0);
+
+  // 检查是否是限制的最后一天
+  const isLastDay =
+    ((timeLimit === 'limit_to_day_start' || timeLimit === 'limit_to_day_end') &&
+      selectedDate.getTime() === todayDate.getTime()) ||
+    ((timeLimit === 'limit_to_yesterday_start' || timeLimit === 'limit_to_yesterday_end') &&
+      selectedDate.getTime() === yesterdayDate.getTime());
+
+  if (!isLastDay) {
+    return {};
+  }
+
+  switch (timeLimit) {
+    case 'limit_to_day_start':
+      // 最多选到今天的 00:00:00
+      return {
+        disabledHours: () => Array.from({ length: 24 }, (_, i) => i).filter((hour) => hour > 0),
+        disabledMinutes: () => Array.from({ length: 60 }, (_, i) => i).filter((minute) => minute > 0),
+        disabledSeconds: () => Array.from({ length: 60 }, (_, i) => i).filter((second) => second > 0)
+      };
+    case 'limit_to_yesterday_start':
+      // 最多选到昨天的 00:00:00
+      return {
+        disabledHours: () => Array.from({ length: 24 }, (_, i) => i).filter((hour) => hour > 0),
+        disabledMinutes: () => Array.from({ length: 60 }, (_, i) => i).filter((minute) => minute > 0),
+        disabledSeconds: () => Array.from({ length: 60 }, (_, i) => i).filter((second) => second > 0)
+      };
+    case 'limit_to_day_end':
+      // 最多选到今天的 23:59:59
+      return {};
+    case 'limit_to_yesterday_end':
+      // 最多选到昨天的 23:59:59
+      return {};
+    default:
+      return {};
+  }
+};
+
 // 2. 从 props 获取配置(安全)
 const templateConfig = computed(() => {
   return Array.isArray(props.filter?.template_config) ? props.filter.template_config : [];
@@ -98,6 +261,7 @@ const rangeTypeConfig = computed(() => {
 // 3. 【关键】初始化表单(避免在 reactive 中直接用 computed)
 const initForm = () => {
   const f = props.filter || {};
+  console.log('initForm', f);
 
   // 字段基础信息
   formModel.value.field_name = f.field_name || '字段名称';
@@ -242,3 +406,9 @@ const handleCancel = () => {
   background-color: var(--primary-default);
 }
 </style>
+<style>
+.arco-picker-cell-selected .arco-picker-date-value {
+  color: white;
+  background-color: var(--primary-default);
+}
+</style>