Bläddra i källkod

feat:添加课时统计

DESKTOP-USV654P\pc 5 månader sedan
förälder
incheckning
9254594f5b

+ 35 - 0
src/services/apis/ClassTimeStatisticsController.ts

@@ -0,0 +1,35 @@
+// @ts-ignore
+/* eslint-disable */
+
+// 该文件自动生成,请勿手动修改!
+import { defHttp } from '/@/utils/http/axios';
+import { ErrorMessageMode } from '/#/axios';
+            // --------------------------------------------------------------------------
+            // Class Time Statistics Controller
+            // --------------------------------------------------------------------------
+
+            ;
+
+
+            /** 新增课时统计 POST /classtime/classTimeStatistics */
+export async function postClasstimeClassTimeStatistics(params:API.AddClassTimeStatisticsDto
+,mode: ErrorMessageMode = 'modal'){ return defHttp.post<any>
+        ({url: '/classtime/classTimeStatistics', data:params},{errorMessageMode:mode});}
+/** 修改课时统计 PUT /classtime/classTimeStatistics */
+export async function putClasstimeClassTimeStatistics(params:API.UpdateClassTimeStatisticsDto
+,mode: ErrorMessageMode = 'modal'){ return defHttp.put<any>
+        ({url: '/classtime/classTimeStatistics', data:params},{errorMessageMode:mode});}
+/** 删除课时统计 DELETE /classtime/classTimeStatistics */
+export async function deleteClasstimeClassTimeStatistics(params:string[],mode: ErrorMessageMode = 'modal'){ return defHttp.delete<any>
+        ({url: '/classtime/classTimeStatistics', data:params},{errorMessageMode:mode});}
+/** 修改状态 POST /classtime/classTimeStatistics/change-status */
+export async function postClassTimeStatisticsChangeStatus(params:API.ChangeStatusDto
+,mode: ErrorMessageMode = 'modal'){ return defHttp.post<any>
+        ({url: '/classtime/classTimeStatistics/change-status', data:params},{errorMessageMode:mode});}
+/** 根据id查询课时统计信息 GET /classtime/classTimeStatistics/info */
+export async function getClassTimeStatisticsInfo(params:any,mode: ErrorMessageMode = 'modal'){ return defHttp.get<API.ClassTimeStatisticsVo>
+        ({url: '/classtime/classTimeStatistics/info', params:params},{errorMessageMode:mode});}
+/** 课时统计列表(分页) GET /classtime/classTimeStatistics/page */
+export async function getClassTimeStatisticsPage(params:any,mode: ErrorMessageMode = 'modal'){ return defHttp.get<API.PageOutput<API.ClassTimeStatisticsPageVo>>
+        ({url: '/classtime/classTimeStatistics/page', params:params},{errorMessageMode:mode});}
+            

+ 34 - 0
src/services/apis/ClassTimeStatisticsSetController.ts

@@ -0,0 +1,34 @@
+// @ts-ignore
+/* eslint-disable */
+
+// 该文件自动生成,请勿手动修改!
+import { defHttp } from '/@/utils/http/axios';
+import { ErrorMessageMode } from '/#/axios';
+            // --------------------------------------------------------------------------
+            // Class Time Statistics Set Controller
+            // --------------------------------------------------------------------------
+
+            ;
+
+
+            /** 新增课时统计-设置 POST /classtime/classTimeStatisticsSet */
+export async function postClasstimeClassTimeStatisticsSet(params:API.AddClassTimeStatisticsSetDto
+,mode: ErrorMessageMode = 'modal'){ return defHttp.post<any>
+        ({url: '/classtime/classTimeStatisticsSet', data:params},{errorMessageMode:mode});}
+/** 修改课时统计-设置 PUT /classtime/classTimeStatisticsSet */
+export async function putClasstimeClassTimeStatisticsSet(params:API.UpdateClassTimeStatisticsSetDto
+,mode: ErrorMessageMode = 'modal'){ return defHttp.put<any>
+        ({url: '/classtime/classTimeStatisticsSet', data:params},{errorMessageMode:mode});}
+/** 删除课时统计-设置 DELETE /classtime/classTimeStatisticsSet */
+export async function deleteClasstimeClassTimeStatisticsSet(params:string[],mode: ErrorMessageMode = 'modal'){ return defHttp.delete<any>
+        ({url: '/classtime/classTimeStatisticsSet', data:params},{errorMessageMode:mode});}
+/** 根据id查询课时统计-设置信息 GET /classtime/classTimeStatisticsSet/info */
+export async function getClassTimeStatisticsSetInfo(params:any,mode: ErrorMessageMode = 'modal'){ return defHttp.get<API.ClassTimeStatisticsSetVo>
+        ({url: '/classtime/classTimeStatisticsSet/info', params:params},{errorMessageMode:mode});}
+/** 查询最新设置信息 GET /classtime/classTimeStatisticsSet/last-info */
+export async function getClassTimeStatisticsSetLastInfo(params:any,mode: ErrorMessageMode = 'modal'){ return defHttp.get<API.ClassTimeStatisticsSetVo>
+        ({url: '/classtime/classTimeStatisticsSet/last-info', params:params},{errorMessageMode:mode});}
+/** 课时统计-设置列表(分页) GET /classtime/classTimeStatisticsSet/page */
+export async function getClassTimeStatisticsSetPage(params:any,mode: ErrorMessageMode = 'modal'){ return defHttp.get<API.PageOutput<API.ClassTimeStatisticsSetPageVo>>
+        ({url: '/classtime/classTimeStatisticsSet/page', params:params},{errorMessageMode:mode});}
+            

