浏览代码

feat: 优化细节

叶静 3 周之前
父节点
当前提交
d28f6bdd62

+ 20 - 15
src/app/shop/admin/data/report/components/chartEdit.vue

@@ -7,10 +7,10 @@
           <!-- 左侧图表列表 -->
           <div class="chart-list-section">
             <div class="list-header">
-              <h4>选择数据维度</h4>
+              <h4>{{ t('dataReport.selectDataDimension') }}</h4>
               <div class="search-box">
-                <el-input v-model="searchKeyword" placeholder="搜索图表名称" prefix-icon="Search" clearable
-                  @input="filterCharts" />
+                <el-input v-model="searchKeyword" :placeholder="t('dataReport.searchChartName')" prefix-icon="Search"
+                  clearable @input="filterCharts" />
               </div>
             </div>
 
@@ -28,7 +28,8 @@
                 <el-icon class="empty-icon">
                   <Search />
                 </el-icon>
-                <div class="empty-text">{{ searchKeyword ? '未找到匹配的图表' : '暂无可选图表' }}</div>
+                <div class="empty-text">{{ searchKeyword ? t('dataReport.noMatchingCharts') :
+                  t('dataReport.noChartsAvailable') }}</div>
               </div>
             </div>
           </div>
@@ -40,8 +41,8 @@
               <el-icon class="empty-icon">
                 <TrendCharts />
               </el-icon>
-              <div class="empty-text">请选择左侧数据维度进行预览</div>
-              <div class="empty-desc">选择后将显示对应的图表预览效果</div>
+              <div class="empty-text">{{ t('dataReport.selectLeftDataDimension') }}</div>
+              <div class="empty-desc">{{ t('dataReport.selectToShowPreview') }}</div>
             </div>
 
             <div v-else class="preview-content">
@@ -55,12 +56,12 @@
 
         <!-- 底部操作按钮 -->
         <el-footer class="sa-footer--submit">
-          <el-button @click="cancel">取消</el-button>
+          <el-button @click="cancel">{{ t('common.cancel') }}</el-button>
           <el-button type="primary" @click="confirm" :disabled="selectedCharts.length === 0">
             <el-icon>
               <Plus />
             </el-icon>
-            确认添加 ({{ selectedCharts.length }})
+            {{ t('dataReport.confirmAdd') }} ({{ selectedCharts.length }})
           </el-button>
         </el-footer>
       </div>
@@ -75,9 +76,13 @@ import {
   Search,
   Plus
 } from '@element-plus/icons-vue';
+import { useI18n } from 'vue-i18n';
 import { api } from '../../data.service.js';
 import ReportChart from './report-chart.vue';
 
