miaofuhao 1 kuukausi sitten
vanhempi
commit
833ae5c591
1 muutettua tiedostoa jossa 386 lisäystä ja 66 poistoa
  1. 386 66
      apps/web-ele/src/views/examManage/examPaper/index.vue

+ 386 - 66
apps/web-ele/src/views/examManage/examPaper/index.vue

@@ -1,13 +1,11 @@
1 1
 <script lang="ts" setup>
2 2
 // 导入依赖
3
-import type { VbenFormProps } from '@vben/common-ui';
4 3
 import type { EchartsUIType } from '@vben/plugins/echarts';
5
-
6 4
 import type { VxeGridProps } from '#/adapter/vxe-table';
7 5
 
8
-import { computed, onMounted, ref } from 'vue';
6
+import { computed, onMounted, ref, watch } from 'vue';
9 7
 
10
-import { Page } from '@vben/common-ui';
8
+import { Page, useVbenDrawer } from '@vben/common-ui';
11 9
 import { EchartsUI, useEcharts } from '@vben/plugins/echarts';
12 10
 
13 11
 import { ElButton } from 'element-plus';
@@ -95,7 +93,7 @@ const switchTab = (tab: string) => {
95 93
 const questionStatsColumns: VxeGridProps['columns'] = [
96 94
   { title: '序号', width: 80, field: 'id', type: 'seq' },
97 95
   { title: '题目类别', width: 120, field: 'category' },
98
-  { title: '题目名称', width: 400, field: 'name' },
96
+  { title: '题目名称', field: 'name' },
99 97
   { title: '正确数', width: 100, field: 'correctCount' },
100 98
   { title: '正确率', width: 100, field: 'correctRate' },
101 99
 ];
@@ -171,29 +169,20 @@ const questionStatsGridOptions: VxeGridProps = {
171 169
   id: 'exam-paper-question-stats',
172 170
 };
173 171
 
174
-// 表单配置(无搜索表单)
175
-const questionStatsFormOptions: VbenFormProps = {
176
-  commonConfig: {
177
-    labelWidth: 80,
178
-    componentProps: { allowClear: true },
179
-  },
180
-  schema: [],
181
-};
182 172
 
183 173
 // 创建表格组件
184 174
 const [QuestionStatsTable] = useVbenVxeGrid({
185
-  formOptions: questionStatsFormOptions,
186 175
   gridOptions: questionStatsGridOptions,
187 176
 });
188 177
 
189 178
 // ========================== 操作日志表格 ==========================
190 179
 // 列配置
191 180
 const operationLogsColumns: VxeGridProps['columns'] = [
192
-  { title: '序号', width: 80, field: 'id', type: 'seq' },
193
-  { title: '操作部门', width: 150, field: 'department' },
194
-  { title: '操作人', width: 120, field: 'operator' },
195
-  { title: '操作内容', width: 300, field: 'content' },
196
-  { title: '操作时间', width: 180, field: 'time' },
181
+  { title: '序号',field: 'id', type: 'seq' },
182
+  { title: '操作部门', field: 'department' },
183
+  { title: '操作人', field: 'operator' },
184
+  { title: '操作内容', field: 'content' },
185
+  { title: '操作时间', field: 'time' },
197 186
 ];
198 187
 
199 188
 // 表格配置
@@ -253,7 +242,8 @@ const operationLogsGridOptions: VxeGridProps = {
253 242
   id: 'exam-paper-operation-logs',
254 243
 };
255 244
 
256
-// 表单配置(无搜索表单)
245
+// 注意:以下表单配置已不再使用
246
+/*
257 247
 const operationLogsFormOptions: VbenFormProps = {
258 248
   commonConfig: {
259 249
     labelWidth: 80,
@@ -261,10 +251,10 @@ const operationLogsFormOptions: VbenFormProps = {
261 251
   },
262 252
   schema: [],
263 253
 };
254
+*/
264 255
 
265 256
 // 创建表格组件
266 257
 const [OperationLogsTable] = useVbenVxeGrid({
267
-  formOptions: operationLogsFormOptions,
268 258
   gridOptions: operationLogsGridOptions,
269 259
 });
270 260
 
@@ -310,7 +300,8 @@ const scoreRanksGridOptions: VxeGridProps = {
310 300
   id: 'exam-paper-score-ranks',
311 301
 };
312 302
 
313
-// 表单配置(无搜索表单)
303
+// 注意:以下表单配置已不再使用
304
+/*
314 305
 const scoreRanksFormOptions: VbenFormProps = {
315 306
   commonConfig: {
316 307
     labelWidth: 80,
@@ -318,10 +309,10 @@ const scoreRanksFormOptions: VbenFormProps = {
318 309
   },
319 310
   schema: [],
320 311
 };
312
+*/
321 313
 
322 314
 // 创建表格组件
323 315
 const [ScoreRanksTable] = useVbenVxeGrid({
324
-  formOptions: scoreRanksFormOptions,
325 316
   gridOptions: scoreRanksGridOptions,
326 317
 });
327 318
 
@@ -360,17 +351,11 @@ const updateChart = () => {
360 351
             borderWidth: 2,
361 352
           },
362 353
           label: {
363
-            show: true,
364
-            position: 'center',
365
-            formatter: '{b}\n{c}',
366
-            fontSize: 18,
367
-            fontWeight: 'bold',
354
+            show: false
368 355
           },
369 356
           emphasis: {
370 357
             label: {
371
-              show: true,
372
-              fontSize: '20',
373
-              fontWeight: 'bold',
358
+              show: false
374 359
             },
375 360
           },
376 361
           labelLine: { show: false },
@@ -384,7 +369,7 @@ const updateChart = () => {
384 369
         formatter: '{b}: {c}<br/>参与率: 60.00%',
385 370
       },
386 371
     });