+ 1 - 1
src/services/apis/LedgerCustomController.ts

@@ -11,7 +11,7 @@ import { ErrorMessageMode } from '/#/axios';
             ;
 
 
-            /** 修改状态(仅限于表中有delete_mark) PUT /ledger/ledgerCustom */
+            /** 修改状态(仅限于表中有enabled_mark) PUT /ledger/ledgerCustom */
 export async function putLedgerLedgerCustom(params:API.LedgerCustomUpdateDto
 ,mode: ErrorMessageMode = 'modal'){ return defHttp.put<any>
         ({url: '/ledger/ledgerCustom', data:params},{errorMessageMode:mode});}

+ 6 - 0
src/services/apis/index.ts

@@ -29,6 +29,8 @@ import * as WhitelistManagementController from './WhitelistManagementController'
 import * as BaseClassController from './BaseClassController';
 import * as ClassroomController from './ClassroomController';
 import * as ClassTimeController from './ClassTimeController';
+import * as ClassTimeStatisticsController from './ClassTimeStatisticsController';
+import * as ClassTimeStatisticsSetController from './ClassTimeStatisticsSetController';
 import * as ConcatController from './ConcatController';
 import * as SecondCourseController from './SecondCourseController';
 import * as CourseTableController from './CourseTableController';
@@ -269,6 +271,10 @@ BaseClassController,
 ClassroomController,
 /** Class Time Controller */
 ClassTimeController,
+/** Class Time Statistics Controller */
+ClassTimeStatisticsController,
+/** Class Time Statistics Set Controller */
+ClassTimeStatisticsSetController,
 /** Concat Controller */
 ConcatController,
 /** Second Course Controller */

+ 193 - 0
src/services/typing.d.ts

@@ -1811,6 +1811,24 @@ winterEndTime?: string;
 winterStartTime?: string;
 }
 
+type AddClassTimeStatisticsDto = {
+/** 结束日期 */
+endDate?: string;
+/** 统计月份 */
+month?: number;
+/** 开始日期 */
+startDate?: string;
+/** 统计年份 */
+year?: number;
+}
+
+type AddClassTimeStatisticsSetDto = {
+/** 类别(1:权重 2:费用设置) */
+category?: number;
+/** 权重内容 */
+jsonContent?: string;
+}
+
 type AddCodeRuleDto = {
 /** 编号 */
 code?: string;
@@ -8003,6 +8021,143 @@ winterEndTime?: string;
 winterStartTime?: string;
 }
 