+// 使用国际化
+const { t } = useI18n();
+
 const props = defineProps({
   modal: {
     type: Object,
@@ -138,7 +143,7 @@ async function getChartList() {
     chartListLoading.value = true;
     const spectId = props.modal.params.spectId;
     if (!spectId) {
-      ElMessage.error('缺少看板ID参数');
+      ElMessage.error(t('dataReport.missingDashboardId'));
       return;
     }
 
@@ -146,11 +151,11 @@ async function getChartList() {
     if (code === '200') {
       chartList.value = data || [];
     } else {
-      ElMessage.error('获取图表列表失败');
+      ElMessage.error(t('dataReport.getChartListFailed'));
     }
   } catch (error) {
     console.error('获取图表列表失败:', error);
-    ElMessage.error('获取图表列表失败');
+    ElMessage.error(t('dataReport.getChartListFailed'));
   } finally {
     chartListLoading.value = false;
   }
@@ -186,7 +191,7 @@ function cancel() {
 // 确认添加图表
 async function confirm() {
   if (selectedCharts.value.length === 0) {
-    ElMessage.warning('请选择至少一个图表');
+    ElMessage.warning(t('dataReport.selectAtLeastOneChart'));
     return;
   }
 
@@ -202,14 +207,14 @@ async function confirm() {
 
     const { code } = await api.report.dimensions.add(submitData);
     if (code === '200') {
-      ElMessage.success(`成功添加${selectedCharts.value.length}个图表`);
+      ElMessage.success(t('dataReport.addChartsSuccess', { count: selectedCharts.value.length }));
       emit('modalCallBack', { event: 'confirm' });
     } else {
-      ElMessage.error('添加图表失败');
+      ElMessage.error(t('dataReport.addChartsFailed'));
     }
   } catch (error) {
     console.error('添加图表失败:', error);
-    ElMessage.error('添加图表失败');
+    ElMessage.error(t('dataReport.addChartsFailed'));
   }
 }
 

+ 11 - 7
src/app/shop/admin/data/report/components/dashboardEdit.vue

@@ -2,17 +2,17 @@
   <el-container>
     <el-main>
       <el-form :model="form.model" :rules="form.rules" ref="formRef" :label-width="formLabelWidth">
-        <el-form-item label="看板名称" prop="name">
-          <el-input v-model="form.model.name" placeholder="请输入看板名称"></el-input>
+        <el-form-item :label="t('dataReport.dashboardName')" prop="name">
+          <el-input v-model="form.model.name" :placeholder="t('dataReport.enterDashboardName')"></el-input>
         </el-form-item>
       </el-form>
     </el-main>
     <el-footer class="sa-footer--submit">
       <el-button v-if="modal.params.type == 'add'" type="primary" @click="confirm">
-        保存
+        {{ t('common.save') }}
       </el-button>
       <el-button v-if="modal.params.type == 'edit'" type="primary" @click="confirm">
-        更新
+        {{ t('common.update') }}
       </el-button>
     </el-footer>
   </el-container>
@@ -22,9 +22,13 @@
 import { cloneDeep } from 'lodash';
 import { onMounted, reactive, ref, unref } from 'vue';
 import { ElMessage } from 'element-plus';
+import { useI18n } from 'vue-i18n';
 import { useFormConfig } from '@/hooks/useFormConfig';
 import { api } from '../../data.service.js';
 
+// 使用国际化
+const { t } = useI18n();
+
 // 使用表单配置hooks
 const { formLabelWidth } = useFormConfig({ enWidth: '140px' });
 
@@ -44,8 +48,8 @@ const form = reactive({
   get rules() {
     return {
       name: [
-        { required: true, message: '请输入看板名称', trigger: 'blur' },
-        { min: 2, max: 50, message: '长度在 2 到 50 个字符', trigger: 'blur' }
+        { required: true, message: t('dataReport.enterDashboardName'), trigger: 'blur' },
+        { min: 2, max: 50, message: t('dataReport.dashboardNameLength'), trigger: 'blur' }
       ]
     };
   },
@@ -70,7 +74,7 @@ async function confirm() {
         ? await api.report.spectaculars.add(submitForm)
         : await api.report.spectaculars.update(submitForm);
     if (code == '200') {
-      ElMessage.success('保存成功');
+      ElMessage.success(t('message.saveSuccess'));
       emit('modalCallBack', { event: 'confirm' });
     }
   });

+ 109 - 42
src/app/shop/admin/data/report/components/dataDisplayEdit.vue

@@ -4,45 +4,55 @@
     <div class="filter-form">
       <el-form :model="filterForm" label-width="80px" inline>
         <!-- 时间范围 -->
-        <el-form-item label="时间范围">
-          <el-date-picker v-model="filterForm.dateRange" type="daterange" range-separator="至" start-placeholder="开始日期"
-            end-placeholder="结束日期" format="YYYY-MM-DD" value-format="YYYY-MM-DD" size="default" clearable />
+        <el-form-item :label="t('dataReport.timeRange')">
+          <el-date-picker v-model="filterForm.dateRange" type="daterange" range-separator="至"
+            :start-placeholder="t('dataReport.startDate')" :end-placeholder="t('dataReport.endDate')"
+            format="YYYY-MM-DD" value-format="YYYY-MM-DD" size="default" clearable />
         </el-form-item>
 
         <!-- 时间区间 -->
-        <el-form-item label="时间区间">
-          <el-select v-model="filterForm.timeInterval" placeholder="选择时间区间" size="default" clearable>
-            <el-option label="最近7天" :value="7" />
-            <el-option label="最近30天" :value="30" />
-            <el-option label="最近90天" :value="90" />
+        <el-form-item :label="t('dataReport.timeInterval')">
+          <el-select v-model="filterForm.timeInterval" :placeholder="t('dataReport.selectTimeInterval')" size="default"
+            clearable>
+            <el-option :label="t('dataReport.yesterday')" :value="1" />
+            <el-option :label="t('dataReport.past7Days')" :value="7" />
+            <el-option :label="t('dataReport.past14Days')" :value="14" />
+            <el-option :label="t('dataReport.past30Days')" :value="30" />
+            <el-option :label="t('dataReport.past60Days')" :value="60" />
+            <el-option :label="t('dataReport.past90Days')" :value="90" />
+            <el-option :label="t('dataReport.past180Days')" :value="180" />
+            <el-option :label="t('dataReport.past360Days')" :value="360" />
           </el-select>
         </el-form-item>
 
         <!-- 汇总周期 -->
-        <el-form-item label="汇总周期">
-          <el-select v-model="filterForm.summaryPeriod" placeholder="选择汇总周期" size="default" clearable>
-            <el-option label="按日" :value="1" />
-            <el-option label="按周" :value="2" />
-            <el-option label="按月" :value="3" />
+        <el-form-item :label="t('dataReport.summaryPeriod')">
+          <el-select v-model="filterForm.summaryPeriod" :placeholder="t('dataReport.selectSummaryPeriod')"
+            size="default" clearable>
+            <el-option :label="t('dataReport.byDay')" :value="1" />
+            <el-option :label="t('dataReport.byWeek')" :value="2" />
+            <el-option :label="t('dataReport.byMonth')" :value="3" />
+            <el-option :label="t('dataReport.byYear')" :value="4" />
           </el-select>
         </el-form-item>
 
         <!-- 颗粒度 -->
-        <el-form-item label="颗粒度">
-          <el-select v-model="filterForm.granularity" placeholder="选择颗粒度" size="default" clearable>
-            <el-option label="应用级" :value="2" />
-            <el-option label="页面级" :value="1" />
-            <el-option label="组件级" :value="3" />
+        <el-form-item :label="t('dataReport.granularity')">
+          <el-select v-model="filterForm.granularity" :placeholder="t('dataReport.selectGranularity')" size="default"
+            clearable>
+            <el-option :label="t('dataReport.applicationLevel')" :value="2" />
+            <el-option :label="t('dataReport.pageLevel')" :value="1" />
+            <el-option :label="t('dataReport.componentLevel')" :value="3" />
           </el-select>
         </el-form-item>
 
         <!-- 操作按钮 -->
         <el-form-item>
           <el-button type="primary" @click="handleSearch" :loading="chartLoading">
-            查询
+            {{ t('dataReport.query') }}
           </el-button>
           <el-button @click="handleReset">
-            重置
+            {{ t('common.reset') }}
           </el-button>
         </el-form-item>
       </el-form>
@@ -61,8 +71,13 @@
 <script setup>
 import { ref, computed, watch, onMounted } from 'vue';
 import { ElMessage } from 'element-plus';
+import { useI18n } from 'vue-i18n';
 import { api } from '../../data.service.js';
 import ReportChart from './report-chart.vue';
+import dsDetailData from '../dsDetail.json'
+
+// 使用国际化
+const { t } = useI18n();
 
 const props = defineProps({
   modal: {
@@ -76,8 +91,8 @@ const emit = defineEmits(['confirm', 'cancel']);
 // 筛选表单数据
 const filterForm = ref({
   dateRange: null, // 时间范围,默认为null
-  timeInterval: null, // 时间区间,默认为null
-  summaryPeriod: null, // 汇总周期,默认为null
+  timeInterval: 7, // 时间区间,默认过去7天
+  summaryPeriod: 1, // 汇总周期,默认按日
   granularity: null // 颗粒度,默认为null
 });
 
@@ -88,7 +103,7 @@ const chartData = ref([]);
 
 // 计算属性
 const dialogTitle = computed(() => {
-  return dimensionData.value?.name || '数据详情';
+  return dimensionData.value?.name || t('dataReport.dataDetail');
 });
 
 const iconComponent = computed(() => {
@@ -96,7 +111,7 @@ const iconComponent = computed(() => {
 });
 
 const chartTitle = computed(() => {
-  return dimensionData.value?.name || '数据分析';
+  return dimensionData.value?.name || t('dataReport.dataAnalysis');
 });
 
 
@@ -109,8 +124,8 @@ const handleSearch = () => {
 const handleReset = () => {
   filterForm.value = {
     dateRange: null,
-    timeInterval: null,
-    summaryPeriod: null,
+    timeInterval: 7, // 默认过去7天
+    summaryPeriod: 1, // 默认按日
     granularity: null
   };
   loadDimensionDetail();
@@ -120,7 +135,7 @@ const handleReset = () => {
 const handleChartTypeChange = async (newType) => {
   const dimensionId = props.modal.params.id;
   if (!dimensionId) {
-    ElMessage.error('缺少维度ID');
+    ElMessage.error(t('dataReport.missingDimensionId'));
     return;
   }
 
@@ -131,10 +146,10 @@ const handleChartTypeChange = async (newType) => {
     });
 
     chartType.value = newType;
-    ElMessage.success('图表类型更新成功');
+    ElMessage.success(t('dataReport.chartTypeUpdateSuccess'));
   } catch (error) {
     console.error('更新图表类型失败:', error);
-    ElMessage.error('更新图表类型失败');
+    ElMessage.error(t('dataReport.updateChartTypeFailed'));
   }
 };
 
@@ -146,7 +161,7 @@ const loadData = () => {
 const loadDimensionDetail = async () => {
   const dimensionId = props.modal?.params.id;
   if (!dimensionId) {
-    console.warn('缺少维度ID');
+    console.warn(t('dataReport.missingDimensionId'));
     return;
   }
 
@@ -155,38 +170,68 @@ const loadDimensionDetail = async () => {
   try {
     const params = {
       id: dimensionId,
-      timeInterval: filterForm.value.timeInterval || null,
-      type: filterForm.value.summaryPeriod || null,
+      timeInterval: filterForm.value.timeInterval || 7, // 默认月7天
+      type: filterForm.value.summaryPeriod || 1, // 默认按日
       granularity: filterForm.value.granularity || null
     };
 
-    // 添加时间范围参数
-    if (filterForm.value.dateRange && filterForm.value.dateRange.length === 2) {
+    // 根据时间区间计算起止时间
+    if (filterForm.value.timeInterval && !filterForm.value.dateRange) {
+      const { startTime, endTime } = calculateTimeRange(filterForm.value.timeInterval);
+      params.startTime = startTime;
+      params.endTime = endTime;
+    } else if (filterForm.value.dateRange && filterForm.value.dateRange.length === 2) {
+      // 优先使用手动选择的日期范围
       params.startTime = filterForm.value.dateRange[0];
       params.endTime = filterForm.value.dateRange[1];
     } else {
-      params.startTime = null;
-      params.endTime = null;
+      // 默认过去7天
+      const { startTime, endTime } = calculateTimeRange(7);
+      params.startTime = startTime;
+      params.endTime = endTime;
     }
 
+    console.log('🔍 详情查询参数:', params);
+
     const { code, data } = await api.report.dimensions.detail(params);
+    // const { code, data } = dsDetailData
 
     if (code === '200' && data) {
       dimensionData.value = data;
       processChartData(data);
       chartType.value = data.viewType || 'line';
     } else {
-      ElMessage.error('获取维度详情失败');
+      ElMessage.error(t('dataReport.getDimensionDetailFailed'));
     }
   } catch (error) {
     console.error('获取维度详情失败:', error);
-    ElMessage.error('获取维度详情失败,请重试');
+    ElMessage.error(t('dataReport.getDimensionDetailFailed'));
   } finally {
     chartLoading.value = false;
   }
 };
 
-// 处理图表数据
+// 根据时间区间计算起止时间
+const calculateTimeRange = (days) => {
+  const endDate = new Date();
+  const startDate = new Date();
+
+  if (days === 1) {
+    // 昨天
+    startDate.setDate(endDate.getDate() - 1);
+    endDate.setDate(endDate.getDate() - 1);
+  } else {
+    // 过去 N 天
+    startDate.setDate(endDate.getDate() - days);
+  }
+
+  return {
+    startTime: startDate.toISOString().split('T')[0],
+    endTime: endDate.toISOString().split('T')[0]
+  };
+};
+
+// 处理图表数据 - 与index.vue保持一致的逻辑
 const processChartData = (data) => {
   if (!data || !data.sections || data.sections.length === 0) {
     chartData.value = [];
@@ -203,14 +248,15 @@ const processChartData = (data) => {
     return;
   }
 
+  // 转换为report-chart组件期望的格式: {x, y, series}
   const result = [];
 
-  // 为每个非汇总section生成数据
+  // 为每个section生成数据点(包含汇总数据,与index.vue一致)
   data.sections.forEach(section => {
-    if (section.statistics && !section.name.includes('汇总')) {
+    if (section.statistics) {
       section.statistics.forEach(stat => {
         result.push({
-          x: stat.cutDay,
+          x: formatDateByPeriod(stat.cutDay, filterForm.value.summaryPeriod),
           y: stat.statisticsValue,
           series: section.name
         });
@@ -218,9 +264,30 @@ const processChartData = (data) => {
     }
   });
 
+  console.log('📈 详情页数据点:', result.length, '周期:', filterForm.value.summaryPeriod);
   chartData.value = result;
 };
 
+// 根据汇总周期格式化日期显示
+const formatDateByPeriod = (dateStr, period) => {
+  const date = new Date(dateStr);
+
+  switch (period) {
+    case 1: // 按日
+      return dateStr; // 保持原格式 YYYY-MM-DD
+    case 2: // 按周
+      const weekStart = new Date(date);
+      weekStart.setDate(date.getDate() - date.getDay());
+      return `${weekStart.getFullYear()}-W${Math.ceil(weekStart.getDate() / 7)}`;
+    case 3: // 按月
+      return `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, '0')}`;
+    case 4: // 按年
+      return `${date.getFullYear()}`;
+    default:
+      return dateStr;
+  }
+};
+
 
 // 组件挂载时加载数据
 onMounted(() => {

+ 35 - 40
src/app/shop/admin/data/report/components/dimension-edit-modal.vue

@@ -1,44 +1,35 @@
 <template>
   <div class="dimension-edit-modal">
     <el-form ref="formRef" :model="form" :rules="rules" label-width="120px">
-      <el-form-item label="维度名称" prop="name">
-        <el-input v-model="form.name" placeholder="请输入维度名称" />
+      <el-form-item :label="t('dataReport.dimensionName')" prop="name">
+        <el-input v-model="form.name" :placeholder="t('dataReport.enterDimensionName')" />
       </el-form-item>
-      <el-form-item label="维度编码" prop="code">
-        <el-input v-model="form.code" placeholder="请输入维度编码" />
+      <el-form-item :label="t('dataReport.dimensionCode')" prop="code">
+        <el-input v-model="form.code" :placeholder="t('dataReport.enterDimensionCode')" />
       </el-form-item>
-      <el-form-item label="维度描述" prop="memo">
-        <el-input 
-          v-model="form.memo" 
-          type="textarea" 
-          :rows="3" 
-          placeholder="请输入维度描述" 
-        />
+      <el-form-item :label="t('dataReport.dimensionDescription')" prop="memo">
+        <el-input v-model="form.memo" type="textarea" :rows="3"
+          :placeholder="t('dataReport.enterDimensionDescription')" />
       </el-form-item>
-      <el-form-item label="单位类型" prop="unitType">
-        <el-select v-model="form.unitType" placeholder="请选择单位类型" style="width: 100%">
-          <el-option label="数量" :value="0" />
-          <el-option label="金额" :value="1" />
-          <el-option label="百分比" :value="2" />
-          <el-option label="时间" :value="3" />
+      <el-form-item :label="t('dataReport.unitType')" prop="unitType">
+        <el-select v-model="form.unitType" :placeholder="t('dataReport.selectUnitType')" style="width: 100%">
+          <el-option :label="t('dataReport.quantity')" :value="0" />
+          <el-option :label="t('dataReport.amount')" :value="1" />
+          <el-option :label="t('dataReport.percentage')" :value="2" />
+          <el-option :label="t('dataReport.time')" :value="3" />
         </el-select>
       </el-form-item>
-      <el-form-item label="视图类型" prop="viewType">
-        <el-select v-model="form.viewType" placeholder="请选择视图类型" style="width: 100%">
-          <el-option label="折线图" value="line" />
-          <el-option label="柱状图" value="bar" />
-          <el-option label="饼图" value="pie" />
-          <el-option label="表格" value="table" />
+      <el-form-item :label="t('dataReport.viewType')" prop="viewType">
+        <el-select v-model="form.viewType" :placeholder="t('dataReport.selectViewType')" style="width: 100%">
+          <el-option :label="t('dataReport.lineChart')" value="line" />
+          <el-option :label="t('dataReport.barChart')" value="bar" />
+          <el-option :label="t('dataReport.pieChart')" value="pie" />
+          <el-option :label="t('dataReport.table')" value="table" />
         </el-select>
       </el-form-item>
-      <el-form-item label="状态" prop="status">
-        <el-switch 
-          v-model="form.status" 
-          :active-value="1" 
-          :inactive-value="0"
-          active-text="启用" 
-          inactive-text="禁用" 
-        />
+      <el-form-item :label="t('common.status')" prop="status">
+        <el-switch v-model="form.status" :active-value="1" :inactive-value="0" :active-text="t('common.enabled')"
+          :inactive-text="t('common.disabled')" />
       </el-form-item>
     </el-form>
   </div>
@@ -47,11 +38,15 @@
 <script setup>
 import { ref, reactive, watch } from 'vue'
 import { ElMessage } from 'element-plus'
+import { useI18n } from 'vue-i18n'
+
+// 使用国际化
+const { t } = useI18n();
 
 const props = defineProps({
   title: {
     type: String,
-    default: '编辑维度'
+    default: () => t('dataReport.editDimension')
   },
   type: {
     type: String,
@@ -78,21 +73,21 @@ const form = reactive({
 
 const rules = {
   name: [
-    { required: true, message: '请输入维度名称', trigger: 'blur' },
-    { min: 2, max: 50, message: '长度在 2 到 50 个字符', trigger: 'blur' }
+    { required: true, message: t('dataReport.enterDimensionName'), trigger: 'blur' },
+    { min: 2, max: 50, message: t('dataReport.dimensionNameLength'), trigger: 'blur' }
   ],
   code: [
-    { required: true, message: '请输入维度编码', trigger: 'blur' },
-    { pattern: /^[a-zA-Z0-9_]+$/, message: '编码只能包含字母、数字和下划线', trigger: 'blur' }
+    { required: true, message: t('dataReport.enterDimensionCode'), trigger: 'blur' },
+    { pattern: /^[a-zA-Z0-9_]+$/, message: t('dataReport.dimensionCodeFormat'), trigger: 'blur' }
   ],
   memo: [
-    { required: true, message: '请输入维度描述', trigger: 'blur' }
+    { required: true, message: t('dataReport.enterDimensionDescription'), trigger: 'blur' }
   ],
   unitType: [
-    { required: true, message: '请选择单位类型', trigger: 'change' }
+    { required: true, message: t('dataReport.selectUnitType'), trigger: 'change' }
   ],
   viewType: [
-    { required: true, message: '请选择视图类型', trigger: 'change' }
+    { required: true, message: t('dataReport.selectViewType'), trigger: 'change' }
   ]
 }
 
@@ -110,7 +105,7 @@ const handleConfirm = async () => {
     emit('confirm', { ...form })
     return true
   } catch (error) {
-    ElMessage.error('请完善表单信息')
+    ElMessage.error(t('dataReport.completeFormInfo'))
     return false
   }
 }

+ 52 - 48
src/app/shop/admin/data/report/components/dimensionManagementEdit.vue

@@ -4,15 +4,15 @@
       <template #header>
         <div class="report-header">
           <div class="header-content">
-            <h2 class="report-title">维度管理</h2>
-            <p class="report-subtitle">管理数据报表的维度配置</p>
+            <h2 class="report-title">{{ t('dataReport.dimensionManagement') }}</h2>
+            <p class="report-subtitle">{{ t('dataReport.manageDimensionConfig') }}</p>
           </div>
           <div class="header-actions">
             <el-button type="primary" @click="handleAdd" :icon="Plus">
-              新增维度
+              {{ t('dataReport.addDimension') }}
             </el-button>
             <el-button @click="refreshList" :icon="Refresh" class="sa-button-refresh">
-              刷新
+              {{ t('dataReport.refreshData') }}
             </el-button>
           </div>
         </div>
@@ -22,7 +22,7 @@
       <div class="search-section">
         <el-form :model="searchForm" inline class="search-form">
           <el-form-item>
-            <el-input v-model="searchForm.keyword" placeholder="请输入维度名称或编码" clearable
+            <el-input v-model="searchForm.keyword" :placeholder="t('dataReport.enterDimensionNameOrCode')" clearable
               @keyup.enter="handleSearch" class="search-input">
               <template #prefix>
                 <el-icon>
@@ -33,10 +33,10 @@
           </el-form-item>
           <el-form-item>
             <el-button type="primary" @click="handleSearch" :icon="Search">
-              搜索
+              {{ t('common.search') }}
             </el-button>
             <el-button @click="handleReset" :icon="RefreshLeft">
-              重置
+              {{ t('common.reset') }}
             </el-button>
           </el-form-item>
         </el-form>
@@ -48,7 +48,7 @@
           @selection-change="handleSelectionChange">
           <el-table-column type="selection" width="55" />
           <el-table-column prop="id" label="ID" width="80" />
-          <el-table-column prop="name" label="维度名称" min-width="150">
+          <el-table-column prop="name" :label="t('dataReport.dimensionName')" min-width="150">
             <template #default="{ row }">
               <div class="dimension-name">
                 <el-tag :type="getDimensionTypeTag(row.type)" size="small" style="margin-right: 8px;">
@@ -58,40 +58,40 @@
               </div>
             </template>
           </el-table-column>
-          <el-table-column prop="code" label="维度编码" width="120" />
-          <el-table-column prop="description" label="描述" min-width="200" show-overflow-tooltip />
-          <el-table-column prop="dataType" label="数据类型" width="100">
+          <el-table-column prop="code" :label="t('dataReport.dimensionCode')" width="120" />
+          <el-table-column prop="description" :label="t('form.description')" min-width="200" show-overflow-tooltip />
+          <el-table-column prop="dataType" :label="t('dataReport.dataType')" width="100">
             <template #default="{ row }">
               <el-tag size="small" :type="getDataTypeTag(row.dataType)">
                 {{ getDataTypeLabel(row.dataType) }}
               </el-tag>
             </template>
           </el-table-column>
-          <el-table-column prop="unit" label="单位" width="80" />
-          <el-table-column prop="status" label="状态" width="80">
+          <el-table-column prop="unit" :label="t('dataReport.unit')" width="80" />
+          <el-table-column prop="status" :label="t('common.status')" width="80">
             <template #default="{ row }">
               <el-switch v-model="row.status" :active-value="1" :inactive-value="0" @change="handleStatusChange(row)" />
             </template>
           </el-table-column>
-          <el-table-column prop="createTime" label="创建时间" width="160">
+          <el-table-column prop="createTime" :label="t('form.createTime')" width="160">
             <template #default="{ row }">
               {{ formatDate(row.createTime) }}
             </template>
           </el-table-column>
-          <el-table-column label="操作" width="180" fixed="right">
+          <el-table-column :label="t('common.operation')" width="180" fixed="right">
             <template #default="{ row }">
               <el-button size="small" type="primary" link @click="handleEdit(row)">
                 <el-icon>
                   <Edit />
                 </el-icon>
-                编辑
+                {{ t('common.edit') }}
               </el-button>
 
               <el-button size="small" type="danger" link @click="handleDelete(row)">
                 <el-icon>
                   <Delete />
                 </el-icon>
-                删除
+                {{ t('common.delete') }}
               </el-button>
             </template>
           </el-table-column>
@@ -100,17 +100,17 @@
         <!-- 批量操作 -->
         <div class="batch-actions" v-if="selectedRows.length > 0">
           <span class="batch-info">
-            已选择 {{ selectedRows.length }}
+            {{ t('dataReport.selectedItems', { count: selectedRows.length }) }}
           </span>
           <div class="batch-buttons">
             <el-button type="danger" size="small" @click="handleBatchDelete">
-              批量删除
+              {{ t('dataReport.batchDelete') }}
             </el-button>
             <el-button type="success" size="small" @click="handleBatchEnable">
-              批量启用
+              {{ t('dataReport.batchEnable') }}
             </el-button>
             <el-button type="warning" size="small" @click="handleBatchDisable">
-              批量禁用
+              {{ t('dataReport.batchDisable') }}
             </el-button>
           </div>
         </div>
@@ -135,9 +135,13 @@ import {
   Plus, Refresh, Search, RefreshLeft, Edit, Delete,
   Check, Close
 } from '@element-plus/icons-vue'
+import { useI18n } from 'vue-i18n'
 import { api } from '../../data.service.js'
 import { useModal } from '@/sheep/components/sa-modal/sa-modal.vue'
 
+// 使用国际化
+const { t } = useI18n();
+
 // 响应式数据
 const loading = ref(false)
 const selectedRows = ref([])
@@ -220,7 +224,7 @@ const handleAdd = () => {
     width: '600px',
     height: '500px',
     componentProps: {
-      title: '新增维度',
+      title: t('dataReport.addDimension'),
       type: 'add',
       dimensionData: {}
     },
@@ -228,7 +232,7 @@ const handleAdd = () => {
       const result = await modalRef.handleConfirm()
       if (result) {
         await api.report.dimensions.add(modalRef.form)
-        ElMessage.success('新增成功')
+        ElMessage.success(t('message.createSuccess'))
         loadData()
         return true
       }
@@ -243,7 +247,7 @@ const handleEdit = (row) => {
     width: '600px',
     height: '500px',
     componentProps: {
-      title: '编辑维度',
+      title: t('dataReport.editDimension'),
       type: 'edit',
       dimensionData: row
     },
@@ -251,7 +255,7 @@ const handleEdit = (row) => {
       const result = await modalRef.handleConfirm()
       if (result) {
         await api.report.dimensions.update(modalRef.form)
-        ElMessage.success('编辑成功')
+        ElMessage.success(t('message.updateSuccess'))
         loadData()
         return true
       }
@@ -265,26 +269,26 @@ const handleEdit = (row) => {
 const handleDelete = async (row) => {
   try {
     await ElMessageBox.confirm(
-      `确定要删除维度 "${row.name}" 吗?`,
-      '删除确认',
+      t('dataReport.confirmDeleteDimension', { name: row.name }),
+      t('dataReport.deleteConfirmation'),
       {
-        confirmButtonText: '确定',
-        cancelButtonText: '取消',
+        confirmButtonText: t('common.confirm'),
+        cancelButtonText: t('common.cancel'),
         type: 'warning'
       }
     )
 
     const response = await api.report.dimensions.delete(row.id)
     if (response.code === 200) {
-      ElMessage.success('删除成功')
+      ElMessage.success(t('message.deleteSuccess'))
       loadData()
     } else {
-      ElMessage.error(response.message || '删除失败')
+      ElMessage.error(response.message || t('message.deleteFailed'))
     }
   } catch (error) {
     if (error !== 'cancel') {
       console.error('删除维度失败:', error)
-      ElMessage.error('删除失败')
+      ElMessage.error(t('message.deleteFailed'))
     }
   }
 }
@@ -295,15 +299,15 @@ const handleStatusChange = async (row) => {
       status: row.status
     })
     if (response.code === 200) {
-      ElMessage.success('状态更新成功')
+      ElMessage.success(t('dataReport.statusUpdateSuccess'))
     } else {
-      ElMessage.error(response.message || '状态更新失败')
+      ElMessage.error(response.message || t('dataReport.statusUpdateFailed'))
       // 回滚状态
       row.status = row.status === 1 ? 0 : 1
     }
   } catch (error) {
     console.error('更新状态失败:', error)
-    ElMessage.error('状态更新失败')
+    ElMessage.error(t('dataReport.statusUpdateFailed'))
     // 回滚状态
     row.status = row.status === 1 ? 0 : 1
   }
@@ -332,64 +336,64 @@ const handleSelectionChange = (selection) => {
 
 const handleBatchDelete = async () => {
   if (selectedRows.value.length === 0) {
-    ElMessage.warning('请选择要删除的项目')
+    ElMessage.warning($t('dataReport.selectItemsToDelete'))
     return
   }
 
   try {
     await ElMessageBox.confirm(
-      `确定要批量删除 ${selectedRows.value.length} 个项目吗?`,
-      '批量删除确认',
+      $t('dataReport.confirmBatchDelete', { count: selectedRows.value.length }),
+      $t('dataReport.batchDeleteConfirmation'),
       {
-        confirmButtonText: '确定',
-        cancelButtonText: '取消',
+        confirmButtonText: t('common.confirm'),
+        cancelButtonText: t('common.cancel'),
         type: 'warning'
       }
     )
 
     const ids = selectedRows.value.map(row => row.id)
     // 这里应该调用批量删除API
-    ElMessage.success('批量删除成功')
+    ElMessage.success($t('dataReport.batchDeleteSuccess'))
     loadData()
   } catch (error) {
     if (error !== 'cancel') {
       console.error('批量删除失败:', error)
-      ElMessage.error('批量删除失败')
+      ElMessage.error($t('dataReport.batchDeleteFailed'))
     }
   }
 }
 
 const handleBatchEnable = async () => {
   if (selectedRows.value.length === 0) {
-    ElMessage.warning('请选择要启用的项目')
+    ElMessage.warning($t('dataReport.selectItemsToEnable'))
     return
   }
 
   try {
     const ids = selectedRows.value.map(row => row.id)
     // 这里应该调用批量更新API
-    ElMessage.success('批量启用成功')
+    ElMessage.success($t('dataReport.batchEnableSuccess'))
     loadData()
   } catch (error) {
     console.error('批量启用失败:', error)
-    ElMessage.error('批量启用失败')
+    ElMessage.error($t('dataReport.batchEnableFailed'))
   }
 }
 
 const handleBatchDisable = async () => {
   if (selectedRows.value.length === 0) {
-    ElMessage.warning('请选择要禁用的项目')
+    ElMessage.warning($t('dataReport.selectItemsToDisable'))
     return
   }
 
   try {
     const ids = selectedRows.value.map(row => row.id)
     // 这里应该调用批量更新API
-    ElMessage.success('批量禁用成功')
+    ElMessage.success($t('dataReport.batchDisableSuccess'))
     loadData()
   } catch (error) {
     console.error('批量禁用失败:', error)
-    ElMessage.error('批量禁用失败')
+    ElMessage.error($t('dataReport.batchDisableFailed'))
   }
 }
 

+ 20 - 13
src/app/shop/admin/data/report/components/report-chart.vue

@@ -4,7 +4,7 @@
       <template #header>
         <div class="chart-header">
           <div class="chart-title-section">
-            <h3 class="chart-title">{{ title || '默认图表' }}</h3>
+            <h3 class="chart-title">{{ title || t('dataReport.defaultChart') }}</h3>
             <p class="chart-subtitle" v-if="subtitle">{{ subtitle }}</p>
           </div>
           <div class="chart-actions mt-20px justify-between flex">
@@ -12,14 +12,15 @@
             <el-radio-group v-model="currentType" size="small" @change="handleTypeChange" class="chart-type-selector">
               <el-radio-button v-for="type in availableTypes" :key="type.value" :label="type.value"
                 :disabled="!type.enabled">
-                {{ type.label }}
+                {{ t(`dataReport.${type.labelKey}`) }}
               </el-radio-button>
             </el-radio-group>
 
             <div class="chart-controls">
               <!-- 时间范围选择 -->
               <el-date-picker v-if="showDatePicker" v-model="dateRange" type="daterange" range-separator="至"
-                start-placeholder="开始日期" end-placeholder="结束日期" size="small" @change="handleDateChange" />
+                :start-placeholder="t('dataReport.startDate')" :end-placeholder="t('dataReport.endDate')" size="small"
+                @change="handleDateChange" />
 
               <!-- 刷新按钮 -->
               <el-button size="small" @click="refreshChart" class="sa-button-refresh">
@@ -43,14 +44,14 @@
         <!-- 全屏状态下的控制栏 -->
         <div v-if="isFullscreen" class="fullscreen-header">
           <div class="chart-title-section">
-            <h3 class="chart-title">{{ title || '默认图表' }}</h3>
+            <h3 class="chart-title">{{ title || t('dataReport.defaultChart') }}</h3>
           </div>
           <div class="chart-controls">
             <!-- 图表类型切换 -->
             <el-radio-group v-model="currentType" size="small" @change="handleTypeChange" class="chart-type-selector">
               <el-radio-button v-for="type in availableTypes" :key="type.value" :label="type.value"
                 :disabled="!type.enabled">
-                {{ type.label }}
+                {{ t(`dataReport.${type.labelKey}`) }}
               </el-radio-button>
             </el-radio-group>
 
@@ -59,7 +60,7 @@
               <el-icon>
                 <FullScreen />
               </el-icon>
-              退出全屏
+              {{ t('dataReport.exitFullscreen') }}
             </el-button>
           </div>
         </div>
@@ -80,7 +81,9 @@
                 </div>
               </template>
               <template #description>
-                <span class="empty-description">{{ title || '图表' }}暂无数据</span>
+                <span class="empty-description">{{ t('dataReport.chartPlaceholder', {
+                  title: title ||
+                    t('dataReport.chart') }) }}</span>
               </template>
             </el-empty>
           </div>
@@ -104,10 +107,14 @@
 import { ref, computed, watch, onMounted, onUnmounted, nextTick } from 'vue'
 import { ElMessage } from 'element-plus'
 import { Refresh, FullScreen } from '@element-plus/icons-vue'
+import { useI18n } from 'vue-i18n'
 import VChart from 'vue-echarts'
 import * as echarts from 'echarts'
 import ChartTipsBox from './chart-tips-box.vue'
 
+// 使用国际化
+const { t } = useI18n();
+
 // Props
 const props = defineProps({
   title: {
@@ -183,12 +190,12 @@ const tipsBoxData = ref({
 
 // 可用的图表类型
 const availableTypes = computed(() => [
-  { label: '折线图', value: 'line', enabled: true },
-  { label: '柱状图', value: 'bar', enabled: true },
-  { label: '饼图', value: 'pie', enabled: true },
-  // { label: '散点图', value: 'scatter', enabled: true },
-  // { label: '雷达图', value: 'radar', enabled: false },
-  // { label: '漏斗图', value: 'funnel', enabled: false }
+  { label: '折线图', labelKey: 'lineChart', value: 'line', enabled: true },
+  { label: '柱状图', labelKey: 'barChart', value: 'bar', enabled: true },
+  { label: '饼图', labelKey: 'pieChart', value: 'pie', enabled: true },
+  // { label: '散点图', labelKey: 'scatterChart', value: 'scatter', enabled: true },
+  // { label: '雷达图', labelKey: 'radarChart', value: 'radar', enabled: false },
+  // { label: '漏斗图', labelKey: 'funnelChart', value: 'funnel', enabled: false }
 ])
 
 // 计算属性

文件差异内容过多而无法显示
+ 896 - 86
src/app/shop/admin/data/report/dsDetail.json


+ 46 - 46
src/app/shop/admin/data/report/index.vue

@@ -11,20 +11,20 @@
               <el-icon>
                 <Grid />
               </el-icon>
-              看板列表
+              {{ t('dataReport.dashboardList') }}
             </h2>
             <div class="section-actions">
               <el-button type="primary" @click="addDashboard">
                 <el-icon>
                   <Plus />
                 </el-icon>
-                新增看板
+                {{ t('dataReport.addDashboard') }}
               </el-button>
               <el-button type="primary" @click="addChart">
                 <el-icon>
                   <Plus />
                 </el-icon>
-                新增图表
+                {{ t('dataReport.addChart') }}
               </el-button>
             </div>
           </div>
@@ -57,7 +57,7 @@
             </div>
             <div v-if="!dashboardList.length" class="empty-state">
               <div class="empty-icon">📋</div>
-              <div class="empty-text">暂无看板数据</div>
+              <div class="empty-text">{{ t('dataReport.noDashboardData') }}</div>
             </div>
           </div>
         </div>
@@ -72,14 +72,14 @@
             <el-icon>
               <TrendCharts />
             </el-icon>
-            {{ selectedDashboard ? selectedDashboard.name : '数据图表' }}
+            {{ selectedDashboard ? selectedDashboard.name : t('dataReport.dataChart') }}
           </h2>
           <div class="section-actions">
             <el-button @click="refreshChartData" :loading="loading" size="small">
               <el-icon>
                 <Refresh />
               </el-icon>
-              刷新数据
+              {{ t('dataReport.refreshData') }}
             </el-button>
 
           </div>
@@ -94,30 +94,31 @@
                   <el-icon>
                     <View />
                   </el-icon>
-                  查看详情
+                  {{ t('dataReport.viewDetail') }}
                 </el-button>
                 <el-button text size="small" @click="deleteChart(chart)" type="danger">
                   <el-icon>
                     <Delete />
                   </el-icon>
-                  删除
+                  {{ t('dataReport.deleteChart') }}
                 </el-button>
                 <el-button text size="small" @click="downloadChart(chart)" :loading="exportLoading"
                   :disabled="exportLoading">
                   <el-icon>
                     <TrendCharts />
                   </el-icon>
-                  {{ exportLoading ? '导出中' : '导出图表' }}
+                  {{ exportLoading ? t('dataReport.exporting') : t('dataReport.exportChart') }}
                 </el-button>
               </div>
             </div>
             <div class="chart-content">
               <reportChart :title="chart.name" :data="transformChartData(chart)" :type="chart.viewType || 'line'"
-                :height="400" :show-date-picker="false" :x-axis-key="'x'" :y-axis-key="'y'" :series-key="'series'"
+                :height="350" :show-date-picker="false" :x-axis-key="'x'" :y-axis-key="'y'" :series-key="'series'"
                 :colors="legendColors" @chart-click="handleChartClick" />
             </div>
             <div class="chart-footer">
-              <span class="update-time">更新时间:{{ chart.updateTime || '暂无' }}</span>
+              <span class="update-time">{{ t('dataReport.updateTime') }}:{{ chart.updateTime ||
+                t('dataReport.noUpdateTime') }}</span>
             </div>
           </div>
 
@@ -135,6 +136,7 @@
 import { onMounted, reactive, ref, computed } from 'vue';
 import { ElMessage, ElMessageBox } from 'element-plus';
 import { Plus, Grid, View, Edit, Delete, TrendCharts, Refresh } from '@element-plus/icons-vue';
+import { useI18n } from 'vue-i18n';
 import { useModal } from '@/sheep/hooks';
 import { api } from '../data.service.js';
 
@@ -144,6 +146,9 @@ import chartEdit from './components/chartEdit.vue';
 import reportChart from './components/report-chart.vue';
 import detailData from './detail.json';
 
+// 使用国际化
+const { t } = useI18n();
+
 // 响应式数据
 const loading = ref(false);
 const dashboardLoading = ref(false);
@@ -183,12 +188,12 @@ async function getDashboardList() {
         await getChartData(dashboardList.value[0].id);
       }
     } else {
-      ElMessage.error('获取看板列表失败');
+      ElMessage.error(t('dataReport.getDashboardListFailed'));
       dashboardList.value = [];
     }
   } catch (error) {
     console.error('获取看板列表失败:', error);
-    ElMessage.error('获取看板列表失败,请重试');
+    ElMessage.error(t('dataReport.getDashboardListFailed'));
     dashboardList.value = [];
   } finally {
     dashboardLoading.value = false;
@@ -201,18 +206,13 @@ async function getChartData(dashboardId) {
 
   loading.value = true;
   try {
-    const { code, data } = detailData
-    console.log('📊 图表数据:', {
-      dashboardId,
-      dimensionsCount: data?.dimensions?.length || 0
-    })
-
-    // const { code, data } = await api.report.spectaculars.detail({
-    //   id: dashboardId,
-    //   startTime: '', // 可以根据实际需要设置时间范围
-    //   endTime: '',
-    //   timeInterval: 7
-    // });
+    // const { code, data } = detailData
+    const { code, data } = await api.report.spectaculars.detail({
+      id: dashboardId,
+      startTime: '', // 可以根据实际需要设置时间范围
+      endTime: '',
+      timeInterval: 7
+    });
     if (code == 200) {
       // 更新当前看板的图表数据
       const newCharts = Array.isArray(data) ? data : [data];
@@ -223,11 +223,11 @@ async function getChartData(dashboardId) {
       // 处理维度数据用于图表显示
       processChartData(data);
     } else {
-      ElMessage.error('获取图表数据失败');
+      ElMessage.error(t('dataReport.getChartDataFailed'));
     }
   } catch (error) {
     console.error('获取图表数据失败:', error);
-    ElMessage.error('获取图表数据失败,请重试');
+    ElMessage.error(t('dataReport.getChartDataFailed'));
   } finally {
     loading.value = false;
   }
@@ -312,23 +312,23 @@ function handleChartClick(params) {
 
 // 删除看板
 function deleteDashboard(dashboard) {
-  ElMessageBox.confirm(`确定要删除看板 "${dashboard.name}" 吗?`, '提示', {
-    confirmButtonText: '确定',
-    cancelButtonText: '取消',
+  ElMessageBox.confirm(t('dataReport.confirmDeleteDashboard', { name: dashboard.name }), t('common.tip'), {
+    confirmButtonText: t('common.confirm'),
+    cancelButtonText: t('common.cancel'),
     type: 'warning'
   }).then(async () => {
     try {
       // 调用删除API
       const { code } = await api.report.spectaculars.delete(dashboard.id);
       if (code == 200) {
-        ElMessage.success('看板删除成功');
+        ElMessage.success(t('dataReport.dashboardDeleteSuccess'));
         getDashboardList();
       } else {
-        ElMessage.error('删除看板失败');
+        ElMessage.error(t('dataReport.dashboardDeleteFailed'));
       }
     } catch (error) {
       console.error('删除看板失败:', error);
-      ElMessage.error('删除看板失败,请重试');
+      ElMessage.error(t('dataReport.dashboardDeleteFailed'));
     }
   }).catch(() => {
     // 取消删除
@@ -339,18 +339,18 @@ function deleteDashboard(dashboard) {
 // 删除图表
 function deleteChart(chart) {
   ElMessageBox.confirm(
-    `确定要删除图表 "${chart.name}" 吗?`,
-    '删除确认',
+    t('dataReport.confirmDeleteChart', { name: chart.name }),
+    t('dataReport.deleteChart'),
     {
-      confirmButtonText: '确定',
-      cancelButtonText: '取消',
+      confirmButtonText: t('common.confirm'),
+      cancelButtonText: t('common.cancel'),
       type: 'warning',
     }
   ).then(async () => {
     try {
       const { code } = await api.report.dimensions.delete(chart.spectacularsDimensionId);
       if (code == 200) {
-        ElMessage.success('图表删除成功');
+        ElMessage.success(t('dataReport.chartDeleteSuccess'));
         refreshChartData()
       }
     } catch (error) {
@@ -387,7 +387,7 @@ function showChartDetail(options) {
   useModal(
     dataDisplayEdit,
     {
-      title: `${options.chart?.name || options.dataType || '数据'} - 数据详情`,
+      title: `${options.chart?.name || options.dataType || t('dataReport.dataDetail')} - ${t('dataReport.dataDetail')}`,
       width: '90%',
       height: '80vh',
       id: options.spectacularsDimensionId,
@@ -404,7 +404,7 @@ function showChartDetail(options) {
 function addDashboard() {
   useModal(
     dashboardEdit,
-    { title: '新增看板', type: 'add', width: '500px' },
+    { title: t('dataReport.addDashboard'), type: 'add', width: '500px' },
     {
       confirm: () => {
         getDashboardList();
@@ -418,7 +418,7 @@ function editDashboard(row) {
   useModal(
     dashboardEdit,
     {
-      title: '编辑看板',
+      title: t('dataReport.editDashboard'),
       type: 'edit',
       width: '500px',
       id: row.id,
@@ -437,14 +437,14 @@ function editDashboard(row) {
 // 新增图表
 function addChart() {
   if (!selectedDashboard.value) {
-    ElMessage.warning('请先选择一个看板');
+    ElMessage.warning(t('dataReport.pleaseSelectDashboard'));
     return;
   }
 
   useModal(
     chartEdit,
     {
-      title: '新增图表',
+      title: t('dataReport.addChart'),
       type: 'add',
       spectId: selectedDashboard.value?.id
     },
@@ -461,7 +461,7 @@ function editChart(row) {
   useModal(
     chartEdit,
     {
-      title: '编辑图表',
+      title: t('dataReport.editChart'),
       type: 'edit',
       id: row.id,
       chartData: row,
@@ -708,8 +708,8 @@ onMounted(() => {
   padding: 16px;
   border: 1px solid #e4e7ed;
   transition: all 0.3s;
-  min-width: 1000px;
-  min-height: 500px;
+  min-width: 370px;
+  min-height: 400px;
   margin: 10px;
   display: flex;
   flex-direction: column;

+ 1 - 0
src/app/shop/admin/marketing/group/edit.vue

@@ -21,6 +21,7 @@
         <el-form-item :label="t('modules.marketing.defaultGroupSize')" prop="content.groupNumber">
           <el-select v-model="form.model.content.groupNumber" :placeholder="t('modules.marketing.selectGroupSize')"
             style="width: 100%">
+            <el-option :label="t('modules.marketing.twoPersonGroup')" :value="2"></el-option>
             <el-option :label="t('modules.marketing.fivePersonGroup')" :value="5"></el-option>
             <el-option :label="t('modules.marketing.tenPersonGroup')" :value="10"></el-option>
             <el-option :label="t('modules.marketing.twentyPersonGroup')" :value="20"></el-option>

+ 130 - 0
src/locales/en-US/index.json

@@ -111,6 +111,134 @@
     "sort": "Sort",
     "enterSort": "Please enter sort"
   },
+  "dataReport": {
+    "dashboard": "Dashboard",
+    "dashboardList": "Dashboard List",
+    "addDashboard": "Add Dashboard",
+    "editDashboard": "Edit Dashboard",
+    "deleteDashboard": "Delete Dashboard",
+    "confirmDeleteDashboard": "Are you sure you want to delete dashboard \"{name}\"?",
+    "dashboardDeleteSuccess": "Dashboard deleted successfully",
+    "dashboardDeleteFailed": "Failed to delete dashboard",
+    "getDashboardListFailed": "Failed to get dashboard list",
+    "chart": "Chart",
+    "addChart": "Add Chart",
+    "editChart": "Edit Chart",
+    "deleteChart": "Delete Chart",
+    "confirmDeleteChart": "Are you sure you want to delete chart \"{name}\"?",
+    "chartDeleteSuccess": "Chart deleted successfully",
+    "chartDeleteFailed": "Failed to delete chart",
+    "dataChart": "Data Chart",
+    "refreshData": "Refresh Data",
+    "viewDetail": "View Detail",
+    "exportChart": "Export Chart",
+    "exporting": "Exporting",
+    "updateTime": "Update Time",
+    "noUpdateTime": "No Update Time",
+    "noDashboardData": "No dashboard data",
+    "getChartDataFailed": "Failed to get chart data",
+    "dataDetail": "Data Detail",
+    "dataAnalysis": "Data Analysis",
+    "timeRange": "Time Range",
+    "timeInterval": "Time Interval",
+    "summaryPeriod": "Summary Period",
+    "granularity": "Granularity",
+    "selectTimeInterval": "Select time interval",
+    "selectSummaryPeriod": "Select summary period",
+    "selectGranularity": "Select granularity",
+    "yesterday": "Yesterday",
+    "past7Days": "Past 7 days",
+    "past14Days": "Past 14 days",
+    "past30Days": "Past 30 days",
+    "past60Days": "Past 60 days",
+    "past90Days": "Past 90 days",
+    "past180Days": "Past 180 days",
+    "past360Days": "Past 360 days",
+    "byDay": "By Day",
+    "byWeek": "By Week",
+    "byMonth": "By Month",
+    "byYear": "By Year",
+    "applicationLevel": "Application Level",
+    "pageLevel": "Page Level",
+    "componentLevel": "Component Level",
+    "query": "Query",
+    "getDimensionDetailFailed": "Failed to get dimension detail",
+    "missingDimensionId": "Missing dimension ID",
+    "chartTypeUpdateSuccess": "Chart type updated successfully",
+    "updateChartTypeFailed": "Failed to update chart type",
+    "lineChart": "Line Chart",
+    "barChart": "Bar Chart",
+    "pieChart": "Pie Chart",
+    "scatterChart": "Scatter Chart",
+    "radarChart": "Radar Chart",
+    "funnelChart": "Funnel Chart",
+    "noData": "No Data",
+    "chartPlaceholder": "{title} has no data",
+    "pleaseSelectDashboard": "Please select a dashboard first",
+    "startDate": "Start Date",
+    "endDate": "End Date",
+    "selectDataDimension": "Select Data Dimension",
+    "searchChartName": "Search chart name",
+    "noMatchingCharts": "No matching charts found",
+    "noChartsAvailable": "No charts available",
+    "selectLeftDataDimension": "Please select left data dimension for preview",
+    "selectToShowPreview": "Chart preview will be displayed after selection",
+    "confirmAdd": "Confirm Add",
+    "missingDashboardId": "Missing dashboard ID parameter",
+    "getChartListFailed": "Failed to get chart list",
+    "selectAtLeastOneChart": "Please select at least one chart",
+    "addChartsSuccess": "Successfully added {count} charts",
+    "addChartsFailed": "Failed to add charts",
+    "dashboardName": "Dashboard Name",
+    "enterDashboardName": "Please enter dashboard name",
+    "dashboardNameLength": "Length should be between 2 to 50 characters",
+    "defaultChart": "Default Chart",
+    "exitFullscreen": "Exit Fullscreen",
+    "dimensionName": "Dimension Name",
+    "enterDimensionName": "Please enter dimension name",
+    "dimensionCode": "Dimension Code",
+    "enterDimensionCode": "Please enter dimension code",
+    "dimensionDescription": "Dimension Description",
+    "enterDimensionDescription": "Please enter dimension description",
+    "unitType": "Unit Type",
+    "selectUnitType": "Please select unit type",
+    "quantity": "Quantity",
+    "amount": "Amount",
+    "percentage": "Percentage",
+    "time": "Time",
+    "viewType": "View Type",
+    "selectViewType": "Please select view type",
+    "table": "Table",
+    "editDimension": "Edit Dimension",
+    "dimensionNameLength": "Length should be between 2 to 50 characters",
+    "dimensionCodeFormat": "Code can only contain letters, numbers and underscores",
+    "completeFormInfo": "Please complete form information",
+    "dimensionManagement": "Dimension Management",
+    "manageDimensionConfig": "Manage data report dimension configuration",
+    "addDimension": "Add Dimension",
+    "enterDimensionNameOrCode": "Please enter dimension name or code",
+    "dataType": "Data Type",
+    "unit": "Unit",
+    "selectedItems": "Selected {count} items",
+    "batchDelete": "Batch Delete",
+    "batchEnable": "Batch Enable",
+    "batchDisable": "Batch Disable",
+    "confirmDeleteDimension": "Are you sure you want to delete dimension \"{name}\"?",
+    "deleteConfirmation": "Delete Confirmation",
+    "statusUpdateSuccess": "Status updated successfully",
+    "statusUpdateFailed": "Status update failed",
+    "selectItemsToDelete": "Please select items to delete",
+    "confirmBatchDelete": "Are you sure you want to batch delete {count} items?",
+    "batchDeleteConfirmation": "Batch Delete Confirmation",
+    "batchDeleteSuccess": "Batch delete successful",
+    "batchDeleteFailed": "Batch delete failed",
+    "selectItemsToEnable": "Please select items to enable",
+    "batchEnableSuccess": "Batch enable successful",
+    "batchEnableFailed": "Batch enable failed",
+    "selectItemsToDisable": "Please select items to disable",
+    "batchDisableSuccess": "Batch disable successful",
+    "batchDisableFailed": "Batch disable failed"
+  },
   "menu": {
     "dashboard": "Dashboard",
     "goods": "Goods",
@@ -147,6 +275,7 @@
     "bannerAd": "Banner",
     "data": "Data",
     "dataReport": "Reports",
+    "dataReport": "Data Reports",
     "finance": "Finance",
     "recharge": "Recharge",
     "withdraw": "Withdraw",
@@ -1436,6 +1565,7 @@
       "selectStartTime": "Select start time",
       "selectEndTime": "Select end time",
       "selectGroupSize": "Select group size",
+      "twoPersonGroup": "2 Person Group",
       "fivePersonGroup": "5 Person Group",
       "tenPersonGroup": "10 Person Group",
       "twentyPersonGroup": "20 Person Group",

+ 130 - 0
src/locales/zh-CN/index.json

@@ -111,6 +111,134 @@
     "sort": "排序",
     "enterSort": "请填写排序"
   },
+  "dataReport": {
+    "dashboard": "看板",
+    "dashboardList": "看板列表",
+    "addDashboard": "新增看板",
+    "editDashboard": "编辑看板",
+    "deleteDashboard": "删除看板",
+    "confirmDeleteDashboard": "确定要删除看板 \"{name}\" 吗?",
+    "dashboardDeleteSuccess": "看板删除成功",
+    "dashboardDeleteFailed": "删除看板失败",
+    "getDashboardListFailed": "获取看板列表失败",
+    "chart": "图表",
+    "addChart": "新增图表",
+    "editChart": "编辑图表",
+    "deleteChart": "删除图表",
+    "confirmDeleteChart": "确定要删除图表 \"{name}\" 吗?",
+    "chartDeleteSuccess": "图表删除成功",
+    "chartDeleteFailed": "删除图表失败",
+    "dataChart": "数据图表",
+    "refreshData": "刷新数据",
+    "viewDetail": "查看详情",
+    "exportChart": "导出图表",
+    "exporting": "导出中",
+    "updateTime": "更新时间",
+    "noUpdateTime": "暂无",
+    "noDashboardData": "暂无看板数据",
+    "getChartDataFailed": "获取图表数据失败",
+    "dataDetail": "数据详情",
+    "dataAnalysis": "数据分析",
+    "timeRange": "时间范围",
+    "timeInterval": "时间区间",
+    "summaryPeriod": "汇总周期",
+    "granularity": "颗粒度",
+    "selectTimeInterval": "选择时间区间",
+    "selectSummaryPeriod": "选择汇总周期",
+    "selectGranularity": "选择颗粒度",
+    "yesterday": "昨天",
+    "past7Days": "过去7天",
+    "past14Days": "过去14天",
+    "past30Days": "过去30天",
+    "past60Days": "过去60天",
+    "past90Days": "过去90天",
+    "past180Days": "过去180天",
+    "past360Days": "过去360天",
+    "byDay": "按日",
+    "byWeek": "按周",
+    "byMonth": "按月",
+    "byYear": "按年",
+    "applicationLevel": "应用级",
+    "pageLevel": "页面级",
+    "componentLevel": "组件级",
+    "query": "查询",
+    "getDimensionDetailFailed": "获取维度详情失败",
+    "missingDimensionId": "缺少维度ID",
+    "chartTypeUpdateSuccess": "图表类型更新成功",
+    "updateChartTypeFailed": "更新图表类型失败",
+    "lineChart": "折线图",
+    "barChart": "柱状图",
+    "pieChart": "饼图",
+    "scatterChart": "散点图",
+    "radarChart": "雷达图",
+    "funnelChart": "漏斗图",
+    "noData": "暂无数据",
+    "chartPlaceholder": "{title}暂无数据",
+    "pleaseSelectDashboard": "请先选择一个看板",
+    "startDate": "开始日期",
+    "endDate": "结束日期",
+    "selectDataDimension": "选择数据维度",
+    "searchChartName": "搜索图表名称",
+    "noMatchingCharts": "未找到匹配的图表",
+    "noChartsAvailable": "暂无可选图表",
+    "selectLeftDataDimension": "请选择左侧数据维度进行预览",
+    "selectToShowPreview": "选择后将显示对应的图表预览效果",
+    "confirmAdd": "确认添加",
+    "missingDashboardId": "缺少看板ID参数",
+    "getChartListFailed": "获取图表列表失败",
+    "selectAtLeastOneChart": "请选择至少一个图表",
+    "addChartsSuccess": "成功添加{count}个图表",
+    "addChartsFailed": "添加图表失败",
+    "dashboardName": "看板名称",
+    "enterDashboardName": "请输入看板名称",
+    "dashboardNameLength": "长度在 2 到 50 个字符",
+    "defaultChart": "默认图表",
+    "exitFullscreen": "退出全屏",
+    "dimensionName": "维度名称",
+    "enterDimensionName": "请输入维度名称",
+    "dimensionCode": "维度编码",
+    "enterDimensionCode": "请输入维度编码",
+    "dimensionDescription": "维度描述",
+    "enterDimensionDescription": "请输入维度描述",
+    "unitType": "单位类型",
+    "selectUnitType": "请选择单位类型",
+    "quantity": "数量",
+    "amount": "金额",
+    "percentage": "百分比",
+    "time": "时间",
+    "viewType": "视图类型",
+    "selectViewType": "请选择视图类型",
+    "table": "表格",
+    "editDimension": "编辑维度",
+    "dimensionNameLength": "长度在 2 到 50 个字符",
+    "dimensionCodeFormat": "编码只能包含字母、数字和下划线",
+    "completeFormInfo": "请完善表单信息",
+    "dimensionManagement": "维度管理",
+    "manageDimensionConfig": "管理数据报表的维度配置",
+    "addDimension": "新增维度",
+    "enterDimensionNameOrCode": "请输入维度名称或编码",
+    "dataType": "数据类型",
+    "unit": "单位",
+    "selectedItems": "已选择 {count} 项",
+    "batchDelete": "批量删除",
+    "batchEnable": "批量启用",
+    "batchDisable": "批量禁用",
+    "confirmDeleteDimension": "确定要删除维度 \"{name}\" 吗?",
+    "deleteConfirmation": "删除确认",
+    "statusUpdateSuccess": "状态更新成功",
+    "statusUpdateFailed": "状态更新失败",
+    "selectItemsToDelete": "请选择要删除的项目",
+    "confirmBatchDelete": "确定要批量删除 {count} 个项目吗?",
+    "batchDeleteConfirmation": "批量删除确认",
+    "batchDeleteSuccess": "批量删除成功",
+    "batchDeleteFailed": "批量删除失败",
+    "selectItemsToEnable": "请选择要启用的项目",
+    "batchEnableSuccess": "批量启用成功",
+    "batchEnableFailed": "批量启用失败",
+    "selectItemsToDisable": "请选择要禁用的项目",
+    "batchDisableSuccess": "批量禁用成功",
+    "batchDisableFailed": "批量禁用失败"
+  },
   "menu": {
     "dashboard": "首页",
     "goods": "商品",
@@ -147,6 +275,7 @@
     "bannerAd": "广告位",
     "data": "数据",
     "dataReport": "数据报表",
+    "dataReport": "数据报表",
     "finance": "财务",
     "recharge": "充值",
     "withdraw": "提款",
@@ -1437,6 +1566,7 @@
       "selectStartTime": "请选择开始时间",
       "selectEndTime": "请选择结束时间",
       "selectGroupSize": "请选择成团默认人数",
+      "twoPersonGroup": "2人团",
       "fivePersonGroup": "5人团",
       "tenPersonGroup": "10人团",
       "twentyPersonGroup": "20人团",

部分文件因为文件数量过多而无法显示