387
-  } else {
372
+  } else if (chartType.value === 'pass') {
388 373
     // 及格情况图表
389 374
     renderEcharts({
390 375
       series: [
@@ -398,17 +383,11 @@ const updateChart = () => {
398 383
             borderWidth: 2,
399 384
           },
400 385
           label: {
401
-            show: true,
402
-            position: 'center',
403
-            formatter: '{b}\n{c}',
404
-            fontSize: 18,
405
-            fontWeight: 'bold',
386
+            show: false
406 387
           },
407 388
           emphasis: {
408 389
             label: {
409
-              show: true,
410
-              fontSize: '20',
411
-              fontWeight: 'bold',
390
+              show: false
412 391
             },
413 392
           },
414 393
           labelLine: { show: false },
@@ -425,6 +404,177 @@ const updateChart = () => {
425 404
   }
426 405
 };
427 406
 
407
+// ========================== 表单数据 ==========================
408
+// 定义表单数据
409
+const formData = ref({
410
+  ruleName: '',
411
+  questionTypes: [] as string[],
412
+  participants: [] as string[],
413
+  correctors: [] as string[],
414
+  timeRange: [] as [Date, Date] | null,
415
+  executionMode: '',
416
+});
417
+
418
+// 表单验证规则
419
+const formRules = ref({
420
+  ruleName: [{ required: true, message: '请输入规则名称', trigger: 'blur' }],
421
+  questionTypes: [{ required: true, message: '请选择题目类型', trigger: 'change' }],
422
+  participants: [{ required: true, message: '请选择参与人员', trigger: 'change' }],
423
+  correctors: [{ required: true, message: '请选择批改人员', trigger: 'change' }],
424
+  timeRange: [{ required: true, message: '请选择规则起止时间', trigger: 'change' }],
425
+  executionMode: [{ required: true, message: '请选择规则执行方式', trigger: 'change' }],
426
+});
427
+
428
+// 题目类型选项
429
+const questionTypeOptions = [
430
+  { value: 'single', label: '单选题' },
431
+  { value: 'multiple', label: '多选题' },
432
+  { value: 'judgment', label: '判断题' },
433
+  { value: 'fill', label: '填空题' },
434
+  { value: 'short', label: '简答题' },
435
+];
436
+
437
+// 表单引用
438
+const formRef = ref<InstanceType<typeof ElForm> | null>(null);
439
+
440
+// 监听题目类型变化,初始化新增类型的默认值
441
+watch(
442
+  () => formData.value.questionTypes,
443
+  (newTypes, oldTypes) => {
444
+    // 如果是新增类型,初始化默认值
445
+    const addedTypes = newTypes.filter(type => !oldTypes.includes(type));
446
+    addedTypes.forEach(type => {
447
+      formData.value[`questionCount_${type}`] = 0;
448
+      formData.value[`extractType_${type}`] = 'random';
449
+      formData.value[`scorePerQuestion_${type}`] = 0;
450
+    });
451
+  },
452
+  { deep: true }
453
+);
454
+
455
+// 计算每种题型的总分
456
+const calculateTypeTotal = (type: string): number => {
457
+  const count = Number(formData.value[`questionCount_${type}`] || 0);
458
+  const scorePer = Number(formData.value[`scorePerQuestion_${type}`] || 0);
459
+  return count * scorePer;
460
+};
461
+
462
+// 计算所有题型的总分
463
+const grandTotal = computed(() => {
464
+  const types = formData.value.questionTypes || [];
465
+  return types.reduce((total, type) => {
466
+    return total + calculateTypeTotal(type);
467
+  }, 0);
468
+});
469
+
470
+// 计算所有题型的总题数
471
+const totalQuestions = computed(() => {
472
+  const types = formData.value.questionTypes || [];
473
+  return types.reduce((total, type) => {
474
+    return total + Number(formData.value[`questionCount_${type}`] || 0);
475
+  }, 0);
476
+});
477
+
478
+// 更新数量或分值时重新计算
479
+const updateCalculations = () => {
480
+  // 计算属性会自动更新,无需手动调用
481
+};
482
+
483
+// 定义抽屉
484
+const [Drawer, drawerApi] = useVbenDrawer({
485
+  title: '添加规则',
486
+  async onOpenChange(isOpen: boolean) {
487
+    if (!isOpen) {
488
+      return;
489
+    }
490
+    try {
491
+      drawerApi.drawerLoading(true);
492
+      // 可以在这里加载表单数据
493
+    } catch (error) {
494
+      console.error(error);
495
+    } finally {
496
+      drawerApi.drawerLoading(false);
497
+    }
498
+  },
499
+  async onClosed() {
500
+    // 重置表单
501
+    if (formRef.value) {
502
+      formRef.value.resetFields();
503
+    }
504
+  },
505
+  async onConfirm() {
506
+    try {
507
+      drawerApi.drawerLoading(true);
508
+      if (!formRef.value) return;
509
+      
510
+      await formRef.value.validate((valid) => {
511
+        if (!valid) {
512
+          return;
513
+        }
514
+        // 处理表单提交逻辑
515
+        console.log('提交的数据:', formData.value);
516
+        drawerApi.close();
517
+      });
518
+    } catch (error) {
519
+      console.error(error);
520
+    } finally {
521
+      drawerApi.drawerLoading(false);
522
+    }
523
+  },
524
+});
525
+
526
+// 打开抽屉
527
+const openAddCategoryModal = () => {
528
+  drawerApi.open();
529
+};
530
+
531
+// 获取题目类型中文名称
532
+const getQuestionTypeName = (type: string): string => {
533
+  const typeMap: Record<string, string> = {
534
+    single: '单选题',
535
+    multiple: '多选题',
536
+    judgment: '判断题',
537
+    fill: '填空题',
538
+    short: '简答题',
539
+  };
540
+  return typeMap[type] || type;
541
+};
542
+
543
+// 注意:以下函数是旧的useVbenForm实现方式,已被新的计算属性替代
544
+// 保留仅供参考,实际已不再使用
545
+/*
546
+const calculateTypeTotal = (type: string): number => {
547
+  const values = formApi.getValues();
548
+  const count = Number(values[`questionCount_${type}`] || 0);
549
+  const scorePer = Number(values[`scorePerQuestion_${type}`] || 0);
550
+  return count * scorePer;
551
+};
552
+
553
+const calculateGrandTotal = (): number => {
554
+  const values = formApi.getValues();
555
+  const types = values.questionTypes || [];
556
+  return types.reduce((total, type) => {
557
+    return total + calculateTypeTotal(type);
558
+  }, 0);
559
+};
560
+
561
+const calculateTotalQuestions = (): number => {
562
+  const values = formApi.getValues();
563
+  const types = values.questionTypes || [];
564
+  return types.reduce((total, type) => {
565
+    return total + Number(values[`questionCount_${type}`] || 0);
566
+  }, 0);
567
+};
568
+
569
+const calculateTotal = () => {
570
+  const values = formApi.getValues();
571
+  const types = values.questionTypes || [];
572
+  types.forEach(type => calculateTypeTotal(type));
573
+  calculateGrandTotal();
574
+  calculateTotalQuestions();
575
+};
576
+*/
577
+
428 578
 // ========================== 生命周期钩子 ==========================
429 579
 onMounted(() => {
430 580
   // 初始化图表
@@ -438,15 +588,10 @@ onMounted(() => {
438 588
       <!-- 左侧考卷分类 -->
439 589
       <div class="left-panel">
440 590
         <div class="panel-header">
441
-          <h2>考卷分类</h2>
442
-        </div>
443
-        <div class="search-container">
444
-          <input
445
-            v-model="searchKeyword"
446
-            type="text"
447
-            class="search-input"
448
-            placeholder="搜索考卷分类"
449
-          />
591
+          <h2>考卷管理</h2>
592
+          <button class="add-btn" @click="openAddCategoryModal">
593
+            添加考卷规则
594
+          </button>
450 595
         </div>
451 596
         <div class="category-list">
452 597
           <div
@@ -499,12 +644,12 @@ onMounted(() => {
499 644
 
500 645
         <!-- 数据看板内容 -->
501 646
         <div v-if="activeTab === 'dashboard'" class="dashboard-content">
502
-          <QuestionStatsTable table-title="题目统计" />
647
+          <QuestionStatsTable/>
503 648
         </div>
504 649
 
505 650
         <!-- 操作日志内容 -->
506 651
         <div v-if="activeTab === 'log'" class="log-content">
507
-          <OperationLogsTable table-title="操作日志" />
652
+          <OperationLogsTable/>
508 653
         </div>
509 654
 
510 655
         <!-- 下方统计区域 -->
@@ -541,7 +686,7 @@ onMounted(() => {
541 686
             <div class="section-header">
542 687
               <h3>人员得分排名</h3>
543 688
             </div>
544
-            <ScoreRanksTable table-title="人员得分排名">
689
+            <ScoreRanksTable>
545 690
               <template #action="{ row }">
546 691
                 <ElButton size="small" @click="viewDetail(row.id)">
547 692
                   查看
@@ -553,6 +698,114 @@ onMounted(() => {
553 698
       </div>
554 699
     </div>
555 700
   </Page>
701
+
702
+  <!-- 添加考卷规则抽屉 -->
703
+  <Drawer class="w-[800px]">
704
+    <ElForm ref="formRef" :model="formData" :rules="formRules" label-width="120px">
705
+      <ElFormItem label="规则名称" prop="ruleName">
706
+        <ElInput v-model="formData.ruleName" placeholder="请输入规则名称" />
707
+      </ElFormItem>
708
+      
709
+      <ElFormItem label="题目类型" prop="questionTypes">
710
+        <ElSelect v-model="formData.questionTypes" multiple placeholder="请选择题目类型">
711
+          <ElOption
712
+            v-for="option in questionTypeOptions"
713
+            :key="option.value"
714
+            :label="option.label"
715
+            :value="option.value"
716
+          />
717
+        </ElSelect>
718
+      </ElFormItem>
719
+      
720
+      <!-- 动态表格:题目数量和分值配置 -->
721
+      <ElFormItem label="题目配置">
722
+        <div v-if="formData.questionTypes.length > 0">
723
+          <ElTable :data="formData.questionTypes" border style="width: 100%">
724
+            <ElTableColumn prop="type" label="类型" width="120">
725
+              <template #default="scope">
726
+                {{ getQuestionTypeName(scope.row) }}
727
+              </template>
728
+            </ElTableColumn>
729
+            <ElTableColumn prop="count" label="数量" width="120">
730
+              <template #default="scope">
731
+                <ElInput-number
732
+                  v-model="formData[`questionCount_${scope.row}`]"
733
+                  :min="0"
734
+                  :step="1"
735
+                  @change="updateCalculations"
736
+                  style="width: 100%"
737
+                />
738
+              </template>
739
+            </ElTableColumn>
740
+            <ElTableColumn prop="extract" label="抽取方式" width="120">
741
+              <template #default="scope">
742
+                <ElSelect v-model="formData[`extractType_${scope.row}`]" style="width: 100%">
743
+                  <ElOption label="随机" value="random" />
744
+                </ElSelect>
745
+              </template>
746
+            </ElTableColumn>
747
+            <ElTableColumn prop="score" label="每题分值" width="120">
748
+              <template #default="scope">
749
+                <ElInput-number
750
+                  v-model="formData[`scorePerQuestion_${scope.row}`]"
751
+                  :min="0"
752
+                  :step="0.5"
753
+                  @change="updateCalculations"
754
+                  style="width: 100%"
755
+                />
756
+              </template>
757
+            </ElTableColumn>
758
+            <ElTableColumn prop="total" label="合计分值" width="120">
759
+              <template #default="scope">
760
+                {{ calculateTypeTotal(scope.row) }}
761
+              </template>
762
+            </ElTableColumn>
763
+          </ElTable>
764
+          
765
+          <!-- 汇总信息 -->
766
+          <div class="summary-info" style=" display: flex; align-items: center; justify-content: flex-end; padding: 12px;margin-top: 16px; background-color: #f5f7fa; border-radius: 4px;">
767
+            <ElDescriptions :column="2" border size="small" style="width: auto;">
768
+              <ElDescriptionsItem label="总题数">{{ totalQuestions }}</ElDescriptionsItem>
769
+              <ElDescriptionsItem label="总分值">{{ grandTotal }}</ElDescriptionsItem>
770
+            </ElDescriptions>
771
+          </div>
772
+        </div>
773
+        <div v-else style="padding: 20px; color: #999; text-align: center; background-color: #fafafa; border: 1px dashed #dcdfe6; border-radius: 4px;">
774
+         
775
+          请先选择题目类型
776
+        </div>
777
+      </ElFormItem>
778
+      
779
+      <ElFormItem label="参与人员" prop="participants">
780
+        <ElSelect v-model="formData.participants" multiple placeholder="请选择参与人员">
781
+          <!-- 这里可以根据实际情况添加参与人员选项 -->
782
+        </ElSelect>
783
+      </ElFormItem>
784
+      
785
+      <ElFormItem label="批改人员" prop="correctors">
786
+        <ElSelect v-model="formData.correctors" multiple placeholder="请选择批改人员">
787
+          <!-- 这里可以根据实际情况添加批改人员选项 -->
788
+        </ElSelect>
789
+      </ElFormItem>
790
+      
791
+      <ElFormItem label="规则起止时间" prop="timeRange">
792
+        <ElDatePicker
793
+          v-model="formData.timeRange"
794
+          type="daterange"
795
+          range-separator="至"
796
+          start-placeholder="开始日期"
797
+          end-placeholder="结束日期"
798
+          style="width: 100%"
799
+        />
800
+      </ElFormItem>
801
+      
802
+      <ElFormItem label="规则执行方式" prop="executionMode">
803
+        <ElSelect v-model="formData.executionMode" placeholder="请选择规则执行方式">
804
+          <!-- 这里可以根据实际情况添加执行方式选项 -->
805
+        </ElSelect>
806
+      </ElFormItem>
807
+    </ElForm>
808
+  </Drawer>
556 809
 </template>
557 810
 
558 811
 <style lang="scss" scoped>
@@ -571,14 +824,14 @@ onMounted(() => {
571 824
   flex-direction: column;
572 825
   background-color: #fff;
573 826
   border-radius: 6px;
574
-  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
827
+  box-shadow: 0 2px 8px rgb(0 0 0 / 10%);
575 828
 }
576 829
 
577 830
 .panel-header {
578 831
   display: flex;
579 832
   gap: 16px;
580
-  justify-content: space-between;
581 833
   align-items: center;
834
+  justify-content: space-between;
582 835
   padding: 16px;
583 836
   border-bottom: 1px solid #e8e8e8;
584 837
 }
@@ -589,18 +842,18 @@ onMounted(() => {
589 842
 }
590 843
 
591 844
 .search-input {
845
+  box-sizing: border-box;
592 846
   width: 100%;
593 847
   padding: 8px 12px;
594 848
   font-size: 14px;
595 849
   border: 1px solid #d9d9d9;
596 850
   border-radius: 4px;
597 851
   transition: all 0.3s;
598
-  box-sizing: border-box;
599 852
 
600 853
   &:focus {
601
-    outline: none;
602 854
     border-color: #1890ff;
603
-    box-shadow: 0 0 0 2px rgba(24, 144, 255, 0.2);
855
+    outline: none;
856
+    box-shadow: 0 0 0 2px rgb(24 144 255 / 20%);
604 857
   }
605 858
 }
606 859
 
@@ -611,6 +864,21 @@ onMounted(() => {
611 864
   color: #333;
612 865
 }
613 866
 
867
+.add-btn {
868
+  padding: 6px 16px;
869
+  font-size: 14px;
870
+  color: white;
871
+  cursor: pointer;
872
+  background-color: #1890ff;
873
+  border: none;
874
+  border-radius: 4px;
875
+  transition: background-color 0.3s;
876
+
877
+  &:hover {
878
+    background-color: #40a9ff;
879
+  }
880
+}
881
+
614 882
 .exam-info {
615 883
   display: flex;
616 884
   flex-wrap: wrap;
@@ -644,13 +912,13 @@ onMounted(() => {
644 912
 
645 913
   &:hover {
646 914
     background-color: #e6f7ff;
647
-    box-shadow: 0 2px 8px rgba(24, 144, 255, 0.15);
915
+    box-shadow: 0 2px 8px rgb(24 144 255 / 15%);
648 916
   }
649 917
 
650 918
   &.active {
651 919
     background-color: #e6f7ff;
652 920
     border-color: #1890ff;
653
-    box-shadow: 0 2px 8px rgba(24, 144, 255, 0.15);
921
+    box-shadow: 0 2px 8px rgb(24 144 255 / 15%);
654 922
   }
655 923
 }
656 924
 
@@ -674,8 +942,8 @@ onMounted(() => {
674 942
 /* 右侧占位符样式 */
675 943
 .placeholder {
676 944
   display: flex;
677
-  justify-content: center;
678 945
   align-items: center;
946
+  justify-content: center;
679 947
   height: 100%;
680 948
   font-size: 16px;
681 949
   color: #999;
@@ -693,8 +961,8 @@ onMounted(() => {
693 961
 .tab-item {
694 962
   padding: 12px 20px;
695 963
   font-size: 14px;
696
-  cursor: pointer;
697 964
   color: #666;
965
+  cursor: pointer;
698 966
   border-bottom: 2px solid transparent;
699 967
   transition: all 0.3s;
700 968
 
@@ -703,9 +971,9 @@ onMounted(() => {
703 971
   }
704 972
 
705 973
   &.active {
974
+    font-weight: 500;
706 975
     color: #1890ff;
707 976
     border-bottom-color: #1890ff;
708
-    font-weight: 500;
709 977
   }
710 978
 }
711 979
 
@@ -713,9 +981,9 @@ onMounted(() => {
713 981
 .dashboard-content,
714 982
 .log-content {
715 983
   flex: 1;
984
+  min-height: 300px;
716 985
   padding: 16px;
717 986
   overflow-y: auto;
718
-  min-height: 300px;
719 987
 }
720 988
 
721 989
 /* 下方统计区域 */
@@ -732,15 +1000,15 @@ onMounted(() => {
732 1000
 .rank-section {
733 1001
   display: flex;
734 1002
   flex-direction: column;
1003
+  padding: 16px;
735 1004
   background-color: #fafafa;
736 1005
   border-radius: 6px;
737
-  padding: 16px;
738 1006
 }
739 1007
 
740 1008
 .section-header {
741 1009
   display: flex;
742
-  justify-content: space-between;
743 1010
   align-items: center;
1011
+  justify-content: space-between;
744 1012
   margin-bottom: 16px;
745 1013
 }
746 1014
 
@@ -760,8 +1028,8 @@ onMounted(() => {
760 1028
   position: absolute;
761 1029
   top: 50%;
762 1030
   left: 50%;
763
-  transform: translate(-50%, -50%);
764 1031
   text-align: center;
1032
+  transform: translate(-50%, -50%);
765 1033
 }
766 1034
 
767 1035
 .count-label {
@@ -782,4 +1050,56 @@ onMounted(() => {
782 1050
     border-radius: 4px;
783 1051
   }
784 1052
 }
1053
+
1054
+/* 动态生成的表格样式 */
1055
+.vben-table {
1056
+  overflow: hidden;
1057
+  border: 1px solid #e8e8e8;
1058
+  border-radius: 4px;
1059
+}
1060
+
1061
+.vben-table th {
1062
+  font-weight: 500;
1063
+  color: #333;
1064
+  background-color: #fafafa;
1065
+  border-bottom: 1px solid #e8e8e8;
1066
+}
1067
+
1068
+.vben-table td {
1069
+  color: #666;
1070
+  border-bottom: 1px solid #f0f0f0;
1071
+}
1072
+
1073
+.vben-table tr:last-child td {
1074
+  border-bottom: none;
1075
+}
1076
+
1077
+/* 动态生成的表单控件样式 */
1078
+.vben-input,
1079
+.vben-select {
1080
+  height: 28px;
1081
+  padding: 4px 8px;
1082
+  font-size: 12px;
1083
+  border-color: #d9d9d9;
1084
+  border-radius: 4px;
1085
+  outline: none;
1086
+  transition: all 0.3s;
1087
+
1088
+  &:focus {
1089
+    border-color: #1890ff;
1090
+    box-shadow: 0 0 0 2px rgb(24 144 255 / 20%);
1091
+  }
1092
+}
1093
+
1094
+/* 汇总信息样式 */
1095
+.summary-info {
1096
+  display: flex;
1097
+  align-items: center;
1098
+  justify-content: flex-start;
1099
+  padding: 12px;
1100
+  margin-top: 12px;
1101
+  background-color: #fafafa;
1102
+  border: 1px solid #e8e8e8;
1103
+  border-radius: 4px;
1104
+}
785 1105
 </style>