+type ClassTimeStatisticsPageVo = {
+/** 总课时 */
+allClassTime?: number;
+/** 总外聘教师超课时费 */
+beyondClassTimeAmount?: number;
+/** 总课时费用 */
+classTimeAmount?: number;
+/** 创建时间 */
+createDate?: string;
+/** 创建人 */
+createUserId?: string;
+/** 删除标记 */
+deleteMark?: number;
+/** 有效标志 */
+enabledMark?: number;
+/** 结束日期 */
+endDate?: string;
+/** 主键编号 */
+id?: string;
+/** 修改时间 */
+modifyDate?: string;
+/** 修改人 */
+modifyUserId?: string;
+/** 统计月份 */
+month?: number;
+/** 开始日期 */
+startDate?: string;
+/** 状态(0:已解锁 1:已锁定) */
+status?: number;
+/** 总金额 */
+totalAmount?: number;
+/** 统计年份 */
+year?: number;
+}
+
+type ClassTimeStatisticsRecordVo = {
+/** 总课时 */
+allClassTime?: number;
+/** 外聘教师超课时费 */
+beyondClassTimeAmount?: number;
+/** 教研会 */
+classTime1?: number;
+/** 顶课 */
+classTime10?: number;
+/** 调课 */
+classTime11?: number;
+/** 督导听课 */
+classTime2?: number;
+/** 临近三年退休政策 */
+classTime3?: number;
+/** 出题 */
+classTime4?: number;
+/** 阅卷 */
+classTime5?: number;
+/** 周末培优 */
+classTime6?: number;
+/** 早自习 */
+classTime7?: number;
+/** 正课(包含调顶课时) */
+classTime8?: number;
+/** 晚辅(包含调顶课时) */
+classTime9?: number;
+/** 课时费用 */
+classTimeAmount?: number;
+/** 课时统计(class_time_statistics) */
+classTimeStatisticsId?: string;
+/** 权重json */
+costSetJson?: string;
+/** 聘用类型 */
+employType?: string;
+/** 主键编号 */
+id?: string;
+/** 总金额 */
+totalAmount?: number;
+/** 教师id(xjr_user) */
+userId?: string;
+/** 每周数据 */
+weekData?: string;
+/** 权重json */
+weightSetJson?: string;
+}
+
+type ClassTimeStatisticsSetPageVo = {
+/** 类别(1:权重 2:费用设置) */
+category?: number;
+/** 创建时间 */
+createDate?: string;
+/** 创建人 */
+createUserId?: string;
+/** 删除标记 */
+deleteMark?: number;
+/** 有效标志 */
+enabledMark?: number;
+/** 主键编号 */
+id?: string;
+/** 权重内容 */
+jsonContent?: string;
+/** 修改时间 */
+modifyDate?: string;
+/** 修改人 */
+modifyUserId?: string;
+}
+
+type ClassTimeStatisticsSetVo = {
+/** 类别(1:权重 2:费用设置) */
+category?: number;
+/** 主键编号 */
+id?: string;
+/** 权重内容 */
+jsonContent?: string;
+}
+
+type ClassTimeStatisticsVo = {
+/** 总课时 */
+allClassTime?: number;
+/** 总外聘教师超课时费 */
+beyondClassTimeAmount?: number;
+/** 总课时费用 */
+classTimeAmount?: number;
+/** classTimeStatisticsRecord子表 */
+classTimeStatisticsRecordList?: ClassTimeStatisticsRecordVo[];
+/** 结束日期 */
+endDate?: string;
+/** 主键编号 */
+id?: string;
+/** 统计月份 */
+month?: number;
+/** 开始日期 */
+startDate?: string;
+/** 状态(0:已解锁 1:已锁定) */
+status?: number;
+/** 总金额 */
+totalAmount?: number;
+/** 统计年份 */
+year?: number;
+}
+
 type ClassTimeVo = {
 /** 创建时间 */
 createDate?: string;
@@ -12055,6 +12210,22 @@ total?: number;
 totalPage?: number;
 }
 
+type PageOutput<ClassTimeStatisticsPageVo> = {
+currentPage?: number;
+list?: ClassTimeStatisticsPageVo[];
+pageSize?: number;
+total?: number;
+totalPage?: number;
+}
+
+type PageOutput<ClassTimeStatisticsSetPageVo> = {
+currentPage?: number;
+list?: ClassTimeStatisticsSetPageVo[];
+pageSize?: number;
+total?: number;
+totalPage?: number;
+}
+
 type PageOutput<DataExpertSourcePageVo> = {
 currentPage?: number;
 list?: DataExpertSourcePageVo[];
@@ -18457,6 +18628,28 @@ winterEndTime?: string;
 winterStartTime?: string;
 }
 
+type UpdateClassTimeStatisticsDto = {
+/** 结束日期 */
+endDate?: string;
+/** 主键编号 */
+id?: string;
+/** 统计月份 */
+month?: number;
+/** 开始日期 */
+startDate?: string;
+/** 统计年份 */
+year?: number;
+}
+
+type UpdateClassTimeStatisticsSetDto = {
+/** 类别(1:权重 2:费用设置) */
+category?: number;
+/** 主键编号 */
+id?: string;
+/** 权重内容 */
+jsonContent?: string;
+}
+
 type UpdateCodeRuleDto = {
 /** 编号 */
 code?: string;

+ 118 - 0
src/views/course/statistics/components/cost.vue

@@ -0,0 +1,118 @@
+<template>
+  <BasicModal
+    @ok="handleSubmit"
+    :destroyOnClose="true"
+    :maskClosable="false"
+    v-bind="$attrs"
+    @register="registerModal"
+    :title="getTitle"
+    :width="1002"
+    showFooter
+  >
+    <BasicForm @register="registerForm" />
+  </BasicModal>
+</template>
+<script setup lang="ts">
+  import { ref, computed, unref, reactive } from 'vue';
+  import { BasicModal, useModalInner } from '/@/components/Modal';
+  import { BasicForm, FormSchema, useForm } from '/@/components/Form/index';
+  import {
+    getClassTimeStatisticsSetLastInfo,
+    postClasstimeClassTimeStatisticsSet,
+    putClasstimeClassTimeStatisticsSet,
+  } from '/@/services/apis/ClassTimeStatisticsSetController';
+
+  const isUpdate = ref(true);
+  const category = ref(2);
+  const modelRef = ref<Recordable>({});
+  const emit = defineEmits(['success', 'register']);
+
+  const formConfig = reactive<Recordable[]>([
+    { label: '早自习课时单价:正式聘用', field: 'cost1', addonAfter: '元', value: '' },
+    { label: '非正式聘用', field: 'cost2', addonAfter: '元', value: '' },
+    { label: '正课课时单价:正式聘用', field: 'cost3', addonAfter: '元', value: '' },
+    { label: '非正式聘用', field: 'cost4', addonAfter: '元', value: '' },
+    { label: '晚自习课时单价:正式聘用', field: 'cost5', addonAfter: '元', value: '' },
+    { label: '非正式聘用', field: 'cost6', addonAfter: '元', value: '' },
+    { label: ' 超出课时单价:正式聘用', field: 'cost7', addonAfter: '元', value: '' },
+    { label: '非正式聘用', field: 'cost8', addonAfter: '元', value: '' },
+    { label: '超出课时标准(每周):正式聘用', field: 'cost9', addonAfter: '课时', value: '' },
+    { label: '非正式聘用', field: 'cost10', addonAfter: '课时', value: '' },
+    { label: '顶课课时单价:正式聘用', field: 'cost11', addonAfter: '元', value: '' },
+    { label: '非正式聘用', field: 'cost12', addonAfter: '元', value: '' },
+  ]);
+
+  const [registerForm, { validate, resetFields, resetSchema, setFieldsValue }] = useForm({
+    labelWidth: 240,
+    schemas: [],
+    showActionButtonGroup: false,
+  });
+
+  const [registerModal, { closeModal, setModalProps }] = useModalInner(async () => {
+    resetFields();
+    setModalProps({ confirmLoading: false });
+    isUpdate.value = false;
+
+    const formWeightSchema: FormSchema[] = [];
+
+    formConfig.forEach((item) => {
+      formWeightSchema.push({
+        label: item.label,
+        field: item.field,
+        component: 'InputNumber',
+        colProps: { span: 12 },
+        required: true,
+        componentProps: {
+          addonAfter: item.addonAfter,
+          style: { width: '100%' },
+        },
+      });
+    });
+
+    resetSchema(formWeightSchema);
+
+    const resData = await getClassTimeStatisticsSetLastInfo({ category: category.value });
+    if (resData) {
+      modelRef.value = { ...resData };
+      const jsonContent = JSON.parse(resData.jsonContent);
+      const values: Recordable = {};
+      jsonContent.forEach((item) => {
+        values[item.field] = item.value;
+      });
+      setFieldsValue(values);
+      isUpdate.value = true;
+    }
+  });
+
+  const getTitle = computed(() => (!unref(isUpdate) ? '费用设置' : '费用设置'));
+  const handleSubmit = async () => {
+    try {
+      const values = await validate();
+      const jsonContent: Recordable[] = [];
+      setModalProps({ confirmLoading: true });
+
+      formConfig.forEach((item) => {
+        jsonContent.push({ label: item.label, field: item.field, value: values[item.field] });
+      });
+
+      const postParams: Recordable = {
+        category: category.value,
+        jsonContent: JSON.stringify(jsonContent),
+        id: unref(modelRef)?.id,
+      };
+
+      if (unref(isUpdate)) {
+        await putClasstimeClassTimeStatisticsSet(postParams as API.UpdateClassTimeStatisticsSetDto);
+      } else {
+        await postClasstimeClassTimeStatisticsSet(postParams as API.AddClassTimeStatisticsSetDto);
+      }
+
+      closeModal();
+      emit('success');
+    } finally {
+      setModalProps({ confirmLoading: false });
+    }
+  };
+</script>
+
+<style scoped lang="less"></style>

+ 117 - 0
src/views/course/statistics/components/edit.vue

@@ -0,0 +1,117 @@
+<template>
+  <BasicModal
+    @ok="handleSubmit"
+    :destroyOnClose="true"
+    :maskClosable="false"
+    v-bind="$attrs"
+    @register="registerModal"
+    :title="getTitle"
+    :width="1002"
+    showFooter
+    :defaultFullscreen="true"
+  >
+    <div>
+      <div style="height: 112px">
+        <Descriptions bordered>
+          <Descriptions.Item label="年月">
+            {{ modelRef?.year }}年{{ modelRef?.month }}月
+          </Descriptions.Item>
+          <Descriptions.Item label="时间">
+            {{ modelRef?.startDate }}-{{ modelRef?.endDate }}
+          </Descriptions.Item>
+          <Descriptions.Item label="总课时">
+            {{ modelRef?.allClassTime }}
+          </Descriptions.Item>
+          <Descriptions.Item label="总课时费(元)">
+            {{ modelRef?.classTimeAmount }}
+          </Descriptions.Item>
+          <Descriptions.Item label="总外聘教师超课时费(元)">
+            {{ modelRef?.beyondClassTimeAmount }}
+          </Descriptions.Item>
+          <Descriptions.Item label="总金额(元)">
+            {{ modelRef?.totalAmount }}
+          </Descriptions.Item>
+        </Descriptions>
+      </div>
+      <div style="height: calc(100% - 112px)">
+        <BasicTable @register="registerTable">
+          <template #toolbar>
+            <a-button type="primary">刷新统计</a-button>
+            <a-button type="primary">节假日调课设置</a-button>
+            <a-button type="primary" @click="handleWeight">权重设置</a-button>
+            <a-button type="primary" @click="handleCost">费用设置</a-button>
+            <a-button type="primary">导出</a-button>
+          </template>
+          <template #allClassTime="{ text }">
+            <div>{{ text }}</div>
+          </template>
+        </BasicTable>
+      </div>
+    </div>
+    <FormWeight @register="registerWeightModal" />
+    <FormCost @register="registerCostModal" />
+  </BasicModal>
+</template>
+<script setup lang="ts">
+  import { ref, computed, unref } from 'vue';
+  import { BasicModal, useModal, useModalInner } from '/@/components/Modal';
+  import { formDetailSchema } from '../data.config';
+  import { getClassTimeStatisticsInfo } from '/@/services/apis/ClassTimeStatisticsController';
+  import { useTable } from '/@/components/Table';
+  import { Descriptions } from 'ant-design-vue';
+  import FormWeight from './weight.vue';
+  import FormCost from './cost.vue';
+
+  const isUpdate = ref(true);
+  const modelRef = ref<Recordable>({});
+  const emit = defineEmits(['success', 'register']);
+  const [registerWeightModal, { openModal: openWeightModal }] = useModal();
+  const [registerCostModal, { openModal: openCostModal }] = useModal();
+
+  const [registerTable, { setTableData }] = useTable({
+    title: '课时统计表',
+    rowKey: 'id',
+    columns: formDetailSchema,
+    useSearchForm: false,
+    showTableSetting: true,
+    bordered: true,
+    immediate: true,
+    canResize: true,
+    pagination: false,
+  });
+
+  const [registerModal, { closeModal, setModalProps }] = useModalInner(async (data) => {
+    setModalProps({ confirmLoading: true });
+    isUpdate.value = false;
+
+    const resData = await getClassTimeStatisticsInfo({ id: data.baseData.id });
+    modelRef.value = { ...resData };
+    setTableData(resData.classTimeStatisticsRecordList);
+    setModalProps({ confirmLoading: false });
+  });
+
+  const getTitle = computed(() => (!unref(isUpdate) ? '统计明细' : '统计明细'));
+  const handleSubmit = async () => {
+    try {
+      closeModal();
+      emit('success');
+    } finally {
+      setModalProps({ confirmLoading: false });
+    }
+  };
+
+  const handleWeight = () => {
+    openWeightModal(true, {
+      isUpdate: true,
+      baseData: {},
+    });
+  };
+  const handleCost = () => {
+    openCostModal(true, {
+      isUpdate: false,
+      baseData: {},
+    });
+  };
+</script>
+
+<style scoped lang="less"></style>

+ 60 - 0
src/views/course/statistics/components/select.vue

@@ -0,0 +1,60 @@
+<template>
+  <BasicModal
+    @ok="handleSubmit"
+    :destroyOnClose="true"
+    :maskClosable="false"
+    v-bind="$attrs"
+    @register="registerModal"
+    :title="getTitle"
+    :width="1002"
+    showFooter
+  >
+    <BasicForm @register="registerForm" />
+  </BasicModal>
+</template>
+<script setup lang="ts">
+  import { ref, computed, unref } from 'vue';
+  import { BasicModal, useModalInner } from '/@/components/Modal';
+  import { BasicForm, useForm } from '/@/components/Form/index';
+  import { formSchema } from '../data.config';
+  import { postClasstimeClassTimeStatistics } from '/@/services/apis/ClassTimeStatisticsController';
+  import { formatToDate } from '/@/utils/dateUtil';
+
+  const isUpdate = ref(true);
+  const emit = defineEmits(['success', 'register']);
+
+  const [registerForm, { validate, resetFields }] = useForm({
+    labelWidth: 100,
+    schemas: formSchema,
+    showActionButtonGroup: false,
+  });
+
+  const [registerModal, { closeModal, setModalProps }] = useModalInner(async (data) => {
+    resetFields();
+    setModalProps({ confirmLoading: false });
+    isUpdate.value = !!data?.isUpdate;
+  });
+
+  const getTitle = computed(() =>
+    !unref(isUpdate) ? '请选择需要统计课时时间段' : '请选择需要统计课时时间段',
+  );
+  const handleSubmit = async () => {
+    try {
+      const values = await validate();
+      setModalProps({ confirmLoading: true });
+      const postParams: Recordable = {
+        year: formatToDate(values['yearMonth'], 'YYYY'),
+        month: formatToDate(values['yearMonth'], 'MM'),
+        startDate: values['date'][0],
+        endDate: values['date'][1],
+      };
+      await postClasstimeClassTimeStatistics(postParams as API.AddClassTimeStatisticsDto);
+      closeModal();
+      emit('success');
+    } finally {
+      setModalProps({ confirmLoading: false });
+    }
+  };
+</script>
+
+<style scoped lang="less"></style>

+ 117 - 0
src/views/course/statistics/components/weight.vue

@@ -0,0 +1,117 @@
+<template>
+  <BasicModal
+    @ok="handleSubmit"
+    :destroyOnClose="true"
+    :maskClosable="false"
+    v-bind="$attrs"
+    @register="registerModal"
+    :title="getTitle"
+    :width="1002"
+    showFooter
+  >
+    <BasicForm @register="registerForm" />
+  </BasicModal>
+</template>
+<script setup lang="ts">
+  import { ref, computed, unref, reactive } from 'vue';
+  import { BasicModal, useModalInner } from '/@/components/Modal';
+  import { BasicForm, FormSchema, useForm } from '/@/components/Form/index';
+  import {
+    getClassTimeStatisticsSetLastInfo,
+    postClasstimeClassTimeStatisticsSet,
+    putClasstimeClassTimeStatisticsSet,
+  } from '/@/services/apis/ClassTimeStatisticsSetController';
+
+  const isUpdate = ref(true);
+  const category = ref(1);
+  const modelRef = ref<Recordable>({});
+  const emit = defineEmits(['success', 'register']);
+
+  const formConfig = reactive<Recordable[]>([
+    { label: '早自习', field: 'time1', addonAfter: '课时', value: '' },
+    { label: '上1', field: 'time2', addonAfter: '课时', value: '' },
+    { label: '上2', field: 'time3', addonAfter: '课时', value: '' },
+    { label: '上3', field: 'time4', addonAfter: '课时', value: '' },
+    { label: '上4', field: 'time5', addonAfter: '课时', value: '' },
+    { label: '下1', field: 'time6', addonAfter: '课时', value: '' },
+    { label: '下2', field: 'time7', addonAfter: '课时', value: '' },
+    { label: '下3', field: 'time8', addonAfter: '课时', value: '' },
+    { label: '晚1', field: 'time9', addonAfter: '课时', value: '' },
+    { label: '晚2', field: 'time10', addonAfter: '课时', value: '' },
+    { label: '晚3', field: 'time11', addonAfter: '课时', value: '' },
+  ]);
+
+  const [registerForm, { validate, resetFields, resetSchema, setFieldsValue }] = useForm({
+    labelWidth: 100,
+    schemas: [],
+    showActionButtonGroup: false,
+  });
+
+  const [registerModal, { closeModal, setModalProps }] = useModalInner(async () => {
+    resetFields();
+    setModalProps({ confirmLoading: false });
+    isUpdate.value = false;
+
+    const formWeightSchema: FormSchema[] = [];
+
+    formConfig.forEach((item) => {
+      formWeightSchema.push({
+        label: item.label,
+        field: item.field,
+        component: 'InputNumber',
+        colProps: { span: 12 },
+        required: true,
+        componentProps: {
+          addonAfter: item.addonAfter,
+          style: { width: '100%' },
+        },
+      });
+    });
+
+    resetSchema(formWeightSchema);
+
+    const resData = await getClassTimeStatisticsSetLastInfo({ category: category.value });
+    if (resData) {
+      modelRef.value = { ...resData };
+      const jsonContent = JSON.parse(resData.jsonContent);
+      const values: Recordable = {};
+      jsonContent.forEach((item) => {
+        values[item.field] = item.value;
+      });
+      setFieldsValue(values);
+      isUpdate.value = true;
+    }
+  });
+
+  const getTitle = computed(() => (!unref(isUpdate) ? '权重设置' : '权重设置'));
+  const handleSubmit = async () => {
+    try {
+      const values = await validate();
+      const jsonContent: Recordable[] = [];
+      setModalProps({ confirmLoading: true });
+
+      formConfig.forEach((item) => {
+        jsonContent.push({ label: item.label, field: item.field, value: values[item.field] });
+      });
+
+      const postParams: Recordable = {
+        category: category.value,
+        jsonContent: JSON.stringify(jsonContent),
+        id: unref(modelRef)?.id,
+      };
+
+      if (unref(isUpdate)) {
+        await putClasstimeClassTimeStatisticsSet(postParams as API.UpdateClassTimeStatisticsSetDto);
+      } else {
+        await postClasstimeClassTimeStatisticsSet(postParams as API.AddClassTimeStatisticsSetDto);
+      }
+
+      closeModal();
+      emit('success');
+    } finally {
+      setModalProps({ confirmLoading: false });
+    }
+  };
+</script>
+
+<style scoped lang="less"></style>

+ 208 - 0
src/views/course/statistics/data.config.ts

@@ -0,0 +1,208 @@
+import { BasicColumn, FormSchema } from '/@/components/Table';
+
+export const tableColumns: BasicColumn[] = [
+  {
+    title: '年月',
+    dataIndex: 'year',
+    align: 'left',
+    width: 80,
+    customRender: ({ record }) => {
+      return `${record.year}${record.month}月`;
+    },
+  },
+  {
+    title: '时间',
+    dataIndex: 'startDate',
+    align: 'left',
+    width: 180,
+    customRender: ({ record }) => {
+      return `${record.startDate}-${record.endDate}`;
+    },
+  },
+  {
+    title: '总课时',
+    dataIndex: 'allClassTime',
+    align: 'left',
+    width: 80,
+  },
+  {
+    title: '总课时费(元)',
+    dataIndex: 'classTimeAmount',
+    align: 'left',
+    width: 100,
+  },
+  {
+    title: '总外聘教师超课时费(元)',
+    dataIndex: 'beyondClassTimeAmount',
+    align: 'left',
+    width: 150,
+  },
+  {
+    title: '总金额(元)',
+    dataIndex: 'totalAmount',
+    align: 'left',
+  },
+  {
+    title: '状态',
+    dataIndex: 'status',
+    align: 'left',
+    width: 80,
+    customRender: ({ record }) => {
+      return record.status == 1 ? '已锁定' : '已解锁';
+    },
+  },
+];
+
+export const searchFormSchema: FormSchema[] = [
+  {
+    field: 'date',
+    label: '年月',
+    component: 'DatePicker',
+    colProps: { span: 8 },
+    componentProps: {
+      showTime: false,
+      format: 'YYYY-MM',
+      valueFormat: 'YYYY-MM',
+      getPopupContainer: () => document.body,
+    },
+  },
+];
+
+export const formSchema: FormSchema[] = [
+  {
+    label: '统计月份',
+    field: 'yearMonth',
+    component: 'DatePicker',
+    colProps: { span: 24 },
+    required: true,
+    componentProps: {
+      showTime: false,
+      format: 'YYYY-MM',
+      valueFormat: 'YYYY-MM',
+      getPopupContainer: () => document.body,
+    },
+  },
+  {
+    label: '统计时间',
+    field: 'date',
+    component: 'RangePicker',
+    colProps: { span: 24 },
+    required: true,
+    componentProps: {
+      getPopupContainer: () => document.body,
+      placeholder: ['开始时间', '结束时间'],
+      format: 'YYYY-MM-DD',
+      showTime: false,
+    },
+  },
+];
+
+export const formDetailSchema: BasicColumn[] = [
+  {
+    title: '工号',
+    dataIndex: 'userName',
+    align: 'left',
+    width: 80,
+  },
+  {
+    title: '姓名',
+    dataIndex: 'name',
+    align: 'left',
+  },
+  {
+    title: '聘用类型',
+    dataIndex: 'employTypeCn',
+    align: 'left',
+    width: 80,
+  },
+  {
+    title: '教研会',
+    dataIndex: 'classTime1',
+    align: 'left',
+    width: 80,
+  },
+  {
+    title: '督导听课',
+    dataIndex: 'classTime2',
+    align: 'left',
+    width: 80,
+  },
+  {
+    title: '临近三年退休政策',
+    dataIndex: 'classTime3',
+    align: 'left',
+    width: 80,
+  },
+  {
+    title: '出题',
+    dataIndex: 'classTime4',
+    align: 'left',
+    width: 80,
+  },
+  {
+    title: '阅卷',
+    dataIndex: 'classTime5',
+    align: 'left',
+    width: 80,
+  },
+  {
+    title: '周末培优',
+    dataIndex: 'classTime6',
+    align: 'left',
+    width: 80,
+  },
+  {
+    title: '早自习',
+    dataIndex: 'classTime7',
+    align: 'left',
+    width: 80,
+  },
+  {
+    title: '正课(含调顶课时)',
+    dataIndex: 'classTime8',
+    align: 'left',
+    width: 80,
+  },
+  {
+    title: '晚辅(含调顶课时)',
+    dataIndex: 'classTime9',
+    align: 'left',
+    width: 80,
+  },
+  {
+    title: '顶课',
+    dataIndex: 'classTime10',
+    align: 'left',
+    width: 80,
+  },
+  {
+    title: '调课',
+    dataIndex: 'classTime11',
+    align: 'left',
+    width: 80,
+  },
+  {
+    title: '总课时',
+    dataIndex: 'allClassTime',
+    align: 'left',
+    width: 80,
+  },
+  {
+    title: '课时费(元)',
+    dataIndex: 'classTimeAmount',
+    align: 'left',
+    width: 100,
+  },
+  {
+    title: '外聘教师超课时费(元)',
+    dataIndex: 'beyondClassTimeAmount',
+    align: 'left',
+    width: 100,
+  },
+  {
+    title: '总金额(元)',
+    dataIndex: 'totalAmount',
+    align: 'left',
+    width: 110,
+  },
+];

+ 112 - 0
src/views/course/statistics/index.vue

@@ -0,0 +1,112 @@
+<template>
+  <PageWrapper dense contentFullHeight fixedHeight contentClass="flex">
+    <BasicTable @register="registerTable">
+      <template #toolbar>
+        <a-button type="primary" @click="handleAdd">新增</a-button>
+        <a-button type="primary" @click="handleWeight">权重设置</a-button>
+        <a-button type="primary" @click="handleCost">费用设置</a-button>
+        <a-button type="primary">导出</a-button>
+      </template>
+      <template #action="{ record }">
+        <TableAction
+          :actions="[
+            {
+              label: '查看',
+              onClick: handleView.bind(null, record),
+            },
+          ]"
+        />
+      </template>
+    </BasicTable>
+    <FormSelect @register="registerSelectModal" @success="handleSuccess" />
+    <FormWeight @register="registerWeightModal" />
+    <FormCost @register="registerCostModal" />
+    <FormEdit @register="registerModal" @success="handleSuccess" />
+  </PageWrapper>
+</template>
+
+<script setup lang="ts">
+  import { onMounted } from 'vue';
+  import { PageWrapper } from '/@/components/Page';
+  import { BasicTable, useTable, TableAction } from '/@/components/Table';
+  import { tableColumns, searchFormSchema } from './data.config';
+
+  import FormSelect from './components/select.vue';
+  import { useModal } from '/@/components/Modal';
+  import { getClassTimeStatisticsPage } from '/@/services/apis/ClassTimeStatisticsController';
+  import { formatToDate } from '/@/utils/dateUtil';
+  import FormWeight from './components/weight.vue';
+  import FormCost from './components/cost.vue';
+  import FormEdit from './components/edit.vue';
+
+  const [registerSelectModal, { openModal: openSelectModal }] = useModal();
+  const [registerWeightModal, { openModal: openWeightModal }] = useModal();
+  const [registerCostModal, { openModal: openCostModal }] = useModal();
+  const [registerModal, { openModal }] = useModal();
+
+  const [registerTable, { reload }] = useTable({
+    api: getClassTimeStatisticsPage,
+    title: '课时统计记录',
+    rowKey: 'id',
+    columns: tableColumns,
+    formConfig: {
+      labelWidth: 120,
+      schemas: searchFormSchema,
+    },
+    useSearchForm: true,
+    showTableSetting: true,
+    bordered: true,
+    immediate: true,
+    canResize: true,
+    actionColumn: {
+      width: 120,
+      title: '操作',
+      dataIndex: 'action',
+      slots: { customRender: 'action' },
+      fixed: 'right',
+    },
+    beforeFetch: async (params) => {
+      if (params['date']) {
+        params['year'] = formatToDate(params['date'], 'YYYY');
+        params['month'] = formatToDate(params['date'], 'MM');
+        delete params['date'];
+      }
+      return params;
+    },
+  });
+
+  const handleAdd = () => {
+    openSelectModal(true, {
+      isUpdate: false,
+      baseData: {},
+    });
+  };
+
+  const handleWeight = () => {
+    openWeightModal(true, {
+      isUpdate: false,
+      baseData: {},
+    });
+  };
+  const handleCost = () => {
+    openCostModal(true, {
+      isUpdate: false,
+      baseData: {},
+    });
+  };
+
+  const handleView = (record: any) => {
+    openModal(true, {
+      isUpdate: true,
+      baseData: { ...record },
+    });
+  };
+
+  const handleSuccess = () => {
+    reload();
+  };
+
+  onMounted(async () => {});
+</script>
+
+<style scoped lang="less"></style>